diff --git a/.eslintrc.js b/.eslintrc.js index 4d943ad316745..7500bf792a820 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -13,6 +13,7 @@ module.exports = { ignorePatterns: [ 'docs/**', 'smoke-tests/**', + 'mock-globals/**', 'mock-registry/**', 'workspaces/**', ], diff --git a/.eslintrc.local.js b/.eslintrc.local.js new file mode 100644 index 0000000000000..6d94f64614fb8 --- /dev/null +++ b/.eslintrc.local.js @@ -0,0 +1,37 @@ +const { resolve, relative } = require('path') + +// Create an override to lockdown a file to es6 syntax only +// and only allow it to require an allowlist of files +const rel = (p) => relative(__dirname, resolve(__dirname, p)) +const braces = (a) => a.length > 1 ? `{${a.map(rel).join(',')}}` : a[0] + +const es6Files = (e) => Object.entries(e).map(([file, allow]) => ({ + files: `./${rel(file)}`, + parserOptions: { + ecmaVersion: 6, + }, + rules: Array.isArray(allow) ? { + 'node/no-restricted-require': ['error', [{ + name: ['/**', `!${__dirname}/${braces(allow)}`], + message: `This file can only require: ${allow.join(',')}`, + }]], + } : {}, +})) + +module.exports = { + rules: { + 'no-console': 'error', + }, + overrides: es6Files({ + 'index.js': ['lib/cli.js'], + 'bin/npm-cli.js': ['lib/cli.js'], + 'lib/cli.js': ['lib/es6/validate-engines.js'], + 'lib/es6/validate-engines.js': ['package.json'], + // TODO: This file should also have its requires restricted as well since it + // is an entry point but it currently pulls in config definitions which have + // a large require graph, so that is not currently feasible. A future config + // refactor should keep that in mind and see if only config definitions can + // be exported in a way that is compatible with ES6. + 'bin/npx-cli.js': null, + }), +} diff --git a/.eslintrc.local.json b/.eslintrc.local.json deleted file mode 100644 index 2ff50f91ec326..0000000000000 --- a/.eslintrc.local.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "rules": { - "no-console": "error" - } -} diff --git a/.github/workflows/ci-npmcli-mock-globals.yml b/.github/workflows/ci-npmcli-mock-globals.yml new file mode 100644 index 0000000000000..60f85f7c7795f --- /dev/null +++ b/.github/workflows/ci-npmcli-mock-globals.yml @@ -0,0 +1,94 @@ +# This file is automatically added by @npmcli/template-oss. Do not edit. + +name: CI - @npmcli/mock-globals + +on: + workflow_dispatch: + pull_request: + paths: + - mock-globals/** + push: + branches: + - main + - latest + paths: + - mock-globals/** + schedule: + # "At 09:00 UTC (02:00 PT) on Monday" https://crontab.guru/#0_9_*_*_1 + - cron: "0 9 * * 1" + +jobs: + lint: + name: Lint + if: github.repository_owner == 'npm' + runs-on: ubuntu-latest + defaults: + run: + shell: bash + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 18.x + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Lint + run: node . run lint --ignore-scripts -w @npmcli/mock-globals + - name: Post Lint + run: node . run postlint --ignore-scripts -w @npmcli/mock-globals + + test: + name: Test - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' + strategy: + fail-fast: false + matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + - name: macOS + os: macos-latest + shell: bash + - name: Windows + os: windows-latest + shell: cmd + node-version: + - 14.17.0 + - 14.x + - 16.13.0 + - 16.x + - 18.0.0 + - 18.x + runs-on: ${{ matrix.platform.os }} + defaults: + run: + shell: ${{ matrix.platform.shell }} + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Add Problem Matcher + run: echo "::add-matcher::.github/matchers/tap.json" + - name: Test + run: node . test --ignore-scripts -w @npmcli/mock-globals + - name: Check Git Status + if: matrix && matrix.platform.os != 'windows-latest' + run: node scripts/git-dirty.js diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml index 4abb5d80bf7ad..821d4a37368a3 100644 --- a/.github/workflows/ci-release.yml +++ b/.github/workflows/ci-release.yml @@ -199,6 +199,10 @@ jobs: check_id: ${{ steps.check.outputs.check_id }} smoke-publish: + # This cant be tested on Windows because our node_modules directory + # checks in symlinks which are not supported there. This should be + # fixed somehow, because this means some forms of local development + # are likely broken on Windows as well. name: Smoke Publish - ${{ matrix.platform.name }} - ${{ matrix.node-version }} if: github.repository_owner == 'npm' strategy: @@ -288,12 +292,20 @@ jobs: NPM_VERSION="$(node . --version)-$GITHUB_SHA.0" node . version $NPM_VERSION --ignore-scripts node scripts/publish.js --pack-destination=$RUNNER_TEMP - node . install --global $RUNNER_TEMP/npm-$NPM_VERSION.tgz + export SMOKE_PUBLISH_TARBALL="$RUNNER_TEMP/npm-$NPM_VERSION.tgz" + node . install --global $SMOKE_PUBLISH_TARBALL node . install -w smoke-tests --ignore-scripts --no-audit --no-fund - node scripts/remove-files.js # call installed npm instead of local source since we are testing # the packed tarball that we just installed globally - npm test -w smoke-tests --ignore-scripts + NPM_GLOBAL_VERSION="$(npm --version)" + npm help + if [ "$NPM_GLOBAL_VERSION" == "$NPM_VERSION" ]; then + npm test -w smoke-tests --ignore-scripts + else + echo "global npm is not the correct version for smoke-publish" + echo "found: $NPM_GLOBAL_VERSION, expected: $NPM_VERSION" + exit 1 + fi - name: Conclude Check uses: LouisBrunner/checks-action@v1.3.1 if: steps.check.outputs.check_id && always() diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 639bf4a0ce49a..485b9bc9245c9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,6 +8,7 @@ on: paths-ignore: - docs/** - smoke-tests/** + - mock-globals/** - mock-registry/** - workspaces/** push: @@ -17,6 +18,7 @@ on: paths-ignore: - docs/** - smoke-tests/** + - mock-globals/** - mock-registry/** - workspaces/** schedule: diff --git a/.github/workflows/node-integration.yml b/.github/workflows/node-integration.yml index 69ef2ce38dc44..64d7894f4934d 100644 --- a/.github/workflows/node-integration.yml +++ b/.github/workflows/node-integration.yml @@ -489,7 +489,7 @@ jobs: env: ${{ matrix.env }} run: | EXIT=1 - if [[ "${{ steps.command.outcome }}" == "success" || "${{ matrix.flaky }}" == "true" || "${{ matrix.knownFailure }}" == "true" || $NODE_VERSION == "nightly"]]; then + if [[ "${{ steps.command.outcome }}" == "success" || "${{ matrix.flaky }}" == "true" || "${{ matrix.knownFailure }}" == "true" || $NODE_VERSION == "nightly" ]]; then EXIT=0 fi exit $EXIT diff --git a/.gitignore b/.gitignore index dd81bed4846dc..5135a77dff8dd 100644 --- a/.gitignore +++ b/.gitignore @@ -40,6 +40,7 @@ !/test/ !/docs/ !/smoke-tests/ +!/mock-globals/ !/mock-registry/ !/workspaces/ /workspaces/* diff --git a/.release-please-manifest.json b/.release-please-manifest.json index edb56c90d4f89..73d8ff091c515 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,16 +1,16 @@ { - ".": "9.6.6", - "workspaces/arborist": "6.2.9", + ".": "9.7.2", + "workspaces/arborist": "6.2.10", "workspaces/libnpmaccess": "7.0.2", - "workspaces/libnpmdiff": "5.0.17", - "workspaces/libnpmexec": "5.0.17", - "workspaces/libnpmfund": "4.0.17", + "workspaces/libnpmdiff": "5.0.18", + "workspaces/libnpmexec": "6.0.1", + "workspaces/libnpmfund": "4.0.18", "workspaces/libnpmhook": "9.0.3", "workspaces/libnpmorg": "5.0.4", - "workspaces/libnpmpack": "5.0.17", - "workspaces/libnpmpublish": "7.1.4", + "workspaces/libnpmpack": "5.0.18", + "workspaces/libnpmpublish": "7.4.0", "workspaces/libnpmsearch": "6.0.2", "workspaces/libnpmteam": "5.0.3", "workspaces/libnpmversion": "4.0.2", - "workspaces/config": "6.1.6" + "workspaces/config": "6.2.1" } diff --git a/AUTHORS b/AUTHORS index 6f0f6c7b47903..efa0778688021 100644 --- a/AUTHORS +++ b/AUTHORS @@ -880,3 +880,10 @@ Jeff Mealo Kevin Rouchut Stafford Williams CharlieWONG +James Henry +Kashyap Kaki <30841403+kashyapkaki@users.noreply.github.com> +Darryl Tec +Michaël Bitard +may <63159454+m4rch3n1ng@users.noreply.github.com> +Rayyan Ul Haq <31252332+Rayyan98@users.noreply.github.com> +DaviDevMod <98312056+DaviDevMod@users.noreply.github.com> diff --git a/CHANGELOG.md b/CHANGELOG.md index 54efa24497b7b..34c56a25e78bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,112 @@ # Changelog +## [9.7.2](https://github.com/npm/cli/compare/v9.7.1...v9.7.2) (2023-06-21) + +### Bug Fixes + +* [`939a188`](https://github.com/npm/cli/commit/939a188bc3ab9c2bfa49ccb4837fe4ad844131ed) [#6574](https://github.com/npm/cli/pull/6574) ignore node prereleases in npm engines check (#6574) (@wraithgar) +* [`d980405`](https://github.com/npm/cli/commit/d980405ffcbc80ad63fbea680ee40a57ffc4a210) [#6556](https://github.com/npm/cli/pull/6556) better color support detection (#6556) (@lukekarrys) +* [`40d7e09`](https://github.com/npm/cli/commit/40d7e09aa9c038bc20e37c4fbd21d02dc82b93a7) [#6555](https://github.com/npm/cli/pull/6555) remove unnecessary package.json values (#6555) (@lukekarrys) +* [`3a7378d`](https://github.com/npm/cli/commit/3a7378d889707d2a4c1f8a6397dda87825e9f5a3) [#6554](https://github.com/npm/cli/pull/6554) cleanup bin contents (@lukekarrys) +* [`e722439`](https://github.com/npm/cli/commit/e722439b05bb4da691975359db58eac794f1f5d9) [#6497](https://github.com/npm/cli/pull/6497) move all definitions to @npmcli/config package (@lukekarrys) + +### Documentation + +* [`405ffbf`](https://github.com/npm/cli/commit/405ffbfa2758ec388c06120fdf5fde2a07835779) [#6557](https://github.com/npm/cli/pull/6557) remove redundant statement about files attribute (#6557) (@DaviDevMod) +* [`cd1e6aa`](https://github.com/npm/cli/commit/cd1e6aa320ccc264f5027de5976bb7acc32f1ded) [#6551](https://github.com/npm/cli/pull/6551) add flag `package-lock-only` for `npm install` (#6551) (@m4rch3n1ng) + +### Dependencies + +* [`aebc523`](https://github.com/npm/cli/commit/aebc523c46f6e37c943a750e4cb6ec4b8f12ae01) [#6585](https://github.com/npm/cli/pull/6585) `safe-buffer@5.2.1` `string_decoder@1.3.0` (#6585) +* [`bb6054b`](https://github.com/npm/cli/commit/bb6054b9558efd859e32ba9227453b3c84ef647d) [#6573](https://github.com/npm/cli/pull/6573) `tuf-js@1.1.7` +* [`aee4a30`](https://github.com/npm/cli/commit/aee4a30bfb88ac147f5f8ac9bdb28cfc0be16e7f) [#6573](https://github.com/npm/cli/pull/6573) `strip-ansi@7.1.0` +* [`6105dbc`](https://github.com/npm/cli/commit/6105dbcc1c1647c66759e73ad8699a539e8a70c3) [#6573](https://github.com/npm/cli/pull/6573) `path-scurry@1.9.2` +* [`22d44e8`](https://github.com/npm/cli/commit/22d44e81d6bced4c9d5960b74023ee017df6606b) [#6573](https://github.com/npm/cli/pull/6573) `read-package-json@6.0.4` +* [`fdd02fd`](https://github.com/npm/cli/commit/fdd02fde1c53ce66a3b15b55907fd7e80680b89b) [#6573](https://github.com/npm/cli/pull/6573) `jackspeak@2.2.1` +* [`7797075`](https://github.com/npm/cli/commit/77970756cb2a18257a50e765617f2237abe245d6) [#6573](https://github.com/npm/cli/pull/6573) `is-core-module@2.12.1` +* [`f9780cc`](https://github.com/npm/cli/commit/f9780ccbde62feb59691b5c2f19ed5f3688b1e7e) [#6573](https://github.com/npm/cli/pull/6573) `sigstore@1.6.0` +* [`72d6a79`](https://github.com/npm/cli/commit/72d6a79fa28aec50dab576e93ef06a89694770a5) [#6573](https://github.com/npm/cli/pull/6573) `semver@7.5.2` +* [`98f1f5f`](https://github.com/npm/cli/commit/98f1f5fd2d6890c207c77452739053a674d83990) [#6573](https://github.com/npm/cli/pull/6573) `nopt@7.2.0` +* [`8710ff8`](https://github.com/npm/cli/commit/8710ff88afffb573b4f65c4a19303924935fecd2) [#6573](https://github.com/npm/cli/pull/6573) `pacote@15.2.0` +* [`0cb539d`](https://github.com/npm/cli/commit/0cb539dae1311ef0f60ccf5bd47def1763c38852) [#6573](https://github.com/npm/cli/pull/6573) `node-gyp@9.4.0` +* [`39ad586`](https://github.com/npm/cli/commit/39ad5862ffc99b3da365ab3dd8538b68a4352ea5) [#6573](https://github.com/npm/cli/pull/6573) `ini@4.1.1` +* [`5e0070c`](https://github.com/npm/cli/commit/5e0070cf28353e94458e0d8190833595aa143314) [#6573](https://github.com/npm/cli/pull/6573) `glob@10.2.7` `minimatch@9.0.1` +* [`26cf235`](https://github.com/npm/cli/commit/26cf235aa45d0d4100f061f009c1ffdf0a1fdf16) [#6573](https://github.com/npm/cli/pull/6573) `cacache@17.1.3` +* [Workspace](https://github.com/npm/cli/releases/tag/arborist-v6.2.10): `@npmcli/arborist@6.2.10` +* [Workspace](https://github.com/npm/cli/releases/tag/config-v6.2.1): `@npmcli/config@6.2.1` +* [Workspace](https://github.com/npm/cli/releases/tag/libnpmdiff-v5.0.18): `libnpmdiff@5.0.18` +* [Workspace](https://github.com/npm/cli/releases/tag/libnpmexec-v6.0.1): `libnpmexec@6.0.1` +* [Workspace](https://github.com/npm/cli/releases/tag/libnpmfund-v4.0.18): `libnpmfund@4.0.18` +* [Workspace](https://github.com/npm/cli/releases/tag/libnpmpack-v5.0.18): `libnpmpack@5.0.18` +* [Workspace](https://github.com/npm/cli/releases/tag/libnpmpublish-v7.4.0): `libnpmpublish@7.4.0` + +## [9.7.1](https://github.com/npm/cli/compare/v9.7.0...v9.7.1) (2023-06-06) + +### Dependencies + +* [`7467ff6`](https://github.com/npm/cli/commit/7467ff680a3fffbf6b974c5779229c2e54e8515f) [#6518](https://github.com/npm/cli/pull/6518) `@npmcli/package-json@3.1.1`, `@npmcli/git@4.1.0` + +## [9.7.0](https://github.com/npm/cli/compare/v9.6.7...v9.7.0) (2023-05-31) + +### Features + +* [`a63a6d8`](https://github.com/npm/cli/commit/a63a6d8d6fd339d504ab94c0364ce7ee3d4e3775) [#6490](https://github.com/npm/cli/pull/6490) add provenanceFile option for libnpmpublish (@bdehamer) +* [`2a8f4f2`](https://github.com/npm/cli/commit/2a8f4f203a47f60cc96312934927419a7d83c2f1) [#6490](https://github.com/npm/cli/pull/6490) add new exclusive config item publish-file (@wraithgar) +* [`361e194`](https://github.com/npm/cli/commit/361e1945b5a34230690ccf37a14687d021e1dbce) [#6483](https://github.com/npm/cli/pull/6483) implement flag --prefer-dedupe for `npm install` (#6483) (@m4rch3n1ng) + +### Bug Fixes + +* [`38eb39b`](https://github.com/npm/cli/commit/38eb39b8068ab4e3b0a544234ac5df804469e3d8) [#6514](https://github.com/npm/cli/pull/6514) strip ansi characters from search results (#6514) (@wraithgar) +* [`4b5ccfc`](https://github.com/npm/cli/commit/4b5ccfce376378521cb743bfbd32a724340e75b8) [#6477](https://github.com/npm/cli/pull/6477) make usage and completion static functions (#6477) (@lukekarrys) +* [`4f39e8c`](https://github.com/npm/cli/commit/4f39e8c983e652b66f9c342b93694a29dc5a0b92) [#6479](https://github.com/npm/cli/pull/6479) refactor engines validation to lint syntax (#6479) (@lukekarrys) +* [`f3cfe12`](https://github.com/npm/cli/commit/f3cfe129b2602e8f454acac572a51d8adc6c1111) [#6482](https://github.com/npm/cli/pull/6482) remove unused lib/npm relics (#6482) (@lukekarrys) +* [`87de0c7`](https://github.com/npm/cli/commit/87de0c79cca0788d728095cfb537447745bada13) [#6472](https://github.com/npm/cli/pull/6472) move explore command to @npmcli/package-json (@wraithgar) +* [`636e29e`](https://github.com/npm/cli/commit/636e29e2c887e7f197977e3215642b6778eb59de) [#6472](https://github.com/npm/cli/pull/6472) move to @npmcli/package-json where possible (@wraithgar) +* [`37cc797`](https://github.com/npm/cli/commit/37cc797341100cd0a8371e80b25b938f166c9d71) [#6418](https://github.com/npm/cli/pull/6418) retrieve registry keys via TUF (#6418) (@bdehamer) + +### Documentation + +* [`83cd5bd`](https://github.com/npm/cli/commit/83cd5bd68aa6255c598b8dd3a544f16129885aee) [#6480](https://github.com/npm/cli/pull/6480) add global option for uninstall (#6480) (@m4rch3n1ng) +* [`0400ce3`](https://github.com/npm/cli/commit/0400ce3c9d7af792c9931f1ba365e25b899833b6) [#6481](https://github.com/npm/cli/pull/6481) add cli params to `npm set`, `npm get` (#6481) (@m4rch3n1ng) +* [`c3638ce`](https://github.com/npm/cli/commit/c3638ce613364aff50fedb493a97f1ee60211158) [#6468](https://github.com/npm/cli/pull/6468) remove `package-lock` option for `npm ci` (#6468) (@m4rch3n1ng) + +### Dependencies + +* [`060d587`](https://github.com/npm/cli/commit/060d587f6f5a60db0c02c319c1df1a11c146442f) `chalk@5.2.0`, `npm-audit-report@5.0.0` +* [`fc52ca8`](https://github.com/npm/cli/commit/fc52ca8c0bd2aeb4e3885e5395ec647628bdd87c) [#6472](https://github.com/npm/cli/pull/6472) remove read-package-json-fast +* [`3238aa7`](https://github.com/npm/cli/commit/3238aa78905bc90b404dc3075ec810884f8fd1c8) [#6472](https://github.com/npm/cli/pull/6472) remove read-package-json +* [Workspace](https://github.com/npm/cli/releases/tag/config-v6.2.0): `@npmcli/config@6.2.0` +* [Workspace](https://github.com/npm/cli/releases/tag/libnpmexec-v6.0.0): `libnpmexec@6.0.0` +* [Workspace](https://github.com/npm/cli/releases/tag/libnpmpublish-v7.3.0): `libnpmpublish@7.3.0` + +## [9.6.7](https://github.com/npm/cli/compare/v9.6.6...v9.6.7) (2023-05-17) + +### Bug Fixes + +* [`9202c7d`](https://github.com/npm/cli/commit/9202c7d7c4058deb618e1a74fdc97b11f2845af7) [#6464](https://github.com/npm/cli/pull/6464) npm cache completion (#6464) (@m4rch3n1ng) +* [`6ce99a8`](https://github.com/npm/cli/commit/6ce99a809c815934df73e002381b2b74b25ab0f8) [#6461](https://github.com/npm/cli/pull/6461) exit codes in node v20 (#6461) (@MichaelBitard) +* [`23c865f`](https://github.com/npm/cli/commit/23c865fcd4bd4ee6957006c7b8f9e8cfde1db321) [#6434](https://github.com/npm/cli/pull/6434) deprecate ci-name config (#6434) (@wraithgar) + +### Documentation + +* [`7751dd4`](https://github.com/npm/cli/commit/7751dd431ca6ee4a3503fa71bda88a5cd89eb83c) [#6413](https://github.com/npm/cli/pull/6413) add a comma (#6413) (@darryltec) + +### Dependencies + +* [`afc38a5`](https://github.com/npm/cli/commit/afc38a564c55e8e7b676a3036d1438784ee6c8f0) [#6458](https://github.com/npm/cli/pull/6458) `cacache@17.1.2` +* [`afb936c`](https://github.com/npm/cli/commit/afb936cc5e22d96115472cdfc16908299db5e9dd) [#6458](https://github.com/npm/cli/pull/6458) `tuf-js@1.1.6` +* [`f6a0884`](https://github.com/npm/cli/commit/f6a0884e0867cf0948ddbbdc1b98e0756bf96cef) [#6458](https://github.com/npm/cli/pull/6458) `readable-stream@4.4.0` +* [`858f0ca`](https://github.com/npm/cli/commit/858f0caa3add38c0a171825421693eddf59ccf40) [#6458](https://github.com/npm/cli/pull/6458) `postcss-selector-parser@6.0.13` +* [`53ecb84`](https://github.com/npm/cli/commit/53ecb84bb625a16e2d0a86b1d9380384c0e7545c) [#6458](https://github.com/npm/cli/pull/6458) `path-scurry@1.9.1` +* [`d93f70c`](https://github.com/npm/cli/commit/d93f70c9cd108e6dc3ce9533339dec77c359c320) [#6458](https://github.com/npm/cli/pull/6458) `signal-exit@4.0.2` +* [`19214b5`](https://github.com/npm/cli/commit/19214b54828a9b4e923ea329fa5841edf0753162) [#6458](https://github.com/npm/cli/pull/6458) `@npmcli/package-json@3.1.0` +* [`f53e6ff`](https://github.com/npm/cli/commit/f53e6ff22bc374a03ea6663dbad584c493f1d5b8) [#6458](https://github.com/npm/cli/pull/6458) `sigstore@1.5.2` +* [`94d6ee7`](https://github.com/npm/cli/commit/94d6ee7f353265b64e51ced879915882be83aa89) [#6458](https://github.com/npm/cli/pull/6458) `glob@10.2.4` +* [`902cb80`](https://github.com/npm/cli/commit/902cb80771cc440ef10e7ce7b2afa8934277e0f6) [#6458](https://github.com/npm/cli/pull/6458) `semver@7.5.1` +* [`35e2e9a`](https://github.com/npm/cli/commit/35e2e9a4ce91325462d75b1774298485127762fc) [#6458](https://github.com/npm/cli/pull/6458) `@npmcli/run-script@6.0.2` +* [Workspace](https://github.com/npm/cli/releases/tag/config-v6.1.7): `@npmcli/config@6.1.7` +* [Workspace](https://github.com/npm/cli/releases/tag/libnpmpublish-v7.2.0): `libnpmpublish@7.2.0` + ## [9.6.6](https://github.com/npm/cli/compare/v9.6.5...v9.6.6) (2023-05-03) ### Dependencies diff --git a/DEPENDENCIES.md b/DEPENDENCIES.md index 7c9e187f4783f..64de1e5a27a4d 100644 --- a/DEPENDENCIES.md +++ b/DEPENDENCIES.md @@ -30,7 +30,6 @@ graph LR; libnpmdiff-->npmcli-template-oss["@npmcli/template-oss"]; libnpmdiff-->pacote; libnpmexec-->bin-links; - libnpmexec-->minify-registry-metadata; libnpmexec-->npm-package-arg; libnpmexec-->npmcli-arborist["@npmcli/arborist"]; libnpmexec-->npmcli-eslint-config["@npmcli/eslint-config"]; @@ -62,6 +61,7 @@ graph LR; libnpmpublish-->npm-package-arg; libnpmpublish-->npm-registry-fetch; libnpmpublish-->npmcli-eslint-config["@npmcli/eslint-config"]; + libnpmpublish-->npmcli-mock-globals["@npmcli/mock-globals"]; libnpmpublish-->npmcli-mock-registry["@npmcli/mock-registry"]; libnpmpublish-->npmcli-template-oss["@npmcli/template-oss"]; libnpmpublish-->proc-log; @@ -121,6 +121,7 @@ graph LR; npm-->npmcli-fs["@npmcli/fs"]; npm-->npmcli-git["@npmcli/git"]; npm-->npmcli-map-workspaces["@npmcli/map-workspaces"]; + npm-->npmcli-mock-globals["@npmcli/mock-globals"]; npm-->npmcli-mock-registry["@npmcli/mock-registry"]; npm-->npmcli-package-json["@npmcli/package-json"]; npm-->npmcli-promise-spawn["@npmcli/promise-spawn"]; @@ -131,8 +132,6 @@ graph LR; npm-->pacote; npm-->parse-conflict-json; npm-->proc-log; - npm-->read-package-json-fast; - npm-->read-package-json; npm-->read; npm-->semver; npm-->ssri; @@ -187,11 +186,13 @@ graph LR; npmcli-config-->nopt; npmcli-config-->npmcli-eslint-config["@npmcli/eslint-config"]; npmcli-config-->npmcli-map-workspaces["@npmcli/map-workspaces"]; + npmcli-config-->npmcli-mock-globals["@npmcli/mock-globals"]; npmcli-config-->npmcli-template-oss["@npmcli/template-oss"]; npmcli-config-->proc-log; npmcli-config-->read-package-json-fast; npmcli-config-->semver; npmcli-docs-->ignore-walk; + npmcli-docs-->npmcli-config["@npmcli/config"]; npmcli-docs-->npmcli-eslint-config["@npmcli/eslint-config"]; npmcli-docs-->npmcli-template-oss["@npmcli/template-oss"]; npmcli-docs-->semver; @@ -208,12 +209,18 @@ graph LR; npmcli-metavuln-calculator-->json-parse-even-better-errors; npmcli-metavuln-calculator-->pacote; npmcli-metavuln-calculator-->semver; + npmcli-mock-globals-->npmcli-eslint-config["@npmcli/eslint-config"]; + npmcli-mock-globals-->npmcli-template-oss["@npmcli/template-oss"]; npmcli-mock-registry-->npm-package-arg; npmcli-mock-registry-->npmcli-arborist["@npmcli/arborist"]; npmcli-mock-registry-->npmcli-eslint-config["@npmcli/eslint-config"]; npmcli-mock-registry-->npmcli-template-oss["@npmcli/template-oss"]; npmcli-mock-registry-->pacote; npmcli-package-json-->json-parse-even-better-errors; + npmcli-package-json-->normalize-package-data; + npmcli-package-json-->npm-normalize-package-bin; + npmcli-package-json-->npmcli-git["@npmcli/git"]; + npmcli-package-json-->proc-log; npmcli-run-script-->npmcli-node-gyp["@npmcli/node-gyp"]; npmcli-run-script-->npmcli-promise-spawn["@npmcli/promise-spawn"]; npmcli-run-script-->read-package-json-fast; @@ -266,26 +273,18 @@ graph LR; bin-links-->write-file-atomic; brace-expansion-->balanced-match; builtins-->semver; - cacache-->chownr; cacache-->fs-minipass; cacache-->glob; - cacache-->infer-owner; cacache-->lru-cache; cacache-->minipass-collect; cacache-->minipass-flush; cacache-->minipass-pipeline; cacache-->minipass; - cacache-->mkdirp; cacache-->npmcli-fs["@npmcli/fs"]; - cacache-->npmcli-move-file["@npmcli/move-file"]; cacache-->p-map; - cacache-->promise-inflight; - cacache-->rimraf; cacache-->ssri; cacache-->tar; cacache-->unique-filename; - chalk-->ansi-styles; - chalk-->supports-color; cidr-regex-->ip-regex; cli-columns-->string-width; cli-columns-->strip-ansi; @@ -374,7 +373,6 @@ graph LR; libnpmexec-->ci-info; libnpmexec-->just-extend; libnpmexec-->just-safe-set; - libnpmexec-->minify-registry-metadata; libnpmexec-->npm-package-arg; libnpmexec-->npmcli-arborist["@npmcli/arborist"]; libnpmexec-->npmcli-eslint-config["@npmcli/eslint-config"]; @@ -422,6 +420,7 @@ graph LR; libnpmpublish-->npm-package-arg; libnpmpublish-->npm-registry-fetch; libnpmpublish-->npmcli-eslint-config["@npmcli/eslint-config"]; + libnpmpublish-->npmcli-mock-globals["@npmcli/mock-globals"]; libnpmpublish-->npmcli-mock-registry["@npmcli/mock-registry"]; libnpmpublish-->npmcli-template-oss["@npmcli/template-oss"]; libnpmpublish-->proc-log; @@ -457,7 +456,6 @@ graph LR; make-fetch-happen-->https-proxy-agent; make-fetch-happen-->is-lambda; make-fetch-happen-->lru-cache; - make-fetch-happen-->minipass-collect; make-fetch-happen-->minipass-fetch; make-fetch-happen-->minipass-flush; make-fetch-happen-->minipass-pipeline; @@ -481,6 +479,7 @@ graph LR; minizlib-->minipass; minizlib-->yallist; node-gyp-->env-paths; + node-gyp-->exponential-backoff; node-gyp-->glob; node-gyp-->graceful-fs; node-gyp-->make-fetch-happen; @@ -503,6 +502,7 @@ graph LR; npm-->cli-columns; npm-->cli-table3; npm-->columnify; + npm-->diff; npm-->fastest-levenshtein; npm-->fs-minipass; npm-->glob; @@ -548,6 +548,7 @@ graph LR; npm-->npmcli-fs["@npmcli/fs"]; npm-->npmcli-git["@npmcli/git"]; npm-->npmcli-map-workspaces["@npmcli/map-workspaces"]; + npm-->npmcli-mock-globals["@npmcli/mock-globals"]; npm-->npmcli-mock-registry["@npmcli/mock-registry"]; npm-->npmcli-package-json["@npmcli/package-json"]; npm-->npmcli-promise-spawn["@npmcli/promise-spawn"]; @@ -560,24 +561,24 @@ graph LR; npm-->parse-conflict-json; npm-->proc-log; npm-->qrcode-terminal; - npm-->read-package-json-fast; - npm-->read-package-json; npm-->read; npm-->remark-gfm; npm-->remark-github; npm-->remark; npm-->semver; + npm-->sigstore; npm-->spawk; npm-->ssri; + npm-->supports-color; npm-->tap; npm-->tar; npm-->text-table; npm-->tiny-relative-date; npm-->treeverse; + npm-->tufjs-repo-mock["@tufjs/repo-mock"]; npm-->validate-npm-package-name; npm-->which; npm-->write-file-atomic; - npm-audit-report-->chalk; npm-bundled-->npm-normalize-package-bin; npm-install-checks-->semver; npm-package-arg-->hosted-git-info; @@ -601,7 +602,6 @@ graph LR; npmcli-arborist-->benchmark; npmcli-arborist-->bin-links; npmcli-arborist-->cacache; - npmcli-arborist-->chalk; npmcli-arborist-->common-ancestor-path; npmcli-arborist-->hosted-git-info; npmcli-arborist-->isaacs-string-locale-compare["@isaacs/string-locale-compare"]; @@ -640,10 +640,12 @@ graph LR; npmcli-arborist-->tcompare; npmcli-arborist-->treeverse; npmcli-arborist-->walk-up-path; + npmcli-config-->ci-info; npmcli-config-->ini; npmcli-config-->nopt; npmcli-config-->npmcli-eslint-config["@npmcli/eslint-config"]; npmcli-config-->npmcli-map-workspaces["@npmcli/map-workspaces"]; + npmcli-config-->npmcli-mock-globals["@npmcli/mock-globals"]; npmcli-config-->npmcli-template-oss["@npmcli/template-oss"]; npmcli-config-->proc-log; npmcli-config-->read-package-json-fast; @@ -655,6 +657,7 @@ graph LR; npmcli-docs-->ignore-walk; npmcli-docs-->isaacs-string-locale-compare["@isaacs/string-locale-compare"]; npmcli-docs-->jsdom; + npmcli-docs-->npmcli-config["@npmcli/config"]; npmcli-docs-->npmcli-eslint-config["@npmcli/eslint-config"]; npmcli-docs-->npmcli-template-oss["@npmcli/template-oss"]; npmcli-docs-->rehype-stringify; @@ -685,6 +688,10 @@ graph LR; npmcli-metavuln-calculator-->json-parse-even-better-errors; npmcli-metavuln-calculator-->pacote; npmcli-metavuln-calculator-->semver; + npmcli-mock-globals-->npmcli-eslint-config["@npmcli/eslint-config"]; + npmcli-mock-globals-->npmcli-template-oss["@npmcli/template-oss"]; + npmcli-mock-globals-->tap; + npmcli-mock-registry-->json-stringify-safe; npmcli-mock-registry-->nock; npmcli-mock-registry-->npm-package-arg; npmcli-mock-registry-->npmcli-arborist["@npmcli/arborist"]; @@ -692,9 +699,12 @@ graph LR; npmcli-mock-registry-->npmcli-template-oss["@npmcli/template-oss"]; npmcli-mock-registry-->pacote; npmcli-mock-registry-->tap; - npmcli-move-file-->mkdirp; - npmcli-move-file-->rimraf; + npmcli-package-json-->glob; npmcli-package-json-->json-parse-even-better-errors; + npmcli-package-json-->normalize-package-data; + npmcli-package-json-->npm-normalize-package-bin; + npmcli-package-json-->npmcli-git["@npmcli/git"]; + npmcli-package-json-->proc-log; npmcli-promise-spawn-->which; npmcli-query-->postcss-selector-parser; npmcli-run-script-->node-gyp; @@ -703,8 +713,6 @@ graph LR; npmcli-run-script-->read-package-json-fast; npmcli-run-script-->which; npmcli-smoke-tests-->http-proxy; - npmcli-smoke-tests-->just-extend; - npmcli-smoke-tests-->just-safe-set; npmcli-smoke-tests-->npmcli-eslint-config["@npmcli/eslint-config"]; npmcli-smoke-tests-->npmcli-mock-registry["@npmcli/mock-registry"]; npmcli-smoke-tests-->npmcli-promise-spawn["@npmcli/promise-spawn"]; @@ -760,7 +768,11 @@ graph LR; shebang-command-->shebang-regex; sigstore-->make-fetch-happen; sigstore-->sigstore-protobuf-specs["@sigstore/protobuf-specs"]; + sigstore-->sigstore-tuf["@sigstore/tuf"]; sigstore-->tuf-js; + sigstore-tuf-->make-fetch-happen; + sigstore-tuf-->sigstore-protobuf-specs["@sigstore/protobuf-specs"]; + sigstore-tuf-->tuf-js; socks-->ip; socks-->smart-buffer; socks-proxy-agent-->agent-base; @@ -777,13 +789,13 @@ graph LR; string-width-->strip-ansi; string_decoder-->safe-buffer; strip-ansi-->ansi-regex; - supports-color-->has-flag; tar-->chownr; tar-->fs-minipass; tar-->minipass; tar-->minizlib; tar-->mkdirp; tar-->yallist; + tuf-js-->debug; tuf-js-->make-fetch-happen; tuf-js-->tufjs-models["@tufjs/models"]; tufjs-models-->minimatch; @@ -815,8 +827,8 @@ packages higher up the chain. - @npmcli/arborist - @npmcli/metavuln-calculator - pacote, libnpmhook, libnpmorg, libnpmsearch, libnpmteam, npm-profile - - npm-registry-fetch, libnpmversion - - @npmcli/git, make-fetch-happen, @npmcli/config, init-package-json - - @npmcli/installed-package-contents, @npmcli/map-workspaces, cacache, npm-pick-manifest, @npmcli/run-script, read-package-json, promzard - - @npmcli/docs, @npmcli/fs, npm-bundled, read-package-json-fast, unique-filename, npm-install-checks, npm-package-arg, npm-packlist, normalize-package-data, @npmcli/package-json, bin-links, nopt, npmlog, parse-conflict-json, read - - @npmcli/eslint-config, @npmcli/template-oss, ignore-walk, semver, npm-normalize-package-bin, @npmcli/name-from-folder, json-parse-even-better-errors, fs-minipass, ssri, unique-slug, @npmcli/promise-spawn, hosted-git-info, proc-log, validate-npm-package-name, @npmcli/node-gyp, minipass-fetch, @npmcli/query, cmd-shim, read-cmd-shim, write-file-atomic, abbrev, are-we-there-yet, gauge, minify-registry-metadata, ini, @npmcli/disparity-colors, mute-stream, npm-audit-report, npm-user-validate + - @npmcli/docs, npm-registry-fetch, @npmcli/package-json, libnpmversion + - @npmcli/config, @npmcli/git, make-fetch-happen, init-package-json + - @npmcli/map-workspaces, @npmcli/installed-package-contents, cacache, npm-pick-manifest, @npmcli/run-script, read-package-json, promzard + - read-package-json-fast, nopt, @npmcli/mock-globals, @npmcli/fs, npm-bundled, unique-filename, npm-install-checks, npm-package-arg, npm-packlist, normalize-package-data, bin-links, npmlog, parse-conflict-json, read + - @npmcli/name-from-folder, json-parse-even-better-errors, npm-normalize-package-bin, ini, abbrev, proc-log, semver, @npmcli/eslint-config, @npmcli/template-oss, ignore-walk, fs-minipass, ssri, unique-slug, @npmcli/promise-spawn, hosted-git-info, validate-npm-package-name, @npmcli/node-gyp, minipass-fetch, @npmcli/query, cmd-shim, read-cmd-shim, write-file-atomic, are-we-there-yet, gauge, minify-registry-metadata, @npmcli/disparity-colors, mute-stream, npm-audit-report, npm-user-validate diff --git a/bin/node-gyp-bin/node-gyp b/bin/node-gyp-bin/node-gyp deleted file mode 100755 index 70efb6f339f76..0000000000000 --- a/bin/node-gyp-bin/node-gyp +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env sh -if [ "x$npm_config_node_gyp" = "x" ]; then - node "`dirname "$0"`/../../node_modules/node-gyp/bin/node-gyp.js" "$@" -else - "$npm_config_node_gyp" "$@" -fi diff --git a/bin/node-gyp-bin/node-gyp.cmd b/bin/node-gyp-bin/node-gyp.cmd deleted file mode 100755 index 1ef2ae0c68fc4..0000000000000 --- a/bin/node-gyp-bin/node-gyp.cmd +++ /dev/null @@ -1,5 +0,0 @@ -if not defined npm_config_node_gyp ( - node "%~dp0\..\..\node_modules\node-gyp\bin\node-gyp.js" %* -) else ( - node "%npm_config_node_gyp%" %* -) diff --git a/bin/npm b/bin/npm index a131a53543404..a08b4d113c444 100755 --- a/bin/npm +++ b/bin/npm @@ -1,4 +1,8 @@ #!/usr/bin/env bash + +# This is used by the Node.js installer, which expects the cygwin/mingw +# shell script to already be present in the npm dependency folder. + (set -o igncr) 2>/dev/null && set -o igncr; # cygwin encoding fix basedir=`dirname "$0"` @@ -19,7 +23,6 @@ fi # kind of paths Node.js thinks it's using, typically win32 paths. CLI_BASEDIR="$("$NODE_EXE" -p 'require("path").dirname(process.execPath)')" NPM_CLI_JS="$CLI_BASEDIR/node_modules/npm/bin/npm-cli.js" - NPM_PREFIX=`"$NODE_EXE" "$NPM_CLI_JS" prefix -g` if [ $? -ne 0 ]; then # if this didn't work, then everything else below will fail diff --git a/bin/npx b/bin/npx index a34e3459b5a70..c51ad45cb68ae 100755 --- a/bin/npx +++ b/bin/npx @@ -19,17 +19,17 @@ if ! [ -x "$NODE_EXE" ]; then NODE_EXE=node fi -# these paths are passed to node.exe, so they need to match whatever +# this path is passed to node.exe, so it needs to match whatever # kind of paths Node.js thinks it's using, typically win32 paths. CLI_BASEDIR="$("$NODE_EXE" -p 'require("path").dirname(process.execPath)')" +NPM_CLI_JS="$CLI_BASEDIR/node_modules/npm/bin/npm-cli.js" +NPX_CLI_JS="$CLI_BASEDIR/node_modules/npm/bin/npx-cli.js" +NPM_PREFIX=`"$NODE_EXE" "$NPM_CLI_JS" prefix -g` if [ $? -ne 0 ]; then # if this didn't work, then everything else below will fail echo "Could not determine Node.js install directory" >&2 exit 1 fi -NPM_CLI_JS="$CLI_BASEDIR/node_modules/npm/bin/npm-cli.js" -NPX_CLI_JS="$CLI_BASEDIR/node_modules/npm/bin/npx-cli.js" -NPM_PREFIX=`"$NODE_EXE" "$NPM_CLI_JS" prefix -g` NPM_PREFIX_NPX_CLI_JS="$NPM_PREFIX/node_modules/npm/bin/npx-cli.js" # a path that will fail -f test on any posix bash diff --git a/bin/npx-cli.js b/bin/npx-cli.js index 75090aed41f1f..17d96fb26267c 100755 --- a/bin/npx-cli.js +++ b/bin/npx-cli.js @@ -24,7 +24,7 @@ const removed = new Set([ ...removedOpts, ]) -const { definitions, shorthands } = require('../lib/utils/config/index.js') +const { definitions, shorthands } = require('@npmcli/config/lib/definitions') const npmSwitches = Object.entries(definitions) .filter(([key, { type }]) => type === Boolean || (Array.isArray(type) && type.includes(Boolean))) diff --git a/docs/lib/content/configuring-npm/package-json.md b/docs/lib/content/configuring-npm/package-json.md index 19d04dc475694..219296f6186c7 100644 --- a/docs/lib/content/configuring-npm/package-json.md +++ b/docs/lib/content/configuring-npm/package-json.md @@ -279,9 +279,6 @@ 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`. - Certain files are always included, regardless of settings: * `package.json` @@ -323,7 +320,7 @@ 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. -If `main` is not set it defaults to `index.js` in the package's root folder. +If `main` is not set, it defaults to `index.js` in the package's root folder. ### browser diff --git a/docs/lib/index.js b/docs/lib/index.js index deb715b38107a..5d4ae7af3457b 100644 --- a/docs/lib/index.js +++ b/docs/lib/index.js @@ -3,7 +3,7 @@ const { join, basename, resolve } = require('path') const transformHTML = require('./transform-html.js') const { version } = require('../../lib/npm.js') const { aliases } = require('../../lib/utils/cmd-list') -const { shorthands, definitions } = require('../../lib/utils/config/index.js') +const { shorthands, definitions } = require('@npmcli/config/lib/definitions') const DOC_EXT = '.md' @@ -42,6 +42,17 @@ const getCommandByDoc = (docFile, docExt) => { const srcName = name === 'npx' ? 'exec' : name const { params, usage = [''], workspaces } = require(`../../lib/commands/${srcName}`) const usagePrefix = name === 'npx' ? 'npx' : `npm ${name}` + if (params) { + for (const param of params) { + if (definitions[param].exclusive) { + for (const e of definitions[param].exclusive) { + if (!params.includes(e)) { + params.splice(params.indexOf(param) + 1, 0, e) + } + } + } + } + } return { name, diff --git a/docs/package.json b/docs/package.json index 841071fb13c1b..78b62e540bfba 100644 --- a/docs/package.json +++ b/docs/package.json @@ -21,6 +21,7 @@ }, "devDependencies": { "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/config": "^6.1.7", "@npmcli/eslint-config": "^4.0.0", "@npmcli/template-oss": "4.14.1", "front-matter": "^4.0.2", diff --git a/lib/base-command.js b/lib/base-command.js index 0adff8e5d95ea..e763820cb052b 100644 --- a/lib/base-command.js +++ b/lib/base-command.js @@ -2,17 +2,81 @@ const { relative } = require('path') -const ConfigDefinitions = require('./utils/config/definitions.js') +const { definitions } = require('@npmcli/config/lib/definitions') const getWorkspaces = require('./workspaces/get-workspaces.js') - -const cmdAliases = require('./utils/cmd-list').aliases +const { aliases: cmdAliases } = require('./utils/cmd-list') class BaseCommand { static workspaces = false static ignoreImplicitWorkspace = true + // these are all overridden by individual commands + static name = null + static description = null + static params = null + + // this is a static so that we can read from it without instantiating a command + // which would require loading the config + static get describeUsage () { + const seenExclusive = new Set() + const wrapWidth = 80 + const { description, usage = [''], name, params } = this + + const fullUsage = [ + `${description}`, + '', + 'Usage:', + ...usage.map(u => `npm ${name} ${u}`.trim()), + ] + + if (params) { + let results = '' + let line = '' + for (const param of params) { + /* istanbul ignore next */ + if (seenExclusive.has(param)) { + continue + } + const { exclusive } = definitions[param] + let paramUsage = `${definitions[param].usage}` + if (exclusive) { + const exclusiveParams = [paramUsage] + seenExclusive.add(param) + for (const e of exclusive) { + seenExclusive.add(e) + exclusiveParams.push(definitions[e].usage) + } + paramUsage = `${exclusiveParams.join('|')}` + } + paramUsage = `[${paramUsage}]` + if (line.length + paramUsage.length > wrapWidth) { + results = [results, line].filter(Boolean).join('\n') + line = '' + } + line = [line, paramUsage].filter(Boolean).join(' ') + } + fullUsage.push('') + fullUsage.push('Options:') + fullUsage.push([results, line].filter(Boolean).join('\n')) + } + + const aliases = Object.entries(cmdAliases).reduce((p, [k, v]) => { + return p.concat(v === name ? k : []) + }, []) + + if (aliases.length) { + const plural = aliases.length === 1 ? '' : 'es' + fullUsage.push('') + fullUsage.push(`alias${plural}: ${aliases.join(', ')}`) + } + + fullUsage.push('') + fullUsage.push(`Run "npm help ${name}" for more info`) + + return fullUsage.join('\n') + } + constructor (npm) { - this.wrapWidth = 80 this.npm = npm const { config } = this.npm @@ -39,59 +103,7 @@ class BaseCommand { } get usage () { - const usage = [ - `${this.description}`, - '', - 'Usage:', - ] - - if (!this.constructor.usage) { - usage.push(`npm ${this.name}`) - } else { - usage.push(...this.constructor.usage.map(u => `npm ${this.name} ${u}`)) - } - - if (this.params) { - usage.push('') - usage.push('Options:') - usage.push(this.wrappedParams) - } - - const aliases = Object.keys(cmdAliases).reduce((p, c) => { - if (cmdAliases[c] === this.name) { - p.push(c) - } - return p - }, []) - - if (aliases.length === 1) { - usage.push('') - usage.push(`alias: ${aliases.join(', ')}`) - } else if (aliases.length > 1) { - usage.push('') - usage.push(`aliases: ${aliases.join(', ')}`) - } - - usage.push('') - usage.push(`Run "npm help ${this.name}" for more info`) - - return usage.join('\n') - } - - get wrappedParams () { - let results = '' - let line = '' - - for (const param of this.params) { - const usage = `[${ConfigDefinitions[param].usage}]` - if (line.length && line.length + usage.length > this.wrapWidth) { - results = [results, line].filter(Boolean).join('\n') - line = '' - } - line = [line, usage].filter(Boolean).join(' ') - } - results = [results, line].filter(Boolean).join('\n') - return results + return this.constructor.describeUsage } usageError (prefix = '') { diff --git a/lib/cli-entry.js b/lib/cli-entry.js new file mode 100644 index 0000000000000..aad06e0690385 --- /dev/null +++ b/lib/cli-entry.js @@ -0,0 +1,74 @@ +/* eslint-disable max-len */ + +// Separated out for easier unit testing +module.exports = async (process, validateEngines) => { + // set it here so that regardless of what happens later, we don't + // leak any private CLI configs to other programs + process.title = 'npm' + + // if npm is called as "npmg" or "npm_g", then run in global mode. + if (process.argv[1][process.argv[1].length - 1] === 'g') { + process.argv.splice(1, 1, 'npm', '-g') + } + + const satisfies = require('semver/functions/satisfies') + const exitHandler = require('./utils/exit-handler.js') + const Npm = require('./npm.js') + const npm = new Npm() + exitHandler.setNpm(npm) + + // only log node and npm paths in argv initially since argv can contain sensitive info. a cleaned version will be logged later + const log = require('./utils/log-shim.js') + log.verbose('cli', process.argv.slice(0, 2).join(' ')) + log.info('using', 'npm@%s', npm.version) + log.info('using', 'node@%s', process.version) + + // At this point we've required a few files and can be pretty sure we dont contain invalid syntax for this version of node. It's possible a lazy require would, but that's unlikely enough that it's not worth catching anymore and we attach the more important exit handlers. + validateEngines.off() + process.on('uncaughtException', exitHandler) + process.on('unhandledRejection', exitHandler) + + // It is now safe to log a warning if they are using a version of node that is not going to fail on syntax errors but is still unsupported and untested and might not work reliably. This is safe to use the logger now which we want since this will show up in the error log too. + if (!satisfies(validateEngines.node, validateEngines.engines)) { + log.warn('cli', validateEngines.unsupportedMessage) + } + + let cmd + // Now actually fire up npm and run the command. + // This is how to use npm programmatically: + try { + await npm.load() + + // npm -v + if (npm.config.get('version', 'cli')) { + npm.output(npm.version) + return exitHandler() + } + + // npm --versions + if (npm.config.get('versions', 'cli')) { + npm.argv = ['version'] + npm.config.set('usage', false, 'cli') + } + + cmd = npm.argv.shift() + if (!cmd) { + npm.output(npm.usage) + process.exitCode = 1 + return exitHandler() + } + + await npm.exec(cmd) + return exitHandler() + } catch (err) { + if (err.code === 'EUNKNOWNCOMMAND') { + const didYouMean = require('./utils/did-you-mean.js') + const suggestions = await didYouMean(npm.localPrefix, cmd) + npm.output(`Unknown command: "${cmd}"${suggestions}\n`) + npm.output('To see a list of supported npm commands, run:\n npm help') + process.exitCode = 1 + return exitHandler() + } + return exitHandler(err) + } +} diff --git a/lib/cli.js b/lib/cli.js index a393626f08291..c85ecb65a7005 100644 --- a/lib/cli.js +++ b/lib/cli.js @@ -1,102 +1,4 @@ -/* eslint-disable max-len */ -// Code in this file should work in all conceivably runnable versions of node. -// A best effort is made to catch syntax errors to give users a good error message if they are using a node version that doesn't allow syntax we are using in other files such as private properties, etc +const validateEngines = require('./es6/validate-engines.js') +const cliEntry = require('path').resolve(__dirname, 'cli-entry.js') -// Separated out for easier unit testing -module.exports = async process => { - // set it here so that regardless of what happens later, we don't - // leak any private CLI configs to other programs - process.title = 'npm' - - // if npm is called as "npmg" or "npm_g", then run in global mode. - if (process.argv[1][process.argv[1].length - 1] === 'g') { - process.argv.splice(1, 1, 'npm', '-g') - } - - const nodeVersion = process.version.replace(/-.*$/, '') - const pkg = require('../package.json') - const engines = pkg.engines.node - const npmVersion = `v${pkg.version}` - - const unsupportedMessage = `npm ${npmVersion} does not support Node.js ${nodeVersion}. This version of npm supports the following node versions: \`${engines}\`. You can find the latest version at https://nodejs.org/.` - - const brokenMessage = `ERROR: npm ${npmVersion} is known not to run on Node.js ${nodeVersion}. This version of npm supports the following node versions: \`${engines}\`. You can find the latest version at https://nodejs.org/.` - - // Coverage ignored because this is only hit in very unsupported node versions and it's a best effort attempt to show something nice in those cases - /* istanbul ignore next */ - const syntaxErrorHandler = (err) => { - if (err instanceof SyntaxError) { - // eslint-disable-next-line no-console - console.error(`${brokenMessage}\n\nERROR:`) - // eslint-disable-next-line no-console - console.error(err) - return process.exit(1) - } - throw err - } - - process.on('uncaughtException', syntaxErrorHandler) - process.on('unhandledRejection', syntaxErrorHandler) - - const satisfies = require('semver/functions/satisfies') - const exitHandler = require('./utils/exit-handler.js') - const Npm = require('./npm.js') - const npm = new Npm() - exitHandler.setNpm(npm) - - // only log node and npm paths in argv initially since argv can contain sensitive info. a cleaned version will be logged later - const log = require('./utils/log-shim.js') - log.verbose('cli', process.argv.slice(0, 2).join(' ')) - log.info('using', 'npm@%s', npm.version) - log.info('using', 'node@%s', process.version) - - // At this point we've required a few files and can be pretty sure we dont contain invalid syntax for this version of node. It's possible a lazy require would, but that's unlikely enough that it's not worth catching anymore and we attach the more important exit handlers. - process.off('uncaughtException', syntaxErrorHandler) - process.off('unhandledRejection', syntaxErrorHandler) - process.on('uncaughtException', exitHandler) - process.on('unhandledRejection', exitHandler) - - // It is now safe to log a warning if they are using a version of node that is not going to fail on syntax errors but is still unsupported and untested and might not work reliably. This is safe to use the logger now which we want since this will show up in the error log too. - if (!satisfies(nodeVersion, engines)) { - log.warn('cli', unsupportedMessage) - } - - let cmd - // Now actually fire up npm and run the command. - // This is how to use npm programmatically: - try { - await npm.load() - - // npm -v - if (npm.config.get('version', 'cli')) { - npm.output(npm.version) - return exitHandler() - } - - // npm --versions - if (npm.config.get('versions', 'cli')) { - npm.argv = ['version'] - npm.config.set('usage', false, 'cli') - } - - cmd = npm.argv.shift() - if (!cmd) { - npm.output(await npm.usage) - process.exitCode = 1 - return exitHandler() - } - - await npm.exec(cmd) - return exitHandler() - } catch (err) { - if (err.code === 'EUNKNOWNCOMMAND') { - const didYouMean = require('./utils/did-you-mean.js') - const suggestions = await didYouMean(npm, npm.localPrefix, cmd) - npm.output(`Unknown command: "${cmd}"${suggestions}\n`) - npm.output('To see a list of supported npm commands, run:\n npm help') - process.exitCode = 1 - return exitHandler() - } - return exitHandler(err) - } -} +module.exports = (process) => validateEngines(process, () => require(cliEntry)) diff --git a/lib/commands/access.js b/lib/commands/access.js index 318151fc81e2c..99c1264a84eda 100644 --- a/lib/commands/access.js +++ b/lib/commands/access.js @@ -1,8 +1,6 @@ -const path = require('path') - const libnpmaccess = require('libnpmaccess') const npa = require('npm-package-arg') -const readPackageJson = require('read-package-json-fast') +const pkgJson = require('@npmcli/package-json') const localeCompare = require('@isaacs/string-locale-compare')('en') const otplease = require('../utils/otplease.js') @@ -47,7 +45,7 @@ class Access extends BaseCommand { 'revoke []', ] - async completion (opts) { + static async completion (opts) { const argv = opts.conf.argv.remain if (argv.length === 2) { return commands @@ -178,8 +176,8 @@ class Access extends BaseCommand { async #getPackage (name, requireScope) { if (!name) { try { - const pkg = await readPackageJson(path.resolve(this.npm.prefix, 'package.json')) - name = pkg.name + const { content } = await pkgJson.normalize(this.npm.prefix) + name = content.name } catch (err) { if (err.code === 'ENOENT') { throw Object.assign(new Error('no package name given and no package.json found'), { diff --git a/lib/commands/audit.js b/lib/commands/audit.js index 7b75ecbf2e024..500620f2cd01b 100644 --- a/lib/commands/audit.js +++ b/lib/commands/audit.js @@ -1,9 +1,10 @@ -const auditReport = require('npm-audit-report') +const npmAuditReport = require('npm-audit-report') const fetch = require('npm-registry-fetch') const localeCompare = require('@isaacs/string-locale-compare')('en') const npa = require('npm-package-arg') const pacote = require('pacote') const pMap = require('p-map') +const { sigstore } = require('sigstore') const ArboristWorkspaceCmd = require('../arborist-cmd.js') const auditError = require('../utils/audit-error.js') @@ -37,7 +38,12 @@ class VerifySignatures { throw new Error('found no installed dependencies to audit') } - await Promise.all([...registries].map(registry => this.setKeys({ registry }))) + const tuf = await sigstore.tuf.client({ + tufCachePath: this.opts.tufCache, + retry: this.opts.retry, + timeout: this.opts.timeout, + }) + await Promise.all([...registries].map(registry => this.setKeys({ registry, tuf }))) const progress = log.newItem('verifying registry signatures', edges.size) const mapper = async (edge) => { @@ -187,20 +193,42 @@ class VerifySignatures { return { edges, registries } } - async setKeys ({ registry }) { - const keys = await fetch.json('/-/npm/v1/keys', { - ...this.npm.flatOptions, - registry, - }).then(({ keys: ks }) => ks.map((key) => ({ - ...key, - pemkey: `-----BEGIN PUBLIC KEY-----\n${key.key}\n-----END PUBLIC KEY-----`, - }))).catch(err => { - if (err.code === 'E404' || err.code === 'E400') { - return null - } else { - throw err - } - }) + async setKeys ({ registry, tuf }) { + const { host, pathname } = new URL(registry) + // Strip any trailing slashes from pathname + const regKey = `${host}${pathname.replace(/\/$/, '')}/keys.json` + let keys = await tuf.getTarget(regKey) + .then((target) => JSON.parse(target)) + .then(({ keys: ks }) => ks.map((key) => ({ + ...key, + keyid: key.keyId, + pemkey: `-----BEGIN PUBLIC KEY-----\n${key.publicKey.rawBytes}\n-----END PUBLIC KEY-----`, + expires: key.publicKey.validFor.end || null, + }))).catch(err => { + if (err.code === 'TUF_FIND_TARGET_ERROR') { + return null + } else { + throw err + } + }) + + // If keys not found in Sigstore TUF repo, fallback to registry keys API + if (!keys) { + keys = await fetch.json('/-/npm/v1/keys', { + ...this.npm.flatOptions, + registry, + }).then(({ keys: ks }) => ks.map((key) => ({ + ...key, + pemkey: `-----BEGIN PUBLIC KEY-----\n${key.key}\n-----END PUBLIC KEY-----`, + }))).catch(err => { + if (err.code === 'E404' || err.code === 'E400') { + return null + } else { + throw err + } + }) + } + if (keys) { this.keys.set(registry, keys) } @@ -384,7 +412,7 @@ class Audit extends ArboristWorkspaceCmd { static usage = ['[fix|signatures]'] - async completion (opts) { + static async completion (opts) { const argv = opts.conf.argv.remain if (argv.length === 2) { @@ -429,7 +457,10 @@ class Audit extends ArboristWorkspaceCmd { } else { // will throw if there's an error, because this is an audit command auditError(this.npm, arb.auditReport) - const result = auditReport(arb.auditReport, opts) + const result = npmAuditReport(arb.auditReport, { + ...opts, + chalk: this.npm.chalk, + }) process.exitCode = process.exitCode || result.exitCode this.npm.output(result.report) } diff --git a/lib/commands/cache.js b/lib/commands/cache.js index 9965f7085d9ad..50bb35e3544df 100644 --- a/lib/commands/cache.js +++ b/lib/commands/cache.js @@ -73,10 +73,10 @@ class Cache extends BaseCommand { 'verify', ] - async completion (opts) { + static async completion (opts) { const argv = opts.conf.argv.remain if (argv.length === 2) { - return ['add', 'clean', 'verify', 'ls', 'delete'] + return ['add', 'clean', 'verify', 'ls'] } // TODO - eventually... @@ -85,7 +85,6 @@ class Cache extends BaseCommand { case 'clean': case 'add': case 'ls': - case 'delete': return [] } } diff --git a/lib/commands/ci.js b/lib/commands/ci.js index 97c292e8c5389..e662379278e03 100644 --- a/lib/commands/ci.js +++ b/lib/commands/ci.js @@ -17,7 +17,6 @@ class CI extends ArboristWorkspaceCmd { 'global-style', 'omit', 'strict-peer-deps', - 'package-lock', 'foreground-scripts', 'ignore-scripts', 'audit', diff --git a/lib/commands/completion.js b/lib/commands/completion.js index efbad9d61001b..59113c50560bc 100644 --- a/lib/commands/completion.js +++ b/lib/commands/completion.js @@ -33,8 +33,9 @@ const fs = require('fs/promises') const nopt = require('nopt') const { resolve } = require('path') -const { definitions, shorthands } = require('../utils/config/index.js') -const { commands, aliases } = require('../utils/cmd-list.js') +const Npm = require('../npm.js') +const { definitions, shorthands } = require('@npmcli/config/lib/definitions') +const { commands, aliases, deref } = require('../utils/cmd-list.js') const configNames = Object.keys(definitions) const shorthandNames = Object.keys(shorthands) const allConfs = configNames.concat(shorthandNames) @@ -48,7 +49,7 @@ class Completion extends BaseCommand { static name = 'completion' // completion for the completion command - async completion (opts) { + static async completion (opts) { if (opts.w > 2) { return } @@ -156,10 +157,14 @@ class Completion extends BaseCommand { // at this point, if words[1] is some kind of npm command, // then complete on it. // otherwise, do nothing - const impl = await this.npm.cmd(cmd) - if (impl.completion) { - const comps = await impl.completion(opts) - return this.wrap(opts, comps) + try { + const { completion } = Npm.cmd(cmd) + if (completion) { + const comps = await completion(opts, this.npm) + return this.wrap(opts, comps) + } + } catch { + // it wasnt a valid command, so do nothing } } @@ -267,7 +272,7 @@ const cmdCompl = (opts, npm) => { return matches } - const derefs = new Set([...matches.map(c => npm.deref(c))]) + const derefs = new Set([...matches.map(c => deref(c))]) if (derefs.size === 1) { return [...derefs] } diff --git a/lib/commands/config.js b/lib/commands/config.js index dfd44015cd043..8e8358fc50b7b 100644 --- a/lib/commands/config.js +++ b/lib/commands/config.js @@ -1,13 +1,11 @@ -// don't expand so that we only assemble the set of defaults when needed -const configDefs = require('../utils/config/index.js') - const { mkdir, readFile, writeFile } = require('fs/promises') const { dirname, resolve } = require('path') const { spawn } = require('child_process') const { EOL } = require('os') const ini = require('ini') const localeCompare = require('@isaacs/string-locale-compare')('en') -const rpj = require('read-package-json-fast') +const pkgJson = require('@npmcli/package-json') +const { defaults, definitions } = require('@npmcli/config/lib/definitions') const log = require('../utils/log-shim.js') // These are the configs that we can nerf-dart. Not all of them currently even @@ -74,7 +72,7 @@ class Config extends BaseCommand { static skipConfigValidation = true - async completion (opts) { + static async completion (opts) { const argv = opts.conf.argv.remain if (argv[1] !== 'config') { argv.unshift('config') @@ -102,7 +100,7 @@ class Config extends BaseCommand { case 'get': case 'delete': case 'rm': - return Object.keys(configDefs.definitions) + return Object.keys(definitions) case 'edit': case 'list': case 'ls': @@ -219,7 +217,7 @@ class Config extends BaseCommand { const data = ( await readFile(file, 'utf8').catch(() => '') ).replace(/\r\n/g, '\n') - const entries = Object.entries(configDefs.defaults) + const entries = Object.entries(defaults) const defData = entries.reduce((str, [key, val]) => { const obj = { [key]: val } const i = ini.stringify(obj) @@ -346,15 +344,15 @@ ${defData} } if (!this.npm.global) { - const pkgPath = resolve(this.npm.prefix, 'package.json') - const pkg = await rpj(pkgPath).catch(() => ({})) + const { content } = await pkgJson.normalize(this.npm.prefix).catch(() => ({ content: {} })) - if (pkg.publishConfig) { + if (content.publishConfig) { + const pkgPath = resolve(this.npm.prefix, 'package.json') msg.push(`; "publishConfig" from ${pkgPath}`) msg.push('; This set of config values will be used at publish-time.', '') - const pkgKeys = Object.keys(pkg.publishConfig).sort(localeCompare) + const pkgKeys = Object.keys(content.publishConfig).sort(localeCompare) for (const k of pkgKeys) { - const v = publicVar(k) ? JSON.stringify(pkg.publishConfig[k]) : '(protected)' + const v = publicVar(k) ? JSON.stringify(content.publishConfig[k]) : '(protected)' msg.push(`${k} = ${v}`) } msg.push('') diff --git a/lib/commands/deprecate.js b/lib/commands/deprecate.js index 844d5f60a02ab..ada2bac40f2fd 100644 --- a/lib/commands/deprecate.js +++ b/lib/commands/deprecate.js @@ -17,13 +17,13 @@ class Deprecate extends BaseCommand { static ignoreImplicitWorkspace = false - async completion (opts) { + static async completion (opts, npm) { if (opts.conf.argv.remain.length > 1) { return [] } - const username = await getIdentity(this.npm, this.npm.flatOptions) - const packages = await libaccess.getPackages(username, this.npm.flatOptions) + const username = await getIdentity(npm, npm.flatOptions) + const packages = await libaccess.getPackages(username, npm.flatOptions) return Object.keys(packages) .filter((name) => packages[name] === 'write' && diff --git a/lib/commands/diff.js b/lib/commands/diff.js index 3924166af0a88..64d81d525d79d 100644 --- a/lib/commands/diff.js +++ b/lib/commands/diff.js @@ -5,7 +5,7 @@ const npa = require('npm-package-arg') const pacote = require('pacote') const pickManifest = require('npm-pick-manifest') const log = require('../utils/log-shim') -const readPackage = require('read-package-json-fast') +const pkgJson = require('@npmcli/package-json') const BaseCommand = require('../base-command.js') class Diff extends BaseCommand { @@ -81,7 +81,7 @@ class Diff extends BaseCommand { async packageName (path) { let name try { - const pkg = await readPackage(resolve(this.prefix, 'package.json')) + const { content: pkg } = await pkgJson.normalize(this.prefix) name = pkg.name } catch (e) { log.verbose('diff', 'could not read project dir package.json') @@ -115,7 +115,7 @@ class Diff extends BaseCommand { let noPackageJson let pkgName try { - const pkg = await readPackage(resolve(this.prefix, 'package.json')) + const { content: pkg } = await pkgJson.normalize(this.prefix) pkgName = pkg.name } catch (e) { log.verbose('diff', 'could not read project dir package.json') @@ -228,7 +228,7 @@ class Diff extends BaseCommand { if (semverA && semverB) { let pkgName try { - const pkg = await readPackage(resolve(this.prefix, 'package.json')) + const { content: pkg } = await pkgJson.normalize(this.prefix) pkgName = pkg.name } catch (e) { log.verbose('diff', 'could not read project dir package.json') diff --git a/lib/commands/dist-tag.js b/lib/commands/dist-tag.js index bc61a4691e55a..15f9622d14906 100644 --- a/lib/commands/dist-tag.js +++ b/lib/commands/dist-tag.js @@ -1,10 +1,9 @@ const npa = require('npm-package-arg') -const path = require('path') const regFetch = require('npm-registry-fetch') const semver = require('semver') const log = require('../utils/log-shim') const otplease = require('../utils/otplease.js') -const readPackage = require('read-package-json-fast') +const pkgJson = require('@npmcli/package-json') const BaseCommand = require('../base-command.js') class DistTag extends BaseCommand { @@ -20,7 +19,7 @@ class DistTag extends BaseCommand { static workspaces = true static ignoreImplicitWorkspace = false - async completion (opts) { + static async completion (opts) { const argv = opts.conf.argv.remain if (argv.length === 2) { return ['add', 'rm', 'ls'] @@ -152,7 +151,7 @@ class DistTag extends BaseCommand { if (this.npm.global) { throw this.usageError() } - const { name } = await readPackage(path.resolve(this.npm.prefix, 'package.json')) + const { content: { name } } = await pkgJson.normalize(this.npm.prefix) if (!name) { throw this.usageError() } diff --git a/lib/commands/doctor.js b/lib/commands/doctor.js index 19262e537dbe0..96e343701d1d5 100644 --- a/lib/commands/doctor.js +++ b/lib/commands/doctor.js @@ -9,9 +9,7 @@ const semver = require('semver') const { promisify } = require('util') const log = require('../utils/log-shim.js') const ping = require('../utils/ping.js') -const { - registry: { default: defaultRegistry }, -} = require('../utils/config/definitions.js') +const { defaults } = require('@npmcli/config/lib/definitions') const lstat = promisify(fs.lstat) const readdir = promisify(fs.readdir) const access = promisify(fs.access) @@ -364,16 +362,17 @@ class Doctor extends BaseCommand { } async checkNpmRegistry () { - if (this.npm.flatOptions.registry !== defaultRegistry) { - throw `Try \`npm config set registry=${defaultRegistry}\`` + if (this.npm.flatOptions.registry !== defaults.registry) { + throw `Try \`npm config set registry=${defaults.registry}\`` } else { - return `using default registry (${defaultRegistry})` + return `using default registry (${defaults.registry})` } } output (row) { const t = new Table({ - chars: { top: '', + chars: { + top: '', 'top-mid': '', 'top-left': '', 'top-right': '', @@ -387,8 +386,17 @@ class Doctor extends BaseCommand { 'mid-mid': '', right: '', 'right-mid': '', - middle: ' ' }, - style: { 'padding-left': 0, 'padding-right': 0 }, + middle: ' ', + }, + style: { + 'padding-left': 0, + 'padding-right': 0, + // setting border here is not necessary visually since we've already + // zeroed out all the chars above, but without it cli-table3 will wrap + // some of the separator spaces with ansi codes which show up in + // snapshots. + border: 0, + }, colWidths: [this.#checkWidth, 6], }) t.push(row) diff --git a/lib/commands/edit.js b/lib/commands/edit.js index a671a5d6bad5d..fbc7840a39876 100644 --- a/lib/commands/edit.js +++ b/lib/commands/edit.js @@ -38,8 +38,8 @@ class Edit extends BaseCommand { // TODO /* istanbul ignore next */ - async completion (opts) { - return completion(this.npm, opts) + static async completion (opts, npm) { + return completion(npm, opts) } async exec (args) { diff --git a/lib/commands/exec.js b/lib/commands/exec.js index a5235c7845851..ed4b07dc39b4d 100644 --- a/lib/commands/exec.js +++ b/lib/commands/exec.js @@ -54,6 +54,7 @@ class Exec extends BaseCommand { localBin, globalBin, globalDir, + chalk, } = this.npm const output = this.npm.output.bind(this.npm) const scriptShell = this.npm.config.get('script-shell') || undefined @@ -83,6 +84,7 @@ class Exec extends BaseCommand { globalBin, globalPath, output, + chalk, packages, path: localPrefix, runPath, diff --git a/lib/commands/explain.js b/lib/commands/explain.js index a72514fb97805..403274db68dfa 100644 --- a/lib/commands/explain.js +++ b/lib/commands/explain.js @@ -18,9 +18,9 @@ class Explain extends ArboristWorkspaceCmd { // TODO /* istanbul ignore next */ - async completion (opts) { + static async completion (opts, npm) { const completion = require('../utils/completion/installed-deep.js') - return completion(this.npm, opts) + return completion(npm, opts) } async exec (args) { diff --git a/lib/commands/explore.js b/lib/commands/explore.js index 0d915cb4c6958..7a03ea4eabd7f 100644 --- a/lib/commands/explore.js +++ b/lib/commands/explore.js @@ -1,9 +1,9 @@ // npm explore [@] // open a subshell to the package folder. -const rpj = require('read-package-json-fast') +const pkgJson = require('@npmcli/package-json') const runScript = require('@npmcli/run-script') -const { join, resolve, relative } = require('path') +const { join, relative } = require('path') const log = require('../utils/log-shim.js') const completion = require('../utils/completion/installed-shallow.js') const BaseCommand = require('../base-command.js') @@ -17,8 +17,8 @@ class Explore extends BaseCommand { // TODO /* istanbul ignore next */ - async completion (opts) { - return completion(this.npm, opts) + static async completion (opts, npm) { + return completion(npm, opts) } async exec (args) { @@ -38,7 +38,7 @@ class Explore extends BaseCommand { // the set of arguments, or the shell config, and let @npmcli/run-script // handle all the escaping and PATH setup stuff. - const pkg = await rpj(resolve(path, 'package.json')).catch(er => { + const { content: pkg } = await pkgJson.normalize(path).catch(er => { log.error('explore', `It doesn't look like ${pkgname} is installed.`) throw er }) diff --git a/lib/commands/fund.js b/lib/commands/fund.js index 1e8981967fc32..2804d36cd5603 100644 --- a/lib/commands/fund.js +++ b/lib/commands/fund.js @@ -36,9 +36,9 @@ class Fund extends ArboristWorkspaceCmd { // TODO /* istanbul ignore next */ - async completion (opts) { + static async completion (opts, npm) { const completion = require('../utils/completion/installed-deep.js') - return completion(this.npm, opts) + return completion(npm, opts) } async exec (args) { diff --git a/lib/commands/get.js b/lib/commands/get.js index 5e92e85a66382..4bf5d2caf8264 100644 --- a/lib/commands/get.js +++ b/lib/commands/get.js @@ -1,16 +1,18 @@ +const Npm = require('../npm.js') const BaseCommand = require('../base-command.js') class Get extends BaseCommand { static description = 'Get a value from the npm configuration' static name = 'get' static usage = ['[ ...] (See `npm config`)'] + static params = ['long'] static ignoreImplicitWorkspace = false // TODO /* istanbul ignore next */ - async completion (opts) { - const config = await this.npm.cmd('config') - return config.completion(opts) + static async completion (opts) { + const Config = Npm.cmd('config') + return Config.completion(opts) } async exec (args) { diff --git a/lib/commands/help.js b/lib/commands/help.js index 4b40ef37afa2d..39c580f9a6871 100644 --- a/lib/commands/help.js +++ b/lib/commands/help.js @@ -3,6 +3,7 @@ const path = require('path') const openUrl = require('../utils/open-url.js') const { glob } = require('glob') const localeCompare = require('@isaacs/string-locale-compare')('en') +const { deref } = require('../utils/cmd-list.js') const globify = pattern => pattern.split('\\').join('/') const BaseCommand = require('../base-command.js') @@ -26,11 +27,11 @@ class Help extends BaseCommand { static usage = [' []'] static params = ['viewer'] - async completion (opts) { + static async completion (opts, npm) { if (opts.conf.argv.remain.length > 2) { return [] } - const g = path.resolve(this.npm.npmRoot, 'man/man[0-9]/*.[0-9]') + const g = path.resolve(npm.npmRoot, 'man/man[0-9]/*.[0-9]') let files = await glob(globify(g)) // preserve glob@8 behavior files = files.sort((a, b) => a.localeCompare(b, 'en')) @@ -49,7 +50,7 @@ class Help extends BaseCommand { const manSearch = /^\d+$/.test(args[0]) ? `man${args.shift()}` : 'man*' if (!args.length) { - return this.npm.output(await this.npm.usage) + return this.npm.output(this.npm.usage) } // npm help foo bar baz: search topics @@ -58,7 +59,7 @@ class Help extends BaseCommand { } // `npm help package.json` - const arg = (this.npm.deref(args[0]) || args[0]).replace('.json', '-json') + const arg = (deref(args[0]) || args[0]).replace('.json', '-json') // find either section.n or npm-section.n const f = globify(path.resolve(this.npm.npmRoot, `man/${manSearch}/?(npm-)${arg}.[0-9]*`)) diff --git a/lib/commands/init.js b/lib/commands/init.js index 1e5661a7840f2..539fba885deef 100644 --- a/lib/commands/init.js +++ b/lib/commands/init.js @@ -3,7 +3,6 @@ const { relative, resolve } = require('path') const { mkdir } = require('fs/promises') const initJson = require('init-package-json') const npa = require('npm-package-arg') -const rpj = require('read-package-json-fast') const libexec = require('libnpmexec') const mapWorkspaces = require('@npmcli/map-workspaces') const PackageJson = require('@npmcli/package-json') @@ -54,7 +53,7 @@ class Init extends BaseCommand { // reads package.json for the top-level folder first, by doing this we // ensure the command throw if no package.json is found before trying // to create a workspace package.json file or its folders - const pkg = await rpj(resolve(this.npm.localPrefix, 'package.json')).catch((err) => { + const { content: pkg } = await PackageJson.normalize(this.npm.localPrefix).catch(err => { if (err.code === 'ENOENT') { log.warn('Missing package.json. Try with `--include-workspace-root`.') } @@ -120,11 +119,11 @@ class Init extends BaseCommand { } const newArgs = [packageName, ...otherArgs] - const { color } = this.npm.flatOptions const { flatOptions, localBin, globalBin, + chalk, } = this.npm const output = this.npm.output.bind(this.npm) const runPath = path @@ -134,10 +133,10 @@ class Init extends BaseCommand { await libexec({ ...flatOptions, args: newArgs, - color, localBin, globalBin, output, + chalk, path, runPath, scriptShell, @@ -217,7 +216,7 @@ class Init extends BaseCommand { // translate workspaces paths into an array containing workspaces names const workspaces = [] for (const path of workspacesPaths) { - const { name } = await rpj(resolve(path, 'package.json')).catch(() => ({})) + const { content: { name } } = await PackageJson.normalize(path).catch(() => ({ content: {} })) if (name) { workspaces.push(name) diff --git a/lib/commands/install.js b/lib/commands/install.js index 99f5b326f7b2b..75f0e2f175b61 100644 --- a/lib/commands/install.js +++ b/lib/commands/install.js @@ -25,7 +25,9 @@ class Install extends ArboristWorkspaceCmd { 'global-style', 'omit', 'strict-peer-deps', + 'prefer-dedupe', 'package-lock', + 'package-lock-only', 'foreground-scripts', 'ignore-scripts', 'audit', @@ -37,7 +39,7 @@ class Install extends ArboristWorkspaceCmd { static usage = ['[ ...]'] - async completion (opts) { + static async completion (opts) { const { partialWord } = opts // install can complete to a folder with a package.json, or any package. // if it has a slash, then it's gotta be a folder diff --git a/lib/commands/link.js b/lib/commands/link.js index 61ae5a9808868..a81450a247ed6 100644 --- a/lib/commands/link.js +++ b/lib/commands/link.js @@ -4,7 +4,7 @@ const readdir = util.promisify(fs.readdir) const { resolve } = require('path') const npa = require('npm-package-arg') -const rpj = require('read-package-json-fast') +const pkgJson = require('@npmcli/package-json') const semver = require('semver') const reifyFinish = require('../utils/reify-finish.js') @@ -35,8 +35,8 @@ class Link extends ArboristWorkspaceCmd { ...super.params, ] - async completion (opts) { - const dir = this.npm.globalDir + static async completion (opts, npm) { + const dir = npm.globalDir const files = await readdir(dir) return files.filter(f => !/^[._-]/.test(f)) } @@ -96,11 +96,12 @@ class Link extends ArboristWorkspaceCmd { const names = [] for (const a of args) { const arg = npa(a) - names.push( - arg.type === 'directory' - ? (await rpj(resolve(arg.fetchSpec, 'package.json'))).name - : arg.name - ) + if (arg.type === 'directory') { + const { content } = await pkgJson.normalize(arg.fetchSpec) + names.push(content.name) + } else { + names.push(arg.name) + } } // npm link should not save=true by default unless you're diff --git a/lib/commands/ls.js b/lib/commands/ls.js index eb9114802d5e0..92300b1c404a3 100644 --- a/lib/commands/ls.js +++ b/lib/commands/ls.js @@ -40,9 +40,9 @@ class LS extends ArboristWorkspaceCmd { // TODO /* istanbul ignore next */ - async completion (opts) { + static async completion (opts, npm) { const completion = require('../utils/completion/installed-deep.js') - return completion(this.npm, opts) + return completion(npm, opts) } async exec (args) { diff --git a/lib/commands/org.js b/lib/commands/org.js index 575ff75e2a6cf..1f32d41ff7306 100644 --- a/lib/commands/org.js +++ b/lib/commands/org.js @@ -14,7 +14,7 @@ class Org extends BaseCommand { static params = ['registry', 'otp', 'json', 'parseable'] - async completion (opts) { + static async completion (opts) { const argv = opts.conf.argv.remain if (argv.length === 2) { return ['set', 'rm', 'ls'] diff --git a/lib/commands/owner.js b/lib/commands/owner.js index 3a997db800db7..5b54dd41f3d60 100644 --- a/lib/commands/owner.js +++ b/lib/commands/owner.js @@ -3,14 +3,13 @@ const npmFetch = require('npm-registry-fetch') const pacote = require('pacote') const log = require('../utils/log-shim') const otplease = require('../utils/otplease.js') -const readPackageJsonFast = require('read-package-json-fast') +const pkgJson = require('@npmcli/package-json') const BaseCommand = require('../base-command.js') -const { resolve } = require('path') -const readJson = async (pkg) => { +const readJson = async (path) => { try { - const json = await readPackageJsonFast(pkg) - return json + const { content } = await pkgJson.normalize(path) + return content } catch { return {} } @@ -35,7 +34,7 @@ class Owner extends BaseCommand { static workspaces = true static ignoreImplicitWorkspace = false - async completion (opts) { + static async completion (opts, npm) { const argv = opts.conf.argv.remain if (argv.length > 3) { return [] @@ -51,17 +50,17 @@ class Owner extends BaseCommand { // reaches registry in order to autocomplete rm if (argv[2] === 'rm') { - if (this.npm.global) { + if (npm.global) { return [] } - const { name } = await readJson(resolve(this.npm.prefix, 'package.json')) + const { name } = await readJson(npm.prefix) if (!name) { return [] } const spec = npa(name) const data = await pacote.packument(spec, { - ...this.npm.flatOptions, + ...npm.flatOptions, fullMetadata: true, }) if (data && data.maintainers && data.maintainers.length) { @@ -130,7 +129,7 @@ class Owner extends BaseCommand { if (this.npm.global) { throw this.usageError() } - const { name } = await readJson(resolve(prefix, 'package.json')) + const { name } = await readJson(prefix) if (!name) { throw this.usageError() } diff --git a/lib/commands/profile.js b/lib/commands/profile.js index 4fba1209e0335..a7d4ac2f29fbe 100644 --- a/lib/commands/profile.js +++ b/lib/commands/profile.js @@ -53,7 +53,7 @@ class Profile extends BaseCommand { 'otp', ] - async completion (opts) { + static async completion (opts) { var argv = opts.conf.argv.remain if (!argv[2]) { diff --git a/lib/commands/publish.js b/lib/commands/publish.js index 8befbc5ca34ce..8d2aa9e0e47f6 100644 --- a/lib/commands/publish.js +++ b/lib/commands/publish.js @@ -1,4 +1,3 @@ -const util = require('util') const log = require('../utils/log-shim.js') const semver = require('semver') const pack = require('libnpmpack') @@ -16,12 +15,8 @@ const { getContents, logTar } = require('../utils/tar.js') // keys that npm supports in .npmrc files and elsewhere. We *may* want to // revisit this at some point, and have a minimal set that's a SemVer-major // change that ought to get a RFC written on it. -const { flatten } = require('../utils/config/index.js') - -// this is the only case in the CLI where we want to use the old full slow -// 'read-package-json' module, because we want to pull in all the defaults and -// metadata, like git sha's and default scripts and all that. -const readJson = util.promisify(require('read-package-json')) +const { flatten } = require('@npmcli/config/lib/definitions') +const pkgJson = require('@npmcli/package-json') const BaseCommand = require('../base-command.js') class Publish extends BaseCommand { @@ -204,7 +199,9 @@ class Publish extends BaseCommand { async getManifest (spec, opts) { let manifest if (spec.type === 'directory') { - manifest = await readJson(`${spec.fetchSpec}/package.json`) + // Prepare is the special function for publishing, different than normalize + const { content } = await pkgJson.prepare(spec.fetchSpec) + manifest = content } else { manifest = await pacote.manifest(spec, { ...opts, diff --git a/lib/commands/rebuild.js b/lib/commands/rebuild.js index 527447e427917..8af96f725555c 100644 --- a/lib/commands/rebuild.js +++ b/lib/commands/rebuild.js @@ -18,9 +18,9 @@ class Rebuild extends ArboristWorkspaceCmd { // TODO /* istanbul ignore next */ - async completion (opts) { + static async completion (opts, npm) { const completion = require('../utils/completion/installed-deep.js') - return completion(this.npm, opts) + return completion(npm, opts) } async exec (args) { diff --git a/lib/commands/run-script.js b/lib/commands/run-script.js index e1bce0e52a513..13efdde750a82 100644 --- a/lib/commands/run-script.js +++ b/lib/commands/run-script.js @@ -1,7 +1,6 @@ -const { resolve } = require('path') const runScript = require('@npmcli/run-script') const { isServerPackage } = runScript -const rpj = require('read-package-json-fast') +const pkgJson = require('@npmcli/package-json') const log = require('../utils/log-shim.js') const didYouMean = require('../utils/did-you-mean.js') const { isWindowsShell } = require('../utils/is-windows.js') @@ -36,12 +35,11 @@ class RunScript extends BaseCommand { static ignoreImplicitWorkspace = false static isShellout = true - async completion (opts) { + static async completion (opts, npm) { const argv = opts.conf.argv.remain if (argv.length === 2) { - // find the script name - const json = resolve(this.npm.localPrefix, 'package.json') - const { scripts = {} } = await rpj(json).catch(er => ({})) + const { content: { scripts = {} } } = await pkgJson.normalize(npm.localPrefix) + .catch(er => ({ content: {} })) if (opts.isFish) { return Object.keys(scripts).map(s => `${s}\t${scripts[s].slice(0, 30)}`) } @@ -70,7 +68,10 @@ class RunScript extends BaseCommand { // null value const scriptShell = this.npm.config.get('script-shell') || undefined - pkg = pkg || (await rpj(`${path}/package.json`)) + if (!pkg) { + const { content } = await pkgJson.normalize(path) + pkg = content + } const { scripts = {} } = pkg if (event === 'restart' && !scripts.restart) { @@ -89,7 +90,7 @@ class RunScript extends BaseCommand { return } - const suggestions = await didYouMean(this.npm, path, event) + const suggestions = await didYouMean(path, event) throw new Error( `Missing script: "${event}"${suggestions}\n\nTo see a list of scripts, run:\n npm run` ) @@ -126,8 +127,8 @@ class RunScript extends BaseCommand { } async list (args, path) { - path = path || this.npm.localPrefix - const { scripts, name, _id } = await rpj(`${path}/package.json`) + /* eslint-disable-next-line max-len */ + const { content: { scripts, name, _id } } = await pkgJson.normalize(path || this.npm.localPrefix) const pkgid = _id || name if (!scripts) { @@ -197,7 +198,7 @@ class RunScript extends BaseCommand { await this.setWorkspaces() for (const workspacePath of this.workspacePaths) { - const pkg = await rpj(`${workspacePath}/package.json`) + const { content: pkg } = await pkgJson.normalize(workspacePath) const runResult = await this.run(args, { path: workspacePath, pkg, @@ -236,7 +237,7 @@ class RunScript extends BaseCommand { if (this.npm.config.get('json')) { const res = {} for (const workspacePath of this.workspacePaths) { - const { scripts, name } = await rpj(`${workspacePath}/package.json`) + const { content: { scripts, name } } = await pkgJson.normalize(workspacePath) res[name] = { ...scripts } } this.npm.output(JSON.stringify(res, null, 2)) @@ -245,7 +246,7 @@ class RunScript extends BaseCommand { if (this.npm.config.get('parseable')) { for (const workspacePath of this.workspacePaths) { - const { scripts, name } = await rpj(`${workspacePath}/package.json`) + const { content: { scripts, name } } = await pkgJson.normalize(workspacePath) for (const [script, cmd] of Object.entries(scripts || {})) { this.npm.output(`${name}:${script}:${cmd}`) } diff --git a/lib/commands/set.js b/lib/commands/set.js index b650026a599a9..f315d183845c5 100644 --- a/lib/commands/set.js +++ b/lib/commands/set.js @@ -1,15 +1,18 @@ +const Npm = require('../npm.js') const BaseCommand = require('../base-command.js') class Set extends BaseCommand { static description = 'Set a value in the npm configuration' static name = 'set' static usage = ['= [= ...] (See `npm config`)'] + static params = ['global', 'location'] static ignoreImplicitWorkspace = false // TODO /* istanbul ignore next */ - async completion (opts) { - return this.npm.cmd('config').completion(opts) + static async completion (opts) { + const Config = Npm.cmd('config') + return Config.completion(opts) } async exec (args) { diff --git a/lib/commands/team.js b/lib/commands/team.js index 2d4fc663715e4..3c6cf305a6e5f 100644 --- a/lib/commands/team.js +++ b/lib/commands/team.js @@ -24,7 +24,7 @@ class Team extends BaseCommand { static ignoreImplicitWorkspace = false - async completion (opts) { + static async completion (opts) { const { conf: { argv: { remain: argv } } } = opts const subcommands = ['create', 'destroy', 'add', 'rm', 'ls'] diff --git a/lib/commands/token.js b/lib/commands/token.js index bc2e4f3796364..c24684b3dd614 100644 --- a/lib/commands/token.js +++ b/lib/commands/token.js @@ -14,7 +14,7 @@ class Token extends BaseCommand { static usage = ['list', 'revoke ', 'create [--read-only] [--cidr=list]'] static params = ['read-only', 'cidr', 'registry', 'otp'] - async completion (opts) { + static async completion (opts) { const argv = opts.conf.argv.remain const subcommands = ['list', 'revoke', 'create'] if (argv.length === 2) { diff --git a/lib/commands/uninstall.js b/lib/commands/uninstall.js index e5373119ec757..07775efb9cf2f 100644 --- a/lib/commands/uninstall.js +++ b/lib/commands/uninstall.js @@ -1,5 +1,5 @@ const { resolve } = require('path') -const rpj = require('read-package-json-fast') +const pkgJson = require('@npmcli/package-json') const reifyFinish = require('../utils/reify-finish.js') const completion = require('../utils/completion/installed-shallow.js') @@ -8,14 +8,14 @@ const ArboristWorkspaceCmd = require('../arborist-cmd.js') class Uninstall extends ArboristWorkspaceCmd { static description = 'Remove a package' static name = 'uninstall' - static params = ['save', ...super.params] + static params = ['save', 'global', ...super.params] static usage = ['[<@scope>/]...'] static ignoreImplicitWorkspace = false // TODO /* istanbul ignore next */ - async completion (opts) { - return completion(this.npm, opts) + static async completion (opts, npm) { + return completion(npm, opts) } async exec (args) { @@ -24,7 +24,7 @@ class Uninstall extends ArboristWorkspaceCmd { throw new Error('Must provide a package name to remove') } else { try { - const pkg = await rpj(resolve(this.npm.localPrefix, 'package.json')) + const { content: pkg } = await pkgJson.normalize(this.npm.localPrefix) args.push(pkg.name) } catch (er) { if (er.code !== 'ENOENT' && er.code !== 'ENOTDIR') { diff --git a/lib/commands/unpublish.js b/lib/commands/unpublish.js index f1bcded192e5a..402f8f30efff8 100644 --- a/lib/commands/unpublish.js +++ b/lib/commands/unpublish.js @@ -2,11 +2,9 @@ const libaccess = require('libnpmaccess') const libunpub = require('libnpmpublish').unpublish const npa = require('npm-package-arg') const npmFetch = require('npm-registry-fetch') -const path = require('path') -const util = require('util') -const readJson = util.promisify(require('read-package-json')) +const pkgJson = require('@npmcli/package-json') -const { flatten } = require('../utils/config/index.js') +const { flatten } = require('@npmcli/config/lib/definitions') const getIdentity = require('../utils/get-identity.js') const log = require('../utils/log-shim') const otplease = require('../utils/otplease.js') @@ -24,7 +22,7 @@ class Unpublish extends BaseCommand { static workspaces = true static ignoreImplicitWorkspace = false - async getKeysOfVersions (name, opts) { + static async getKeysOfVersions (name, opts) { const pkgUri = npa(name).escapedName const json = await npmFetch.json(`${pkgUri}?write=true`, { ...opts, @@ -33,15 +31,15 @@ class Unpublish extends BaseCommand { return Object.keys(json.versions) } - async completion (args) { + static async completion (args, npm) { const { partialWord, conf } = args if (conf.argv.remain.length >= 3) { return [] } - const opts = { ...this.npm.flatOptions } - const username = await getIdentity(this.npm, { ...opts }).catch(() => null) + const opts = { ...npm.flatOptions } + const username = await getIdentity(npm, { ...opts }).catch(() => null) if (!username) { return [] } @@ -96,8 +94,8 @@ class Unpublish extends BaseCommand { let manifest let manifestErr try { - const pkgJson = path.join(this.npm.localPrefix, 'package.json') - manifest = await readJson(pkgJson) + const { content } = await pkgJson.prepare(this.npm.localPrefix) + manifest = content } catch (err) { manifestErr = err } @@ -107,7 +105,7 @@ class Unpublish extends BaseCommand { if (manifest && manifest.name === spec.name && manifest.publishConfig) { flatten(manifest.publishConfig, opts) } - const versions = await this.getKeysOfVersions(spec.name, opts) + const versions = await Unpublish.getKeysOfVersions(spec.name, opts) if (versions.length === 1 && !force) { throw this.usageError(LAST_REMAINING_VERSION_ERROR) } diff --git a/lib/commands/update.js b/lib/commands/update.js index 26be5ad681983..caa69dd317ca6 100644 --- a/lib/commands/update.js +++ b/lib/commands/update.js @@ -31,9 +31,9 @@ class Update extends ArboristWorkspaceCmd { // TODO /* istanbul ignore next */ - async completion (opts) { + static async completion (opts, npm) { const completion = require('../utils/completion/installed-deep.js') - return completion(this.npm, opts) + return completion(npm, opts) } async exec (args) { diff --git a/lib/commands/version.js b/lib/commands/version.js index a523283671791..029a6fdd3101e 100644 --- a/lib/commands/version.js +++ b/lib/commands/version.js @@ -28,7 +28,7 @@ class Version extends BaseCommand { /* eslint-disable-next-line max-len */ static usage = ['[ | major | minor | patch | premajor | preminor | prepatch | prerelease | from-git]'] - async completion (opts) { + static async completion (opts) { const { conf: { argv: { remain }, diff --git a/lib/commands/view.js b/lib/commands/view.js index bbe7dcdd18bbf..f118184124db9 100644 --- a/lib/commands/view.js +++ b/lib/commands/view.js @@ -29,7 +29,7 @@ class View extends BaseCommand { static ignoreImplicitWorkspace = false static usage = ['[] [[.subfield]...]'] - async completion (opts) { + static async completion (opts, npm) { if (opts.conf.argv.remain.length <= 2) { // There used to be registry completion here, but it stopped // making sense somewhere around 50,000 packages on the registry @@ -37,13 +37,13 @@ class View extends BaseCommand { } // have the package, get the fields const config = { - ...this.npm.flatOptions, + ...npm.flatOptions, fullMetadata: true, preferOnline: true, } const spec = npa(opts.conf.argv.remain[2]) const pckmnt = await packument(spec, config) - const defaultTag = this.npm.config.get('tag') + const defaultTag = npm.config.get('tag') const dv = pckmnt.versions[pckmnt['dist-tags'][defaultTag]] pckmnt.versions = Object.keys(pckmnt.versions).sort(semver.compareLoose) diff --git a/lib/es6/validate-engines.js b/lib/es6/validate-engines.js new file mode 100644 index 0000000000000..cf5315a25dce0 --- /dev/null +++ b/lib/es6/validate-engines.js @@ -0,0 +1,49 @@ +// This is separate to indicate that it should contain code we expect to work in +// all versions of node >= 6. This is a best effort to catch syntax errors to +// give users a good error message if they are using a node version that doesn't +// allow syntax we are using such as private properties, etc. This file is +// linted with ecmaVersion=6 so we don't use invalid syntax, which is set in the +// .eslintrc.local.json file + +const { engines: { node: engines }, version } = require('../../package.json') +const npm = `v${version}` + +module.exports = (process, getCli) => { + const node = process.version + + /* eslint-disable-next-line max-len */ + const unsupportedMessage = `npm ${npm} does not support Node.js ${node}. This version of npm supports the following node versions: \`${engines}\`. You can find the latest version at https://nodejs.org/.` + + /* eslint-disable-next-line max-len */ + const brokenMessage = `ERROR: npm ${npm} is known not to run on Node.js ${node}. This version of npm supports the following node versions: \`${engines}\`. You can find the latest version at https://nodejs.org/.` + + // coverage ignored because this is only hit in very unsupported node versions + // and it's a best effort attempt to show something nice in those cases + /* istanbul ignore next */ + const syntaxErrorHandler = (err) => { + if (err instanceof SyntaxError) { + // eslint-disable-next-line no-console + console.error(`${brokenMessage}\n\nERROR:`) + // eslint-disable-next-line no-console + console.error(err) + return process.exit(1) + } + throw err + } + + process.on('uncaughtException', syntaxErrorHandler) + process.on('unhandledRejection', syntaxErrorHandler) + + // require this only after setting up the error handlers + const cli = getCli() + return cli(process, { + node, + npm, + engines, + unsupportedMessage, + off: () => { + process.off('uncaughtException', syntaxErrorHandler) + process.off('unhandledRejection', syntaxErrorHandler) + }, + }) +} diff --git a/lib/npm.js b/lib/npm.js index eebb453dbbacb..14706629e79c2 100644 --- a/lib/npm.js +++ b/lib/npm.js @@ -1,15 +1,12 @@ -const EventEmitter = require('events') const { resolve, dirname, join } = require('path') const Config = require('@npmcli/config') -const chalk = require('chalk') const which = require('which') const fs = require('fs/promises') -const abbrev = require('abbrev') // Patch the global fs module here at the app level require('graceful-fs').gracefulify(require('fs')) -const { definitions, flatten, shorthands } = require('./utils/config/index.js') +const { definitions, flatten, shorthands } = require('@npmcli/config/lib/definitions') const usage = require('./utils/npm-usage.js') const LogFile = require('./utils/log-file.js') const Timers = require('./utils/timers.js') @@ -18,13 +15,23 @@ const log = require('./utils/log-shim') const replaceInfo = require('./utils/replace-info.js') const updateNotifier = require('./utils/update-notifier.js') const pkg = require('../package.json') -const { commands, aliases } = require('./utils/cmd-list.js') +const { deref } = require('./utils/cmd-list.js') -class Npm extends EventEmitter { +class Npm { static get version () { return pkg.version } + static cmd (c) { + const command = deref(c) + if (!command) { + throw Object.assign(new Error(`Unknown command ${c}`), { + code: 'EUNKNOWNCOMMAND', + }) + } + return require(`./commands/${command}.js`) + } + updateNotification = null loadErr = null argv = [] @@ -32,15 +39,15 @@ class Npm extends EventEmitter { #command = null #runId = new Date().toISOString().replace(/[.:]/g, '_') #loadPromise = null - #tmpFolder = null #title = 'npm' #argvClean = [] - #chalk = null - #logChalk = null - #noColorChalk = new chalk.Instance({ level: 0 }) #npmRoot = null #warnedNonDashArg = false + #chalk = null + #logChalk = null + #noColorChalk = null + #outputBuffer = [] #logFile = new LogFile() #display = new Display() @@ -66,7 +73,6 @@ class Npm extends EventEmitter { // prefix to `npmRoot` since that is the first dir it would encounter when // doing implicit detection constructor ({ npmRoot = dirname(__dirname), argv = [], excludeNpmCwd = false } = {}) { - super() this.#npmRoot = npmRoot this.config = new Config({ npmPath: this.#npmRoot, @@ -82,53 +88,9 @@ class Npm extends EventEmitter { return this.constructor.version } - deref (c) { - if (!c) { - return - } - - // Translate camelCase to snake-case (i.e. installTest to install-test) - if (c.match(/[A-Z]/)) { - c = c.replace(/([A-Z])/g, m => '-' + m.toLowerCase()) - } - - // if they asked for something exactly we are done - if (commands.includes(c)) { - return c - } - - // if they asked for a direct alias - if (aliases[c]) { - return aliases[c] - } - - const abbrevs = abbrev(commands.concat(Object.keys(aliases))) - - // first deref the abbrev, if there is one - // then resolve any aliases - // so `npm install-cl` will resolve to `install-clean` then to `ci` - let a = abbrevs[c] - while (aliases[a]) { - a = aliases[a] - } - return a - } - - // Get an instantiated npm command - // npm.command is already taken as the currently running command, a refactor - // would be needed to change this - async cmd (cmd) { - await this.load() - - const cmdId = this.deref(cmd) - if (!cmdId) { - throw Object.assign(new Error(`Unknown command ${cmd}`), { - code: 'EUNKNOWNCOMMAND', - }) - } - - const Impl = require(`./commands/${cmdId}.js`) - const command = new Impl(this) + setCmd (cmd) { + const Command = Npm.cmd(cmd) + const command = new Command(this) // since 'test', 'start', 'stop', etc. commands re-enter this function // to call the run-script command, we need to only set it one time. @@ -141,8 +103,14 @@ class Npm extends EventEmitter { } // Call an npm command + // TODO: tests are currently the only time the second + // parameter of args is used. When called via `lib/cli.js` the config is + // loaded and this.argv is set to the remaining command line args. We should + // consider testing the CLI the same way it is used and not allow args to be + // passed in directly. async exec (cmd, args = this.argv) { - const command = await this.cmd(cmd) + const command = this.setCmd(cmd) + const timeEnd = this.time(`command:${cmd}`) // this is async but we dont await it, since its ok if it doesnt @@ -226,6 +194,20 @@ class Npm extends EventEmitter { await this.time('npm:load:configload', () => this.config.load()) + // get createSupportsColor from chalk directly if this lands + // https://github.com/chalk/chalk/pull/600 + const [{ Chalk }, { createSupportsColor }] = await Promise.all([ + import('chalk'), + import('supports-color'), + ]) + this.#noColorChalk = new Chalk({ level: 0 }) + // we get the chalk level based on a null stream meaning chalk will only use + // what it knows about the environment to get color support since we already + // determined in our definitions that we want to show colors. + const level = Math.max(createSupportsColor(null).level, 1) + this.#chalk = this.color ? new Chalk({ level }) : this.#noColorChalk + this.#logChalk = this.logColor ? new Chalk({ level }) : this.#noColorChalk + // mkdir this separately since the logs dir can be set to // a different location. if this fails, then we don't have // a cache dir, but we don't want to fail immediately since @@ -333,20 +315,10 @@ class Npm extends EventEmitter { } get chalk () { - if (!this.#chalk) { - this.#chalk = new chalk.Instance({ - level: this.color ? chalk.level : 0, - }) - } return this.#chalk } get logChalk () { - if (!this.#logChalk) { - this.#logChalk = new chalk.Instance({ - level: this.logColor ? chalk.stderr.level : 0, - }) - } return this.#logChalk } @@ -462,15 +434,6 @@ class Npm extends EventEmitter { return usage(this) } - // XXX add logging to see if we actually use this - get tmp () { - if (!this.#tmpFolder) { - const rand = require('crypto').randomBytes(4).toString('hex') - this.#tmpFolder = `npm-${process.pid}-${rand}` - } - return resolve(this.config.get('tmp'), this.#tmpFolder) - } - // output to stdout in a progress bar compatible way output (...msg) { log.clearProgress() diff --git a/lib/utils/cmd-list.js b/lib/utils/cmd-list.js index e5479139033d5..9bd252bc3facc 100644 --- a/lib/utils/cmd-list.js +++ b/lib/utils/cmd-list.js @@ -1,3 +1,5 @@ +const abbrev = require('abbrev') + // These correspond to filenames in lib/commands // Please keep this list sorted alphabetically const commands = [ @@ -136,7 +138,40 @@ const aliases = { 'add-user': 'adduser', } +const deref = (c) => { + if (!c) { + return + } + + // Translate camelCase to snake-case (i.e. installTest to install-test) + if (c.match(/[A-Z]/)) { + c = c.replace(/([A-Z])/g, m => '-' + m.toLowerCase()) + } + + // if they asked for something exactly we are done + if (commands.includes(c)) { + return c + } + + // if they asked for a direct alias + if (aliases[c]) { + return aliases[c] + } + + const abbrevs = abbrev(commands.concat(Object.keys(aliases))) + + // first deref the abbrev, if there is one + // then resolve any aliases + // so `npm install-cl` will resolve to `install-clean` then to `ci` + let a = abbrevs[c] + while (aliases[a]) { + a = aliases[a] + } + return a +} + module.exports = { aliases, commands, + deref, } diff --git a/lib/utils/did-you-mean.js b/lib/utils/did-you-mean.js index 10b33d5f83a08..ff3c812b46c3c 100644 --- a/lib/utils/did-you-mean.js +++ b/lib/utils/did-you-mean.js @@ -1,19 +1,19 @@ +const Npm = require('../npm') const { distance } = require('fastest-levenshtein') -const readJson = require('read-package-json-fast') +const pkgJson = require('@npmcli/package-json') const { commands } = require('./cmd-list.js') -const didYouMean = async (npm, path, scmd) => { - // const cmd = await npm.cmd(str) +const didYouMean = async (path, scmd) => { const close = commands.filter(cmd => distance(scmd, cmd) < scmd.length * 0.4 && scmd !== cmd) let best = [] for (const str of close) { - const cmd = await npm.cmd(str) + const cmd = Npm.cmd(str) best.push(` npm ${str} # ${cmd.description}`) } // We would already be suggesting this in `npm x` so omit them here const runScripts = ['stop', 'start', 'test', 'restart'] try { - const { bin, scripts } = await readJson(`${path}/package.json`) + const { content: { scripts, bin } } = await pkgJson.normalize(path) best = best.concat( Object.keys(scripts || {}) .filter(cmd => distance(scmd, cmd) < scmd.length * 0.4 && !runScripts.includes(cmd)) diff --git a/lib/utils/exit-handler.js b/lib/utils/exit-handler.js index b5d6cd030fb5c..25cecd170a584 100644 --- a/lib/utils/exit-handler.js +++ b/lib/utils/exit-handler.js @@ -131,8 +131,8 @@ const exitHandler = err => { log.level = level } - let exitCode - let noLogMessage + let exitCode = process.exitCode || 0 + let noLogMessage = exitCode !== 0 let jsonError if (err) { diff --git a/lib/utils/explain-eresolve.js b/lib/utils/explain-eresolve.js index ba46f3480adb3..f3c6ae23a479d 100644 --- a/lib/utils/explain-eresolve.js +++ b/lib/utils/explain-eresolve.js @@ -44,7 +44,7 @@ const explain = (expl, chalk, depth) => { } // generate a full verbose report and tell the user how to fix it -const report = (expl, chalk, noColor) => { +const report = (expl, chalk, noColorChalk) => { const flags = [ expl.strictPeerDeps ? '--no-strict-peer-deps' : '', '--force', @@ -61,7 +61,7 @@ to accept an incorrect (and potentially broken) dependency resolution.` return { explanation: `${explain(expl, chalk, 4)}\n\n${fix}`, - file: `# npm resolution error report\n\n${explain(expl, noColor, Infinity)}\n\n${fix}`, + file: `# npm resolution error report\n\n${explain(expl, noColorChalk, Infinity)}\n\n${fix}`, } } diff --git a/lib/utils/format-search-stream.js b/lib/utils/format-search-stream.js index 21929cce7d056..762dea90859d1 100644 --- a/lib/utils/format-search-stream.js +++ b/lib/utils/format-search-stream.js @@ -1,5 +1,6 @@ const { Minipass } = require('minipass') const columnify = require('columnify') +const ansiTrim = require('../utils/ansi-trim.js') // This module consumes package data in the following format: // @@ -141,13 +142,13 @@ function highlightSearchTerms (str, terms) { function normalizePackage (data, opts) { return { - name: data.name, - description: data.description, - author: data.maintainers.map((m) => `=${m.username}`).join(' '), + name: ansiTrim(data.name), + description: ansiTrim(data.description), + author: data.maintainers.map((m) => `=${ansiTrim(m.username)}`).join(' '), keywords: Array.isArray(data.keywords) - ? data.keywords.join(' ') + ? data.keywords.map(ansiTrim).join(' ') : typeof data.keywords === 'string' - ? data.keywords.replace(/[,\s]+/, ' ') + ? ansiTrim(data.keywords.replace(/[,\s]+/, ' ')) : '', version: data.version, date: (data.date && diff --git a/lib/utils/npm-usage.js b/lib/utils/npm-usage.js index b04ad33f9dd79..1bd790ca601bc 100644 --- a/lib/utils/npm-usage.js +++ b/lib/utils/npm-usage.js @@ -8,9 +8,9 @@ const INDENT = 4 const indent = (repeat = INDENT) => ' '.repeat(repeat) const indentNewline = (repeat) => `\n${indent(repeat)}` -module.exports = async (npm) => { +module.exports = (npm) => { const browser = npm.config.get('viewer') === 'browser' ? ' (in a browser)' : '' - const allCommands = npm.config.get('long') ? await cmdUsages(npm) : cmdNames() + const allCommands = npm.config.get('long') ? cmdUsages(npm.constructor) : cmdNames() return `npm @@ -57,13 +57,12 @@ const cmdNames = () => { return indentNewline() + out.join(indentNewline()).slice(2) } -const cmdUsages = async (npm) => { +const cmdUsages = (Npm) => { // return a string of : let maxLen = 0 const set = [] for (const c of commands) { - const { usage } = await npm.cmd(c) - set.push([c, usage.split('\n')]) + set.push([c, Npm.cmd(c).describeUsage.split('\n')]) maxLen = Math.max(maxLen, c.length) } diff --git a/lib/utils/reify-output.js b/lib/utils/reify-output.js index 5ac7fa4b01896..22036dc8110cf 100644 --- a/lib/utils/reify-output.js +++ b/lib/utils/reify-output.js @@ -116,6 +116,7 @@ const getAuditReport = (npm, report) => { reporter, ...npm.flatOptions, auditLevel, + chalk: npm.chalk, }) if (npm.command === 'audit') { process.exitCode = process.exitCode || res.exitCode diff --git a/lib/workspaces/get-workspaces.js b/lib/workspaces/get-workspaces.js index 7065533596000..59efb0e9f01be 100644 --- a/lib/workspaces/get-workspaces.js +++ b/lib/workspaces/get-workspaces.js @@ -1,7 +1,7 @@ const { resolve, relative } = require('path') const mapWorkspaces = require('@npmcli/map-workspaces') const { minimatch } = require('minimatch') -const rpj = require('read-package-json-fast') +const pkgJson = require('@npmcli/package-json') // minimatch wants forward slashes only for glob patterns const globify = pattern => pattern.split('\\').join('/') @@ -9,8 +9,8 @@ const globify = pattern => pattern.split('\\').join('/') // Returns an Map of paths to workspaces indexed by workspace name // { foo => '/path/to/foo' } const getWorkspaces = async (filters, { path, includeWorkspaceRoot, relativeFrom }) => { - // TODO we need a better error to be bubbled up here if this rpj call fails - const pkg = await rpj(resolve(path, 'package.json')) + // TODO we need a better error to be bubbled up here if this call fails + const { content: pkg } = await pkgJson.normalize(path) const workspaces = await mapWorkspaces({ cwd: path, pkg }) let res = new Map() if (includeWorkspaceRoot) { diff --git a/mock-globals/.eslintrc.js b/mock-globals/.eslintrc.js new file mode 100644 index 0000000000000..5db9f815536f1 --- /dev/null +++ b/mock-globals/.eslintrc.js @@ -0,0 +1,17 @@ +/* This file is automatically added by @npmcli/template-oss. Do not edit. */ + +'use strict' + +const { readdirSync: readdir } = require('fs') + +const localConfigs = readdir(__dirname) + .filter((file) => file.startsWith('.eslintrc.local.')) + .map((file) => `./${file}`) + +module.exports = { + root: true, + extends: [ + '@npmcli', + ...localConfigs, + ], +} diff --git a/mock-globals/.gitignore b/mock-globals/.gitignore new file mode 100644 index 0000000000000..79af2bfcaa4d8 --- /dev/null +++ b/mock-globals/.gitignore @@ -0,0 +1,21 @@ +# This file is automatically added by @npmcli/template-oss. Do not edit. + +# ignore everything in the root +/* + +# keep these +!**/.gitignore +!/.eslintrc.js +!/.eslintrc.local.* +!/.gitignore +!/bin/ +!/CHANGELOG* +!/docs/ +!/lib/ +!/LICENSE* +!/map.js +!/package.json +!/README* +!/scripts/ +!/tap-snapshots/ +!/test/ diff --git a/test/fixtures/mock-globals.js b/mock-globals/lib/index.js similarity index 100% rename from test/fixtures/mock-globals.js rename to mock-globals/lib/index.js diff --git a/mock-globals/package.json b/mock-globals/package.json new file mode 100644 index 0000000000000..b67429f43c15b --- /dev/null +++ b/mock-globals/package.json @@ -0,0 +1,54 @@ +{ + "name": "@npmcli/mock-globals", + "version": "1.0.0", + "description": "", + "main": "lib/index.js", + "private": true, + "scripts": { + "test": "tap", + "lint": "eslint \"**/*.js\"", + "postlint": "template-oss-check", + "template-oss-apply": "template-oss-apply --force", + "lintfix": "node .. run lint -- --fix", + "snap": "tap", + "posttest": "node .. run lint" + }, + "repository": { + "type": "git", + "url": "https://github.com/npm/cli.git", + "directory": "mock-globals" + }, + "keywords": [], + "author": "GitHub Inc.", + "license": "ISC", + "bugs": { + "url": "https://github.com/npm/cli/issues" + }, + "homepage": "https://github.com/npm/cli#readme", + "files": [ + "bin/", + "lib/" + ], + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "templateOSS": { + "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", + "version": "4.14.1" + }, + "tap": { + "branches": 89, + "functions": 97, + "lines": 97, + "statements": 97, + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] + }, + "devDependencies": { + "@npmcli/eslint-config": "^4.0.1", + "@npmcli/template-oss": "4.14.1", + "tap": "^16.3.2" + } +} diff --git a/test/lib/fixtures/mock-globals.js b/mock-globals/test/index.js similarity index 99% rename from test/lib/fixtures/mock-globals.js rename to mock-globals/test/index.js index 55418dd8e199d..5480801196301 100644 --- a/test/lib/fixtures/mock-globals.js +++ b/mock-globals/test/index.js @@ -1,5 +1,5 @@ const t = require('tap') -const mockGlobals = require('../../fixtures/mock-globals') +const mockGlobals = require('..') /* eslint-disable no-console */ const originals = { diff --git a/mock-registry/lib/index.js b/mock-registry/lib/index.js index 176c5635fa1d1..91f1de5b52e0d 100644 --- a/mock-registry/lib/index.js +++ b/mock-registry/lib/index.js @@ -2,6 +2,7 @@ const pacote = require('pacote') const Arborist = require('@npmcli/arborist') const npa = require('npm-package-arg') const Nock = require('nock') +const stringify = require('json-stringify-safe') class MockRegistry { #tap @@ -30,16 +31,16 @@ class MockRegistry { static tnock (t, host, opts, { debug = false, strict = false } = {}) { const noMatch = (req) => { + if (debug) { + console.error('NO MATCH', t.name, req.options ? req.options : req.path) + } if (strict) { // There are network requests that get caught regardless of error code. // Turning on strict mode requires that those requests get explicitly // mocked with a 404, 500, etc. // XXX: this is opt-in currently because it breaks some existing CLI // tests. We should work towards making this the default for all tests. - t.fail(`Unmatched request: ${JSON.stringify(req, null, 2)}`) - } - if (debug) { - console.error('NO MATCH', t.name, req.options ? req.options : req.path) + t.fail(`Unmatched request: ${stringify(req, null, 2)}`) } } @@ -143,10 +144,10 @@ class MockRegistry { ).reply(200) } - getVisibility ({ spec, visibility }) { + getVisibility ({ spec, visibility, responseCode = 200 }) { this.nock = this.nock.get( this.fullPath(`/-/package/${npa(spec).escapedName}/visibility`)) - .reply(200, visibility) + .reply(responseCode, visibility) } setPermissions ({ spec, team, permissions }) { @@ -337,9 +338,9 @@ class MockRegistry { } nock = nock.reply(200, manifest) if (tarballs) { - for (const version in tarballs) { + for (const [version, tarball] of Object.entries(tarballs)) { const m = manifest.versions[version] - nock = await this.tarball({ manifest: m, tarball: tarballs[version] }) + nock = await this.tarball({ manifest: m, tarball }) } } this.nock = nock diff --git a/mock-registry/package.json b/mock-registry/package.json index c85877288d3ef..6ab00a246705a 100644 --- a/mock-registry/package.json +++ b/mock-registry/package.json @@ -47,6 +47,7 @@ "@npmcli/arborist": "^6.1.1", "@npmcli/eslint-config": "^4.0.1", "@npmcli/template-oss": "4.14.1", + "json-stringify-safe": "^5.0.1", "nock": "^13.3.0", "npm-package-arg": "^10.1.0", "pacote": "^15.0.8", diff --git a/node_modules/.gitignore b/node_modules/.gitignore index ef85a22014caa..a32136b521357 100644 --- a/node_modules/.gitignore +++ b/node_modules/.gitignore @@ -6,9 +6,6 @@ !/@colors/ /@colors/* !/@colors/colors -!/@gar/ -/@gar/* -!/@gar/promisify !/@isaacs/ /@isaacs/* !/@isaacs/cliui @@ -29,7 +26,6 @@ !/@npmcli/installed-package-contents !/@npmcli/map-workspaces !/@npmcli/metavuln-calculator -!/@npmcli/move-file !/@npmcli/name-from-folder !/@npmcli/node-gyp !/@npmcli/package-json @@ -42,6 +38,7 @@ !/@sigstore/ /@sigstore/* !/@sigstore/protobuf-specs +!/@sigstore/tuf !/@tootallnate/ /@tootallnate/* !/@tootallnate/once @@ -103,6 +100,7 @@ !/err-code !/event-target-shim !/events +!/exponential-backoff !/fastest-levenshtein !/foreground-child !/fs-minipass @@ -111,7 +109,6 @@ !/gauge !/glob !/graceful-fs -!/has-flag !/has-unicode !/has !/hosted-git-info @@ -124,7 +121,6 @@ !/ignore-walk !/imurmurhash !/indent-string -!/infer-owner !/inflight !/inherits !/ini @@ -189,32 +185,16 @@ !/node-gyp !/node-gyp/node_modules/ /node-gyp/node_modules/* -!/node-gyp/node_modules/@npmcli/ -/node-gyp/node_modules/@npmcli/* -!/node-gyp/node_modules/@npmcli/fs !/node-gyp/node_modules/abbrev !/node-gyp/node_modules/are-we-there-yet !/node-gyp/node_modules/brace-expansion -!/node-gyp/node_modules/cacache -!/node-gyp/node_modules/cacache/node_modules/ -/node-gyp/node_modules/cacache/node_modules/* -!/node-gyp/node_modules/cacache/node_modules/brace-expansion -!/node-gyp/node_modules/cacache/node_modules/glob -!/node-gyp/node_modules/cacache/node_modules/minimatch -!/node-gyp/node_modules/fs-minipass !/node-gyp/node_modules/gauge !/node-gyp/node_modules/glob -!/node-gyp/node_modules/make-fetch-happen !/node-gyp/node_modules/minimatch -!/node-gyp/node_modules/minipass-fetch -!/node-gyp/node_modules/minipass !/node-gyp/node_modules/nopt !/node-gyp/node_modules/npmlog !/node-gyp/node_modules/readable-stream !/node-gyp/node_modules/signal-exit -!/node-gyp/node_modules/ssri -!/node-gyp/node_modules/unique-filename -!/node-gyp/node_modules/unique-slug !/node-gyp/node_modules/which !/nopt !/normalize-package-data diff --git a/node_modules/@gar/promisify/LICENSE.md b/node_modules/@gar/promisify/LICENSE.md deleted file mode 100644 index 64f773240bed1..0000000000000 --- a/node_modules/@gar/promisify/LICENSE.md +++ /dev/null @@ -1,10 +0,0 @@ -The MIT License (MIT) - -Copyright © 2020-2022 Michael Garvin - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/node_modules/@gar/promisify/index.js b/node_modules/@gar/promisify/index.js deleted file mode 100644 index d0be95f6fec61..0000000000000 --- a/node_modules/@gar/promisify/index.js +++ /dev/null @@ -1,36 +0,0 @@ -'use strict' - -const { promisify } = require('util') - -const handler = { - get: function (target, prop, receiver) { - if (typeof target[prop] !== 'function') { - return target[prop] - } - if (target[prop][promisify.custom]) { - return function () { - return Reflect.get(target, prop, receiver)[promisify.custom].apply(target, arguments) - } - } - return function () { - return new Promise((resolve, reject) => { - Reflect.get(target, prop, receiver).apply(target, [...arguments, function (err, result) { - if (err) { - return reject(err) - } - resolve(result) - }]) - }) - } - } -} - -module.exports = function (thingToPromisify) { - if (typeof thingToPromisify === 'function') { - return promisify(thingToPromisify) - } - if (typeof thingToPromisify === 'object') { - return new Proxy(thingToPromisify, handler) - } - throw new TypeError('Can only promisify functions or objects') -} diff --git a/node_modules/@gar/promisify/package.json b/node_modules/@gar/promisify/package.json deleted file mode 100644 index d0ce69b2f7c0e..0000000000000 --- a/node_modules/@gar/promisify/package.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "@gar/promisify", - "version": "1.1.3", - "description": "Promisify an entire class or object", - "main": "index.js", - "repository": { - "type": "git", - "url": "https://github.com/wraithgar/gar-promisify.git" - }, - "scripts": { - "lint": "standard", - "lint:fix": "standard --fix", - "test": "lab -a @hapi/code -t 100", - "posttest": "npm run lint" - }, - "files": [ - "index.js" - ], - "keywords": [ - "promisify", - "all", - "class", - "object" - ], - "author": "Gar ", - "license": "MIT", - "devDependencies": { - "@hapi/code": "^8.0.1", - "@hapi/lab": "^24.1.0", - "standard": "^16.0.3" - } -} diff --git a/node_modules/@isaacs/cliui/node_modules/strip-ansi/index.js b/node_modules/@isaacs/cliui/node_modules/strip-ansi/index.js index ef3c095f5fd42..ba19750e64e06 100644 --- a/node_modules/@isaacs/cliui/node_modules/strip-ansi/index.js +++ b/node_modules/@isaacs/cliui/node_modules/strip-ansi/index.js @@ -1,9 +1,14 @@ import ansiRegex from 'ansi-regex'; +const regex = ansiRegex(); + export default function stripAnsi(string) { if (typeof string !== 'string') { throw new TypeError(`Expected a \`string\`, got \`${typeof string}\``); } - return string.replace(ansiRegex(), ''); + // Even though the regex is global, we don't need to reset the `.lastIndex` + // because unlike `.exec()` and `.test()`, `.replace()` does it automatically + // and doing it manually has a performance penalty. + return string.replace(regex, ''); } diff --git a/node_modules/@isaacs/cliui/node_modules/strip-ansi/package.json b/node_modules/@isaacs/cliui/node_modules/strip-ansi/package.json index 0de0586f7eef1..e1f455c325b00 100644 --- a/node_modules/@isaacs/cliui/node_modules/strip-ansi/package.json +++ b/node_modules/@isaacs/cliui/node_modules/strip-ansi/package.json @@ -1,6 +1,6 @@ { "name": "strip-ansi", - "version": "7.0.1", + "version": "7.1.0", "description": "Strip ANSI escape codes from a string", "license": "MIT", "repository": "chalk/strip-ansi", diff --git a/node_modules/@npmcli/git/lib/find.js b/node_modules/@npmcli/git/lib/find.js index d58f01dbcc16f..34bd310b88e5d 100644 --- a/node_modules/@npmcli/git/lib/find.js +++ b/node_modules/@npmcli/git/lib/find.js @@ -1,15 +1,15 @@ const is = require('./is.js') const { dirname } = require('path') -module.exports = async ({ cwd = process.cwd() } = {}) => { - if (await is({ cwd })) { - return cwd - } - while (cwd !== dirname(cwd)) { - cwd = dirname(cwd) +module.exports = async ({ cwd = process.cwd(), root } = {}) => { + while (true) { if (await is({ cwd })) { return cwd } + const next = dirname(cwd) + if (cwd === root || cwd === next) { + return null + } + cwd = next } - return null } diff --git a/node_modules/@npmcli/git/package.json b/node_modules/@npmcli/git/package.json index 41c78dddfa3cc..eeba1c0415788 100644 --- a/node_modules/@npmcli/git/package.json +++ b/node_modules/@npmcli/git/package.json @@ -1,6 +1,6 @@ { "name": "@npmcli/git", - "version": "4.0.4", + "version": "4.1.0", "main": "lib/index.js", "files": [ "bin/", @@ -23,8 +23,7 @@ "template-oss-apply": "template-oss-apply --force" }, "tap": { - "check-coverage": true, - "coverage-map": "map.js", + "timeout": 600, "nyc-arg": [ "--exclude", "tap-snapshots/**" @@ -32,7 +31,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", - "@npmcli/template-oss": "4.12.0", + "@npmcli/template-oss": "4.15.1", "npm-package-arg": "^10.0.0", "slash": "^3.0.0", "tap": "^16.0.1" @@ -52,7 +51,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "windowsCI": false, - "version": "4.12.0" + "version": "4.15.1", + "publish": true } } diff --git a/node_modules/@npmcli/move-file/LICENSE.md b/node_modules/@npmcli/move-file/LICENSE.md deleted file mode 100644 index 072bf20840acd..0000000000000 --- a/node_modules/@npmcli/move-file/LICENSE.md +++ /dev/null @@ -1,22 +0,0 @@ -MIT License - -Copyright (c) Sindre Sorhus (https://sindresorhus.com) -Copyright (c) npm, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/node_modules/@npmcli/move-file/lib/index.js b/node_modules/@npmcli/move-file/lib/index.js deleted file mode 100644 index 5789bb127e096..0000000000000 --- a/node_modules/@npmcli/move-file/lib/index.js +++ /dev/null @@ -1,185 +0,0 @@ -const { dirname, join, resolve, relative, isAbsolute } = require('path') -const rimraf_ = require('rimraf') -const { promisify } = require('util') -const { - access: access_, - accessSync, - copyFile: copyFile_, - copyFileSync, - readdir: readdir_, - readdirSync, - rename: rename_, - renameSync, - stat: stat_, - statSync, - lstat: lstat_, - lstatSync, - symlink: symlink_, - symlinkSync, - readlink: readlink_, - readlinkSync, -} = require('fs') - -const access = promisify(access_) -const copyFile = promisify(copyFile_) -const readdir = promisify(readdir_) -const rename = promisify(rename_) -const stat = promisify(stat_) -const lstat = promisify(lstat_) -const symlink = promisify(symlink_) -const readlink = promisify(readlink_) -const rimraf = promisify(rimraf_) -const rimrafSync = rimraf_.sync - -const mkdirp = require('mkdirp') - -const pathExists = async path => { - try { - await access(path) - return true - } catch (er) { - return er.code !== 'ENOENT' - } -} - -const pathExistsSync = path => { - try { - accessSync(path) - return true - } catch (er) { - return er.code !== 'ENOENT' - } -} - -const moveFile = async (source, destination, options = {}, root = true, symlinks = []) => { - if (!source || !destination) { - throw new TypeError('`source` and `destination` file required') - } - - options = { - overwrite: true, - ...options, - } - - if (!options.overwrite && await pathExists(destination)) { - throw new Error(`The destination file exists: ${destination}`) - } - - await mkdirp(dirname(destination)) - - try { - await rename(source, destination) - } catch (error) { - if (error.code === 'EXDEV' || error.code === 'EPERM') { - const sourceStat = await lstat(source) - if (sourceStat.isDirectory()) { - const files = await readdir(source) - await Promise.all(files.map((file) => - moveFile(join(source, file), join(destination, file), options, false, symlinks) - )) - } else if (sourceStat.isSymbolicLink()) { - symlinks.push({ source, destination }) - } else { - await copyFile(source, destination) - } - } else { - throw error - } - } - - if (root) { - await Promise.all(symlinks.map(async ({ source: symSource, destination: symDestination }) => { - let target = await readlink(symSource) - // junction symlinks in windows will be absolute paths, so we need to - // make sure they point to the symlink destination - if (isAbsolute(target)) { - target = resolve(symDestination, relative(symSource, target)) - } - // try to determine what the actual file is so we can create the correct - // type of symlink in windows - let targetStat = 'file' - try { - targetStat = await stat(resolve(dirname(symSource), target)) - if (targetStat.isDirectory()) { - targetStat = 'junction' - } - } catch { - // targetStat remains 'file' - } - await symlink( - target, - symDestination, - targetStat - ) - })) - await rimraf(source) - } -} - -const moveFileSync = (source, destination, options = {}, root = true, symlinks = []) => { - if (!source || !destination) { - throw new TypeError('`source` and `destination` file required') - } - - options = { - overwrite: true, - ...options, - } - - if (!options.overwrite && pathExistsSync(destination)) { - throw new Error(`The destination file exists: ${destination}`) - } - - mkdirp.sync(dirname(destination)) - - try { - renameSync(source, destination) - } catch (error) { - if (error.code === 'EXDEV' || error.code === 'EPERM') { - const sourceStat = lstatSync(source) - if (sourceStat.isDirectory()) { - const files = readdirSync(source) - for (const file of files) { - moveFileSync(join(source, file), join(destination, file), options, false, symlinks) - } - } else if (sourceStat.isSymbolicLink()) { - symlinks.push({ source, destination }) - } else { - copyFileSync(source, destination) - } - } else { - throw error - } - } - - if (root) { - for (const { source: symSource, destination: symDestination } of symlinks) { - let target = readlinkSync(symSource) - // junction symlinks in windows will be absolute paths, so we need to - // make sure they point to the symlink destination - if (isAbsolute(target)) { - target = resolve(symDestination, relative(symSource, target)) - } - // try to determine what the actual file is so we can create the correct - // type of symlink in windows - let targetStat = 'file' - try { - targetStat = statSync(resolve(dirname(symSource), target)) - if (targetStat.isDirectory()) { - targetStat = 'junction' - } - } catch { - // targetStat remains 'file' - } - symlinkSync( - target, - symDestination, - targetStat - ) - } - rimrafSync(source) - } -} - -module.exports = moveFile -module.exports.sync = moveFileSync diff --git a/node_modules/@npmcli/move-file/package.json b/node_modules/@npmcli/move-file/package.json deleted file mode 100644 index 58793b93a9ca0..0000000000000 --- a/node_modules/@npmcli/move-file/package.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "name": "@npmcli/move-file", - "version": "2.0.1", - "files": [ - "bin/", - "lib/" - ], - "main": "lib/index.js", - "description": "move a file (fork of move-file)", - "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - }, - "devDependencies": { - "@npmcli/eslint-config": "^3.0.1", - "@npmcli/template-oss": "3.5.0", - "tap": "^16.0.1" - }, - "scripts": { - "test": "tap", - "snap": "tap", - "preversion": "npm test", - "postversion": "npm publish", - "prepublishOnly": "git push origin --follow-tags", - "lint": "eslint \"**/*.js\"", - "postlint": "template-oss-check", - "template-oss-apply": "template-oss-apply --force", - "lintfix": "npm run lint -- --fix", - "posttest": "npm run lint" - }, - "repository": { - "type": "git", - "url": "https://github.com/npm/move-file.git" - }, - "tap": { - "check-coverage": true - }, - "license": "MIT", - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - }, - "author": "GitHub Inc.", - "templateOSS": { - "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "3.5.0" - } -} diff --git a/node_modules/@npmcli/package-json/lib/index.js b/node_modules/@npmcli/package-json/lib/index.js index e98308f3d3b84..756837cdde58a 100644 --- a/node_modules/@npmcli/package-json/lib/index.js +++ b/node_modules/@npmcli/package-json/lib/index.js @@ -1,18 +1,12 @@ -const fs = require('fs') -const promisify = require('util').promisify -const readFile = promisify(fs.readFile) -const writeFile = promisify(fs.writeFile) +const { readFile, writeFile } = require('fs/promises') const { resolve } = require('path') const updateDeps = require('./update-dependencies.js') const updateScripts = require('./update-scripts.js') const updateWorkspaces = require('./update-workspaces.js') +const normalize = require('./normalize.js') const parseJSON = require('json-parse-even-better-errors') -const _filename = Symbol('filename') -const _manifest = Symbol('manifest') -const _readFileContent = Symbol('readFileContent') - // a list of handy specialized helper functions that take // care of special cases that are handled by the npm cli const knownSteps = new Set([ @@ -29,42 +23,112 @@ const knownKeys = new Set([ ]) class PackageJson { + static normalizeSteps = Object.freeze([ + '_id', + '_attributes', + 'bundledDependencies', + 'bundleDependencies', + 'optionalDedupe', + 'scripts', + 'funding', + 'bin', + ]) + + static prepareSteps = Object.freeze([ + '_attributes', + 'bundledDependencies', + 'bundleDependencies', + 'bundleDependenciesDeleteFalse', + 'gypfile', + 'serverjs', + 'scriptpath', + 'authors', + 'readme', + 'mans', + 'binDir', + 'gitHead', + 'fillTypes', + 'normalizeData', + 'binRefs', + ]) + + // default behavior, just loads and parses static async load (path) { return await new PackageJson(path).load() } + // read-package-json compatible behavior + static async prepare (path, opts) { + return await new PackageJson(path).prepare(opts) + } + + // read-package-json-fast compatible behavior + static async normalize (path, opts) { + return await new PackageJson(path).normalize(opts) + } + + #filename + #path + #manifest = {} + #readFileContent = '' + #fromIndex = false + constructor (path) { - this[_filename] = resolve(path, 'package.json') - this[_manifest] = {} - this[_readFileContent] = '' + this.#path = path + this.#filename = resolve(path, 'package.json') } - async load () { + async load (parseIndex) { + let parseErr try { - this[_readFileContent] = - await readFile(this[_filename], 'utf8') + this.#readFileContent = + await readFile(this.#filename, 'utf8') } catch (err) { - throw new Error('package.json not found') + err.message = `Could not read package.json: ${err}` + if (!parseIndex) { + throw err + } + parseErr = err + } + + if (parseErr) { + const indexFile = resolve(this.#path, 'index.js') + let indexFileContent + try { + indexFileContent = await readFile(indexFile, 'utf8') + } catch (err) { + throw parseErr + } + try { + this.#manifest = fromComment(indexFileContent) + } catch (err) { + throw parseErr + } + this.#fromIndex = true + return this } try { - this[_manifest] = - parseJSON(this[_readFileContent]) + this.#manifest = parseJSON(this.#readFileContent) } catch (err) { - throw new Error(`Invalid package.json: ${err}`) + err.message = `Invalid package.json: ${err}` + throw err } - return this } get content () { - return this[_manifest] + return this.#manifest + } + + get path () { + return this.#path } update (content) { // validates both current manifest and content param const invalidContent = - typeof this[_manifest] !== 'object' + typeof this.#manifest !== 'object' || typeof content !== 'object' if (invalidContent) { throw Object.assign( @@ -74,13 +138,13 @@ class PackageJson { } for (const step of knownSteps) { - this[_manifest] = step({ content, originalContent: this[_manifest] }) + this.#manifest = step({ content, originalContent: this.#manifest }) } // unknown properties will just be overwitten for (const [key, value] of Object.entries(content)) { if (!knownKeys.has(key)) { - this[_manifest][key] = value + this.#manifest[key] = value } } @@ -88,22 +152,62 @@ class PackageJson { } async save () { + if (this.#fromIndex) { + throw new Error('No package.json to save to') + } const { [Symbol.for('indent')]: indent, [Symbol.for('newline')]: newline, - } = this[_manifest] + } = this.#manifest const format = indent === undefined ? ' ' : indent const eol = newline === undefined ? '\n' : newline const fileContent = `${ - JSON.stringify(this[_manifest], null, format) + JSON.stringify(this.#manifest, null, format) }\n` .replace(/\n/g, eol) - if (fileContent.trim() !== this[_readFileContent].trim()) { - return await writeFile(this[_filename], fileContent) + if (fileContent.trim() !== this.#readFileContent.trim()) { + return await writeFile(this.#filename, fileContent) } } + + async normalize (opts = {}) { + if (!opts.steps) { + opts.steps = this.constructor.normalizeSteps + } + await this.load() + await normalize(this, opts) + return this + } + + async prepare (opts = {}) { + if (!opts.steps) { + opts.steps = this.constructor.prepareSteps + } + await this.load(true) + await normalize(this, opts) + return this + } +} + +// /**package { "name": "foo", "version": "1.2.3", ... } **/ +function fromComment (data) { + data = data.split(/^\/\*\*package(?:\s|$)/m) + + if (data.length < 2) { + throw new Error('File has no package in comments') + } + data = data[1] + data = data.split(/\*\*\/$/m) + + if (data.length < 2) { + throw new Error('File has no package in comments') + } + data = data[0] + data = data.replace(/^\s*\*/mg, '') + + return parseJSON(data) } module.exports = PackageJson diff --git a/node_modules/@npmcli/package-json/lib/normalize.js b/node_modules/@npmcli/package-json/lib/normalize.js new file mode 100644 index 0000000000000..9594ef3d7ff4f --- /dev/null +++ b/node_modules/@npmcli/package-json/lib/normalize.js @@ -0,0 +1,292 @@ +const fs = require('fs/promises') +const { glob } = require('glob') +const normalizePackageBin = require('npm-normalize-package-bin') +const normalizePackageData = require('normalize-package-data') +const path = require('path') +const log = require('proc-log') +const git = require('@npmcli/git') + +const normalize = async (pkg, { strict, steps, root }) => { + const data = pkg.content + const scripts = data.scripts || {} + const pkgId = `${data.name ?? ''}@${data.version ?? ''}` + + // remove attributes that start with "_" + if (steps.includes('_attributes')) { + for (const key in data) { + if (key.startsWith('_')) { + delete pkg.content[key] + } + } + } + + // build the "_id" attribute + if (steps.includes('_id')) { + if (data.name && data.version) { + data._id = pkgId + } + } + + // fix bundledDependencies typo + if (steps.includes('bundledDependencies')) { + if (data.bundleDependencies === undefined && data.bundledDependencies !== undefined) { + data.bundleDependencies = data.bundledDependencies + } + delete data.bundledDependencies + } + // expand "bundleDependencies: true or translate from object" + if (steps.includes('bundleDependencies')) { + const bd = data.bundleDependencies + if (bd === false && !steps.includes('bundleDependenciesDeleteFalse')) { + data.bundleDependencies = [] + } else if (bd === true) { + data.bundleDependencies = Object.keys(data.dependencies || {}) + } else if (bd && typeof bd === 'object') { + if (!Array.isArray(bd)) { + data.bundleDependencies = Object.keys(bd) + } + } else { + delete data.bundleDependencies + } + } + + // it was once common practice to list deps both in optionalDependencies and + // in dependencies, to support npm versions that did not know about + // optionalDependencies. This is no longer a relevant need, so duplicating + // the deps in two places is unnecessary and excessive. + if (steps.includes('optionalDedupe')) { + if (data.dependencies && + data.optionalDependencies && typeof data.optionalDependencies === 'object') { + for (const name in data.optionalDependencies) { + delete data.dependencies[name] + } + if (!Object.keys(data.dependencies).length) { + delete data.dependencies + } + } + } + + // add "install" attribute if any "*.gyp" files exist + if (steps.includes('gypfile')) { + if (!scripts.install && !scripts.preinstall && data.gypfile !== false) { + const files = await glob('*.gyp', { cwd: pkg.path }) + if (files.length) { + scripts.install = 'node-gyp rebuild' + data.scripts = scripts + data.gypfile = true + } + } + } + + // add "start" attribute if "server.js" exists + if (steps.includes('serverjs') && !scripts.start) { + try { + await fs.access(path.join(pkg.path, 'server.js')) + scripts.start = 'node server.js' + data.scripts = scripts + } catch { + // do nothing + } + } + + // strip "node_modules/.bin" from scripts entries + if (steps.includes('scripts') || steps.includes('scriptpath')) { + const spre = /^(\.[/\\])?node_modules[/\\].bin[\\/]/ + if (typeof data.scripts === 'object') { + for (const name in data.scripts) { + if (typeof data.scripts[name] !== 'string') { + delete data.scripts[name] + } else if (steps.includes('scriptpath')) { + data.scripts[name] = data.scripts[name].replace(spre, '') + } + } + } else { + delete data.scripts + } + } + + if (steps.includes('funding')) { + if (data.funding && typeof data.funding === 'string') { + data.funding = { url: data.funding } + } + } + + // populate "authors" attribute + if (steps.includes('authors') && !data.contributors) { + try { + const authorData = await fs.readFile(path.join(pkg.path, 'AUTHORS'), 'utf8') + const authors = authorData.split(/\r?\n/g) + .map(line => line.replace(/^\s*#.*$/, '').trim()) + .filter(line => line) + data.contributors = authors + } catch { + // do nothing + } + } + + // populate "readme" attribute + if (steps.includes('readme') && !data.readme) { + const mdre = /\.m?a?r?k?d?o?w?n?$/i + const files = await glob('{README,README.*}', { cwd: pkg.path, nocase: true, mark: true }) + let readmeFile + for (const file of files) { + // don't accept directories. + if (!file.endsWith(path.sep)) { + if (file.match(mdre)) { + readmeFile = file + break + } + if (file.endsWith('README')) { + readmeFile = file + } + } + } + if (readmeFile) { + const readmeData = await fs.readFile(path.join(pkg.path, readmeFile), 'utf8') + data.readme = readmeData + data.readmeFilename = readmeFile + } + } + + // expand directories.man + if (steps.includes('mans') && !data.man && data.directories?.man) { + const manDir = data.directories.man + const cwd = path.resolve(pkg.path, manDir) + const files = await glob('**/*.[0-9]', { cwd }) + data.man = files.map(man => + path.relative(pkg.path, path.join(cwd, man)).split(path.sep).join('/') + ) + } + + if (steps.includes('bin') || steps.includes('binDir') || steps.includes('binRefs')) { + normalizePackageBin(data) + } + + // expand "directories.bin" + if (steps.includes('binDir') && data.directories?.bin && !data.bin) { + const binsDir = path.resolve(pkg.path, path.join('.', path.join('/', data.directories.bin))) + const bins = await glob('**', { cwd: binsDir }) + data.bin = bins.reduce((acc, binFile) => { + if (binFile && !binFile.startsWith('.')) { + const binName = path.basename(binFile) + acc[binName] = path.join(data.directories.bin, binFile) + } + return acc + }, {}) + // *sigh* + normalizePackageBin(data) + } + + // populate "gitHead" attribute + if (steps.includes('gitHead') && !data.gitHead) { + const gitRoot = await git.find({ cwd: pkg.path, root }) + let head + if (gitRoot) { + try { + head = await fs.readFile(path.resolve(gitRoot, '.git/HEAD'), 'utf8') + } catch (err) { + // do nothing + } + } + let headData + if (head) { + if (head.startsWith('ref: ')) { + const headRef = head.replace(/^ref: /, '').trim() + const headFile = path.resolve(gitRoot, '.git', headRef) + try { + headData = await fs.readFile(headFile, 'utf8') + headData = headData.replace(/^ref: /, '').trim() + } catch (err) { + // do nothing + } + if (!headData) { + const packFile = path.resolve(gitRoot, '.git/packed-refs') + try { + let refs = await fs.readFile(packFile, 'utf8') + if (refs) { + refs = refs.split('\n') + for (let i = 0; i < refs.length; i++) { + const match = refs[i].match(/^([0-9a-f]{40}) (.+)$/) + if (match && match[2].trim() === headRef) { + headData = match[1] + break + } + } + } + } catch { + // do nothing + } + } + } else { + headData = head.trim() + } + } + if (headData) { + data.gitHead = headData + } + } + + // populate "types" attribute + if (steps.includes('fillTypes')) { + const index = data.main || 'index.js' + + if (typeof index !== 'string') { + throw new TypeError('The "main" attribute must be of type string.') + } + + // TODO exports is much more complicated than this in verbose format + // We need to support for instance + + // "exports": { + // ".": [ + // { + // "default": "./lib/npm.js" + // }, + // "./lib/npm.js" + // ], + // "./package.json": "./package.json" + // }, + // as well as conditional exports + + // if (data.exports && typeof data.exports === 'string') { + // index = data.exports + // } + + // if (data.exports && data.exports['.']) { + // index = data.exports['.'] + // if (typeof index !== 'string') { + // } + // } + const extless = path.join(path.dirname(index), path.basename(index, path.extname(index))) + const dts = `./${extless}.d.ts` + const hasDTSFields = 'types' in data || 'typings' in data + if (!hasDTSFields) { + try { + await fs.access(path.join(pkg.path, dts)) + data.types = dts.split(path.sep).join('/') + } catch { + // do nothing + } + } + } + + // "normalizeData" from read-package-json + if (steps.includes('normalizeData')) { + normalizePackageData(data, strict) + } + + // Warn if the bin references don't point to anything. This might be better + // in normalize-package-data if it had access to the file path. + if (steps.includes('binRefs') && data.bin instanceof Object) { + for (const key in data.bin) { + try { + await fs.access(path.resolve(pkg.path, data.bin[key])) + } catch { + log.warn('package-json', pkgId, `No bin file found at ${data.bin[key]}`) + // XXX: should a future breaking change delete bin entries that cannot be accessed? + } + } + } +} + +module.exports = normalize diff --git a/node_modules/@npmcli/package-json/package.json b/node_modules/@npmcli/package-json/package.json index faae7891a1e72..a4e2cbab4c0bd 100644 --- a/node_modules/@npmcli/package-json/package.json +++ b/node_modules/@npmcli/package-json/package.json @@ -1,6 +1,6 @@ { "name": "@npmcli/package-json", - "version": "3.0.0", + "version": "3.1.1", "description": "Programmatic API to update package.json", "main": "lib/index.js", "files": [ @@ -24,12 +24,19 @@ "author": "GitHub Inc.", "license": "ISC", "devDependencies": { - "@npmcli/eslint-config": "^3.0.1", - "@npmcli/template-oss": "4.5.1", + "@npmcli/eslint-config": "^4.0.0", + "@npmcli/template-oss": "4.15.1", + "read-package-json": "^6.0.4", + "read-package-json-fast": "^3.0.2", "tap": "^16.0.1" }, "dependencies": { - "json-parse-even-better-errors": "^3.0.0" + "@npmcli/git": "^4.1.0", + "glob": "^10.2.2", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^5.0.0", + "npm-normalize-package-bin": "^3.0.1", + "proc-log": "^3.0.0" }, "repository": { "type": "git", @@ -40,7 +47,8 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.5.1" + "version": "4.15.1", + "publish": "true" }, "tap": { "nyc-arg": [ diff --git a/node_modules/@npmcli/run-script/lib/run-script-pkg.js b/node_modules/@npmcli/run-script/lib/run-script-pkg.js index cbb0a0b3a5e73..a5518285d1af1 100644 --- a/node_modules/@npmcli/run-script/lib/run-script-pkg.js +++ b/node_modules/@npmcli/run-script/lib/run-script-pkg.js @@ -94,7 +94,11 @@ const runScriptPkg = async options => { return p.catch(er => { const { signal } = er if (stdio === 'inherit' && signal) { + // by the time we reach here, the child has already exited. we send the + // signal back to ourselves again so that npm will exit with the same + // status as the child process.kill(process.pid, signal) + // just in case we don't die, reject after 500ms // this also keeps the node process open long enough to actually // get the signal, rather than terminating gracefully. diff --git a/node_modules/@npmcli/run-script/lib/signal-manager.js b/node_modules/@npmcli/run-script/lib/signal-manager.js index 7e10f859e0a68..efc00b488063f 100644 --- a/node_modules/@npmcli/run-script/lib/signal-manager.js +++ b/node_modules/@npmcli/run-script/lib/signal-manager.js @@ -1,17 +1,19 @@ const runningProcs = new Set() let handlersInstalled = false +// NOTE: these signals aren't actually forwarded anywhere. they're trapped and +// ignored until all child processes have exited. in our next breaking change +// we should rename this const forwardedSignals = [ 'SIGINT', 'SIGTERM', ] -const handleSignal = signal => { - for (const proc of runningProcs) { - proc.kill(signal) - } -} - +// no-op, this is so receiving the signal doesn't cause us to exit immediately +// instead, we exit after all children have exited when we re-send the signal +// to ourselves. see the catch handler at the bottom of run-script-pkg.js +// istanbul ignore next - this function does nothing +const handleSignal = () => {} const setupListeners = () => { for (const signal of forwardedSignals) { process.on(signal, handleSignal) diff --git a/node_modules/@npmcli/run-script/package.json b/node_modules/@npmcli/run-script/package.json index cdcf6fb0fcf82..38f6f72fa6ad9 100644 --- a/node_modules/@npmcli/run-script/package.json +++ b/node_modules/@npmcli/run-script/package.json @@ -1,6 +1,6 @@ { "name": "@npmcli/run-script", - "version": "6.0.1", + "version": "6.0.2", "description": "Run a lifecycle script for a package (descendant of npm-lifecycle)", "author": "GitHub Inc.", "license": "ISC", @@ -16,7 +16,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", - "@npmcli/template-oss": "4.14.1", + "@npmcli/template-oss": "4.15.1", "require-inject": "^1.4.4", "tap": "^16.0.1" }, @@ -41,7 +41,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.14.1", + "version": "4.15.1", "publish": "true" }, "tap": { diff --git a/node_modules/@sigstore/tuf/LICENSE b/node_modules/@sigstore/tuf/LICENSE new file mode 100644 index 0000000000000..e9e7c1679a09d --- /dev/null +++ b/node_modules/@sigstore/tuf/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2023 The Sigstore Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/node_modules/sigstore/dist/util/appdata.js b/node_modules/@sigstore/tuf/dist/appdata.js similarity index 61% rename from node_modules/sigstore/dist/util/appdata.js rename to node_modules/@sigstore/tuf/dist/appdata.js index d0c7f6f079e50..c9a8ee92b531e 100644 --- a/node_modules/sigstore/dist/util/appdata.js +++ b/node_modules/@sigstore/tuf/dist/appdata.js @@ -4,19 +4,37 @@ var __importDefault = (this && this.__importDefault) || function (mod) { }; Object.defineProperty(exports, "__esModule", { value: true }); exports.appDataPath = void 0; +/* +Copyright 2023 The Sigstore Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ const os_1 = __importDefault(require("os")); const path_1 = __importDefault(require("path")); function appDataPath(name) { const homedir = os_1.default.homedir(); switch (process.platform) { + /* istanbul ignore next */ case 'darwin': { const appSupport = path_1.default.join(homedir, 'Library', 'Application Support'); return path_1.default.join(appSupport, name); } + /* istanbul ignore next */ case 'win32': { const localAppData = process.env.LOCALAPPDATA || path_1.default.join(homedir, 'AppData', 'Local'); return path_1.default.join(localAppData, name, 'Data'); } + /* istanbul ignore next */ default: { const localData = process.env.XDG_DATA_HOME || path_1.default.join(homedir, '.local', 'share'); return path_1.default.join(localData, name); diff --git a/node_modules/sigstore/dist/tuf/index.js b/node_modules/@sigstore/tuf/dist/client.js similarity index 55% rename from node_modules/sigstore/dist/tuf/index.js rename to node_modules/@sigstore/tuf/dist/client.js index 89923d63fa657..08d6b61840909 100644 --- a/node_modules/sigstore/dist/tuf/index.js +++ b/node_modules/@sigstore/tuf/dist/client.js @@ -1,32 +1,9 @@ "use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.getTarget = exports.getTrustedRoot = void 0; +exports.TUFClient = void 0; /* Copyright 2023 The Sigstore Authors. @@ -45,28 +22,21 @@ limitations under the License. const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const tuf_js_1 = require("tuf-js"); -const sigstore = __importStar(require("../types/sigstore")); -const util_1 = require("../util"); const target_1 = require("./target"); -const TRUSTED_ROOT_TARGET = 'trusted_root.json'; -const DEFAULT_CACHE_DIR = util_1.appdata.appDataPath('sigstore-js'); -const DEFAULT_MIRROR_URL = 'https://tuf-repo-cdn.sigstore.dev'; -const DEFAULT_TUF_ROOT_PATH = '../../store/public-good-instance-root.json'; -async function getTrustedRoot(options = {}) { - const trustedRoot = await getTarget(TRUSTED_ROOT_TARGET, options); - return sigstore.TrustedRoot.fromJSON(JSON.parse(trustedRoot)); -} -exports.getTrustedRoot = getTrustedRoot; -async function getTarget(targetName, options = {}) { - const cachePath = options.cachePath || DEFAULT_CACHE_DIR; - const tufRootPath = options.rootPath || require.resolve(DEFAULT_TUF_ROOT_PATH); - const mirrorURL = options.mirrorURL || DEFAULT_MIRROR_URL; - initTufCache(cachePath, tufRootPath); - const remote = initRemoteConfig(cachePath, mirrorURL); - const repoClient = initClient(cachePath, remote); - return (0, target_1.readTarget)(repoClient, targetName); +class TUFClient { + constructor(options) { + initTufCache(options.cachePath, options.rootPath); + const remote = initRemoteConfig(options.cachePath, options.mirrorURL); + this.updater = initClient(options.cachePath, remote, options); + } + async refresh() { + return this.updater.refresh(); + } + getTarget(targetName) { + return (0, target_1.readTarget)(this.updater, targetName); + } } -exports.getTarget = getTarget; +exports.TUFClient = TUFClient; // Initializes the TUF cache directory structure including the initial // root.json file. If the cache directory does not exist, it will be // created. If the targets directory does not exist, it will be created. @@ -102,12 +72,30 @@ function initRemoteConfig(rootDir, mirrorURL) { } return remoteConfig; } -function initClient(cachePath, remote) { +function initClient(cachePath, remote, options) { const baseURL = remote.mirror; + const config = { + fetchTimeout: options.timeout, + }; + // tuf-js only supports a number for fetchRetries so we have to + // convert the boolean and object options to a number. + /* istanbul ignore if */ + if (typeof options.retry !== 'undefined') { + if (typeof options.retry === 'number') { + config.fetchRetries = options.retry; + } + else if (typeof options.retry === 'object') { + config.fetchRetries = options.retry.retries; + } + else if (options.retry === true) { + config.fetchRetries = 1; + } + } return new tuf_js_1.Updater({ metadataBaseUrl: baseURL, targetBaseUrl: `${baseURL}/targets`, metadataDir: cachePath, targetDir: path_1.default.join(cachePath, 'targets'), + config, }); } diff --git a/node_modules/@sigstore/tuf/dist/error.js b/node_modules/@sigstore/tuf/dist/error.js new file mode 100644 index 0000000000000..e13971b289ff2 --- /dev/null +++ b/node_modules/@sigstore/tuf/dist/error.js @@ -0,0 +1,12 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.TUFError = void 0; +class TUFError extends Error { + constructor({ code, message, cause, }) { + super(message); + this.code = code; + this.cause = cause; + this.name = this.constructor.name; + } +} +exports.TUFError = TUFError; diff --git a/node_modules/@sigstore/tuf/dist/index.js b/node_modules/@sigstore/tuf/dist/index.js new file mode 100644 index 0000000000000..0d201c356dffc --- /dev/null +++ b/node_modules/@sigstore/tuf/dist/index.js @@ -0,0 +1,55 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.TUFError = exports.initTUF = exports.getTrustedRoot = void 0; +/* +Copyright 2023 The Sigstore Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +const protobuf_specs_1 = require("@sigstore/protobuf-specs"); +const appdata_1 = require("./appdata"); +const client_1 = require("./client"); +const DEFAULT_CACHE_DIR = 'sigstore-js'; +const DEFAULT_MIRROR_URL = 'https://tuf-repo-cdn.sigstore.dev'; +const DEFAULT_TUF_ROOT_PATH = '../store/public-good-instance-root.json'; +const DEFAULT_RETRY = { retries: 2 }; +const DEFAULT_TIMEOUT = 5000; +const TRUSTED_ROOT_TARGET = 'trusted_root.json'; +async function getTrustedRoot( +/* istanbul ignore next */ +options = {}) { + const client = createClient(options); + const trustedRoot = await client.getTarget(TRUSTED_ROOT_TARGET); + return protobuf_specs_1.TrustedRoot.fromJSON(JSON.parse(trustedRoot)); +} +exports.getTrustedRoot = getTrustedRoot; +async function initTUF( +/* istanbul ignore next */ +options = {}) { + const client = createClient(options); + return client.refresh().then(() => client); +} +exports.initTUF = initTUF; +// Create a TUF client with default options +function createClient(options) { + /* istanbul ignore next */ + return new client_1.TUFClient({ + cachePath: options.cachePath || (0, appdata_1.appDataPath)(DEFAULT_CACHE_DIR), + rootPath: options.rootPath || require.resolve(DEFAULT_TUF_ROOT_PATH), + mirrorURL: options.mirrorURL || DEFAULT_MIRROR_URL, + retry: options.retry ?? DEFAULT_RETRY, + timeout: options.timeout ?? DEFAULT_TIMEOUT, + }); +} +var error_1 = require("./error"); +Object.defineProperty(exports, "TUFError", { enumerable: true, get: function () { return error_1.TUFError; } }); diff --git a/node_modules/sigstore/dist/tuf/target.js b/node_modules/@sigstore/tuf/dist/target.js similarity index 89% rename from node_modules/sigstore/dist/tuf/target.js rename to node_modules/@sigstore/tuf/dist/target.js index b79411c3dd0a4..29eaf99a7e721 100644 --- a/node_modules/sigstore/dist/tuf/target.js +++ b/node_modules/@sigstore/tuf/dist/target.js @@ -20,14 +20,14 @@ See the License for the specific language governing permissions and limitations under the License. */ const fs_1 = __importDefault(require("fs")); -const error_1 = require("../error"); +const error_1 = require("./error"); // Downloads and returns the specified target from the provided TUF Updater. async function readTarget(tuf, targetPath) { const path = await getTargetPath(tuf, targetPath); return new Promise((resolve, reject) => { fs_1.default.readFile(path, 'utf-8', (err, data) => { if (err) { - reject(new error_1.InternalError({ + reject(new error_1.TUFError({ code: 'TUF_READ_TARGET_ERROR', message: `error reading target ${path}`, cause: err, @@ -46,17 +46,17 @@ exports.readTarget = readTarget; async function getTargetPath(tuf, target) { let targetInfo; try { - targetInfo = await tuf.refresh().then(() => tuf.getTargetInfo(target)); + targetInfo = await tuf.getTargetInfo(target); } catch (err) { - throw new error_1.InternalError({ + throw new error_1.TUFError({ code: 'TUF_REFRESH_METADATA_ERROR', message: 'error refreshing TUF metadata', cause: err, }); } if (!targetInfo) { - throw new error_1.InternalError({ + throw new error_1.TUFError({ code: 'TUF_FIND_TARGET_ERROR', message: `target ${target} not found`, }); @@ -69,7 +69,7 @@ async function getTargetPath(tuf, target) { path = await tuf.downloadTarget(targetInfo); } catch (err) { - throw new error_1.InternalError({ + throw new error_1.TUFError({ code: 'TUF_DOWNLOAD_TARGET_ERROR', message: `error downloading target ${path}`, cause: err, diff --git a/node_modules/@sigstore/tuf/package.json b/node_modules/@sigstore/tuf/package.json new file mode 100644 index 0000000000000..241dc32b3c8a9 --- /dev/null +++ b/node_modules/@sigstore/tuf/package.json @@ -0,0 +1,45 @@ +{ + "name": "@sigstore/tuf", + "version": "1.0.0", + "description": "Client for the Sigstore TUF repository", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "clean": "shx rm -rf dist *.tsbuildinfo", + "build": "tsc --build", + "test": "jest" + }, + "files": [ + "dist", + "store" + ], + "author": "bdehamer@github.com", + "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "git+https://github.com/sigstore/sigstore-js.git" + }, + "bugs": { + "url": "https://github.com/sigstore/sigstore-js/issues" + }, + "homepage": "https://github.com/sigstore/sigstore-js/tree/main/packages/tuf#readme", + "publishConfig": { + "provenance": true + }, + "devDependencies": { + "@total-typescript/shoehorn": "^0.1.0", + "@tufjs/repo-mock": "^1.1.0", + "@types/node": "^20.2.5", + "nock": "^13.2.4", + "shx": "^0.3.3", + "typescript": "^5.1.3" + }, + "dependencies": { + "@sigstore/protobuf-specs": "^0.1.0", + "tuf-js": "^1.1.3", + "make-fetch-happen": "^11.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } +} diff --git a/node_modules/@sigstore/tuf/store/public-good-instance-root.json b/node_modules/@sigstore/tuf/store/public-good-instance-root.json new file mode 100644 index 0000000000000..e95c7e88cdf09 --- /dev/null +++ b/node_modules/@sigstore/tuf/store/public-good-instance-root.json @@ -0,0 +1 @@ +{"signed":{"_type":"root","spec_version":"1.0","version":7,"expires":"2023-10-04T13:08:11Z","keys":{"25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEXsz3SZXFb8jMV42j6pJlyjbjR8K\nN3Bwocexq6LMIb5qsWKOQvLN16NUefLc4HswOoumRsVVaajSpQS6fobkRw==\n-----END PUBLIC KEY-----\n"}},"2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0ghrh92Lw1Yr3idGV5WqCtMDB8Cx\n+D8hdC4w2ZLNIplVRoVGLskYa3gheMyOjiJ8kPi15aQ2//7P+oj7UvJPGw==\n-----END PUBLIC KEY-----\n"}},"45b283825eb184cabd582eb17b74fc8ed404f68cf452acabdad2ed6f90ce216b":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAELrWvNt94v4R085ELeeCMxHp7PldF\n0/T1GxukUh2ODuggLGJE0pc1e8CSBf6CS91Fwo9FUOuRsjBUld+VqSyCdQ==\n-----END PUBLIC KEY-----\n"}},"7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEinikSsAQmYkNeH5eYq/CnIzLaacO\nxlSaawQDOwqKy/tCqxq5xxPSJc21K4WIhs9GyOkKfzueY3GILzcMJZ4cWw==\n-----END PUBLIC KEY-----\n"}},"e1863ba02070322ebc626dcecf9d881a3a38c35c3b41a83765b6ad6c37eaec2a":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWRiGr5+j+3J5SsH+Ztr5nE2H2wO7\nBV+nO3s93gLca18qTOzHY1oWyAGDykMSsGTUBSt9D+An0KfKsD2mfSM42Q==\n-----END PUBLIC KEY-----\n"}},"f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEzBzVOmHCPojMVLSI364WiiV8NPrD\n6IgRxVliskz/v+y3JER5mcVGcONliDcWMC5J2lfHmjPNPhb4H7xm8LzfSA==\n-----END PUBLIC KEY-----\n"}},"ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEy8XKsmhBYDI8Jc0GwzBxeKax0cm5\nSTKEU65HPFunUn41sT8pi0FjM4IkHz/YUmwmLUO0Wt7lxhj6BkLIK4qYAw==\n-----END PUBLIC KEY-----\n"}}},"roles":{"root":{"keyids":["ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c","25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99","f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f","7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b","2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de"],"threshold":3},"snapshot":{"keyids":["45b283825eb184cabd582eb17b74fc8ed404f68cf452acabdad2ed6f90ce216b"],"threshold":1},"targets":{"keyids":["ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c","25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99","f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f","7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b","2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de"],"threshold":3},"timestamp":{"keyids":["e1863ba02070322ebc626dcecf9d881a3a38c35c3b41a83765b6ad6c37eaec2a"],"threshold":1}},"consistent_snapshot":true},"signatures":[{"keyid":"25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99","sig":"3046022100c0610c0055ce5c4a52d054d7322e7b514d55baf44423d63aa4daa077cc60fd1f022100a097f2803f090fb66c42ead915a2c46ebe7db53a32bf18f2188275cc936f8bdd"},{"keyid":"f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f","sig":"304502203134f0468810299d5493a867c40630b341296b92e59c29821311d353343bb3a4022100e667ae3d304e7e3da0894c7425f6b9ecd917106841280e5cf6f3496ad5f8f68e"},{"keyid":"7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b","sig":"3045022037fe5f45426f21eaaf4730d2136f2b1611d6379688f79b9d1e3f61719997135c022100b63b022d7b79d4694b96f416d88aa4d7b1a3bff8a01f4fb51e0f42137c7d2d06"},{"keyid":"2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de","sig":"3044022007cc8fcc4940809f2751ad5b535f4c5f53f5b4952f5b5696b09668e743306ac1022006dfcdf94e94c92163eeb1b47796db62cedaa730aa13aa61b573fe23714730f2"}]} diff --git a/node_modules/cacache/lib/content/write.js b/node_modules/cacache/lib/content/write.js index b6f5c5623b58b..7146146581287 100644 --- a/node_modules/cacache/lib/content/write.js +++ b/node_modules/cacache/lib/content/write.js @@ -15,6 +15,9 @@ const fsm = require('fs-minipass') module.exports = write +// Cache of move operations in process so we don't duplicate +const moveOperations = new Map() + async function write (cache, data, opts = {}) { const { algorithms, size, integrity } = opts @@ -159,16 +162,27 @@ async function makeTmp (cache, opts) { async function moveToDestination (tmp, cache, sri, opts) { const destination = contentPath(cache, sri) const destDir = path.dirname(destination) - - await fs.mkdir(destDir, { recursive: true }) - try { - await moveFile(tmp.target, destination, { overwrite: false }) - tmp.moved = true - } catch (err) { - if (!err.message.startsWith('The destination file exists')) { - throw Object.assign(err, { code: 'EEXIST' }) - } + if (moveOperations.has(destination)) { + return moveOperations.get(destination) } + moveOperations.set( + destination, + fs.mkdir(destDir, { recursive: true }) + .then(async () => { + await moveFile(tmp.target, destination, { overwrite: false }) + tmp.moved = true + return tmp.moved + }) + .catch(err => { + if (!err.message.startsWith('The destination file exists')) { + throw Object.assign(err, { code: 'EEXIST' }) + } + }).finally(() => { + moveOperations.delete(destination) + }) + + ) + return moveOperations.get(destination) } function sizeError (expected, found) { diff --git a/node_modules/cacache/lib/util/glob.js b/node_modules/cacache/lib/util/glob.js index 3132a4da65e63..8500c1c16a429 100644 --- a/node_modules/cacache/lib/util/glob.js +++ b/node_modules/cacache/lib/util/glob.js @@ -1,6 +1,7 @@ 'use strict' const { glob } = require('glob') +const path = require('path') -const globify = (pattern) => pattern.split('//').join('/') +const globify = (pattern) => pattern.split(path.win32.sep).join(path.posix.sep) module.exports = (path, options) => glob(globify(path), options) diff --git a/node_modules/cacache/package.json b/node_modules/cacache/package.json index b8ee783388d84..a6f6f9bdfc465 100644 --- a/node_modules/cacache/package.json +++ b/node_modules/cacache/package.json @@ -1,6 +1,6 @@ { "name": "cacache", - "version": "17.1.0", + "version": "17.1.3", "cache-version": { "content": "2", "index": "5" @@ -60,7 +60,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", - "@npmcli/template-oss": "4.14.1", + "@npmcli/template-oss": "4.15.1", "tap": "^16.0.0" }, "engines": { @@ -69,7 +69,7 @@ "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", "windowsCI": false, - "version": "4.14.1", + "version": "4.15.1", "publish": "true" }, "author": "GitHub Inc.", diff --git a/node_modules/chalk/license b/node_modules/chalk/license index e7af2f77107d7..fa7ceba3eb4a9 100644 --- a/node_modules/chalk/license +++ b/node_modules/chalk/license @@ -1,6 +1,6 @@ MIT License -Copyright (c) Sindre Sorhus (sindresorhus.com) +Copyright (c) Sindre Sorhus (https://sindresorhus.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/node_modules/chalk/package.json b/node_modules/chalk/package.json index 47c23f29068ca..ddcf7589e9797 100644 --- a/node_modules/chalk/package.json +++ b/node_modules/chalk/package.json @@ -1,21 +1,31 @@ { "name": "chalk", - "version": "4.1.2", + "version": "5.2.0", "description": "Terminal string styling done right", "license": "MIT", "repository": "chalk/chalk", "funding": "https://github.com/chalk/chalk?sponsor=1", - "main": "source", + "type": "module", + "main": "./source/index.js", + "exports": "./source/index.js", + "imports": { + "#ansi-styles": "./source/vendor/ansi-styles/index.js", + "#supports-color": { + "node": "./source/vendor/supports-color/index.js", + "default": "./source/vendor/supports-color/browser.js" + } + }, + "types": "./source/index.d.ts", "engines": { - "node": ">=10" + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, "scripts": { - "test": "xo && nyc ava && tsd", + "test": "xo && c8 ava && tsd", "bench": "matcha benchmark.js" }, "files": [ "source", - "index.d.ts" + "!source/index.test-d.ts" ], "keywords": [ "color", @@ -25,7 +35,6 @@ "console", "cli", "string", - "str", "ansi", "style", "styles", @@ -40,29 +49,33 @@ "command-line", "text" ], - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "devDependencies": { - "ava": "^2.4.0", - "coveralls": "^3.0.7", - "execa": "^4.0.0", - "import-fresh": "^3.1.0", + "@types/node": "^16.11.10", + "ava": "^3.15.0", + "c8": "^7.10.0", + "color-convert": "^2.0.1", + "execa": "^6.0.0", + "log-update": "^5.0.0", "matcha": "^0.7.0", - "nyc": "^15.0.0", - "resolve-from": "^5.0.0", - "tsd": "^0.7.4", - "xo": "^0.28.2" + "tsd": "^0.19.0", + "xo": "^0.53.0", + "yoctodelay": "^2.0.0" }, "xo": { "rules": { "unicorn/prefer-string-slice": "off", - "unicorn/prefer-includes": "off", - "@typescript-eslint/member-ordering": "off", - "no-redeclare": "off", - "unicorn/string-content": "off", - "unicorn/better-regex": "off" + "@typescript-eslint/consistent-type-imports": "off", + "@typescript-eslint/consistent-type-exports": "off", + "@typescript-eslint/consistent-type-definitions": "off" } + }, + "c8": { + "reporter": [ + "text", + "lcov" + ], + "exclude": [ + "source/vendor" + ] } } diff --git a/node_modules/chalk/source/index.js b/node_modules/chalk/source/index.js index 75ec66350527a..8bc993da5d622 100644 --- a/node_modules/chalk/source/index.js +++ b/node_modules/chalk/source/index.js @@ -1,19 +1,22 @@ -'use strict'; -const ansiStyles = require('ansi-styles'); -const {stdout: stdoutColor, stderr: stderrColor} = require('supports-color'); -const { +import ansiStyles from '#ansi-styles'; +import supportsColor from '#supports-color'; +import { // eslint-disable-line import/order stringReplaceAll, - stringEncaseCRLFWithFirstIndex -} = require('./util'); + stringEncaseCRLFWithFirstIndex, +} from './utilities.js'; -const {isArray} = Array; +const {stdout: stdoutColor, stderr: stderrColor} = supportsColor; + +const GENERATOR = Symbol('GENERATOR'); +const STYLER = Symbol('STYLER'); +const IS_EMPTY = Symbol('IS_EMPTY'); // `supportsColor.level` → `ansiStyles.color[name]` mapping const levelMapping = [ 'ansi', 'ansi', 'ansi256', - 'ansi16m' + 'ansi16m', ]; const styles = Object.create(null); @@ -28,7 +31,7 @@ const applyOptions = (object, options = {}) => { object.level = options.level === undefined ? colorLevel : options.level; }; -class ChalkClass { +export class Chalk { constructor(options) { // eslint-disable-next-line no-constructor-return return chalkFactory(options); @@ -36,69 +39,80 @@ class ChalkClass { } const chalkFactory = options => { - const chalk = {}; + const chalk = (...strings) => strings.join(' '); applyOptions(chalk, options); - chalk.template = (...arguments_) => chalkTag(chalk.template, ...arguments_); - - Object.setPrototypeOf(chalk, Chalk.prototype); - Object.setPrototypeOf(chalk.template, chalk); - - chalk.template.constructor = () => { - throw new Error('`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.'); - }; - - chalk.template.Instance = ChalkClass; + Object.setPrototypeOf(chalk, createChalk.prototype); - return chalk.template; + return chalk; }; -function Chalk(options) { +function createChalk(options) { return chalkFactory(options); } +Object.setPrototypeOf(createChalk.prototype, Function.prototype); + for (const [styleName, style] of Object.entries(ansiStyles)) { styles[styleName] = { get() { - const builder = createBuilder(this, createStyler(style.open, style.close, this._styler), this._isEmpty); + const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]); Object.defineProperty(this, styleName, {value: builder}); return builder; - } + }, }; } styles.visible = { get() { - const builder = createBuilder(this, this._styler, true); + const builder = createBuilder(this, this[STYLER], true); Object.defineProperty(this, 'visible', {value: builder}); return builder; + }, +}; + +const getModelAnsi = (model, level, type, ...arguments_) => { + if (model === 'rgb') { + if (level === 'ansi16m') { + return ansiStyles[type].ansi16m(...arguments_); + } + + if (level === 'ansi256') { + return ansiStyles[type].ansi256(ansiStyles.rgbToAnsi256(...arguments_)); + } + + return ansiStyles[type].ansi(ansiStyles.rgbToAnsi(...arguments_)); } + + if (model === 'hex') { + return getModelAnsi('rgb', level, type, ...ansiStyles.hexToRgb(...arguments_)); + } + + return ansiStyles[type][model](...arguments_); }; -const usedModels = ['rgb', 'hex', 'keyword', 'hsl', 'hsv', 'hwb', 'ansi', 'ansi256']; +const usedModels = ['rgb', 'hex', 'ansi256']; for (const model of usedModels) { styles[model] = { get() { const {level} = this; return function (...arguments_) { - const styler = createStyler(ansiStyles.color[levelMapping[level]][model](...arguments_), ansiStyles.color.close, this._styler); - return createBuilder(this, styler, this._isEmpty); + const styler = createStyler(getModelAnsi(model, levelMapping[level], 'color', ...arguments_), ansiStyles.color.close, this[STYLER]); + return createBuilder(this, styler, this[IS_EMPTY]); }; - } + }, }; -} -for (const model of usedModels) { const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1); styles[bgModel] = { get() { const {level} = this; return function (...arguments_) { - const styler = createStyler(ansiStyles.bgColor[levelMapping[level]][model](...arguments_), ansiStyles.bgColor.close, this._styler); - return createBuilder(this, styler, this._isEmpty); + const styler = createStyler(getModelAnsi(model, levelMapping[level], 'bgColor', ...arguments_), ansiStyles.bgColor.close, this[STYLER]); + return createBuilder(this, styler, this[IS_EMPTY]); }; - } + }, }; } @@ -107,12 +121,12 @@ const proto = Object.defineProperties(() => {}, { level: { enumerable: true, get() { - return this._generator.level; + return this[GENERATOR].level; }, set(level) { - this._generator.level = level; - } - } + this[GENERATOR].level = level; + }, + }, }); const createStyler = (open, close, parent) => { @@ -131,46 +145,39 @@ const createStyler = (open, close, parent) => { close, openAll, closeAll, - parent + parent, }; }; const createBuilder = (self, _styler, _isEmpty) => { - const builder = (...arguments_) => { - if (isArray(arguments_[0]) && isArray(arguments_[0].raw)) { - // Called as a template literal, for example: chalk.red`2 + 3 = {bold ${2+3}}` - return applyStyle(builder, chalkTag(builder, ...arguments_)); - } - - // Single argument is hot path, implicit coercion is faster than anything - // eslint-disable-next-line no-implicit-coercion - return applyStyle(builder, (arguments_.length === 1) ? ('' + arguments_[0]) : arguments_.join(' ')); - }; + // Single argument is hot path, implicit coercion is faster than anything + // eslint-disable-next-line no-implicit-coercion + const builder = (...arguments_) => applyStyle(builder, (arguments_.length === 1) ? ('' + arguments_[0]) : arguments_.join(' ')); // We alter the prototype because we must return a function, but there is // no way to create a function with a different prototype Object.setPrototypeOf(builder, proto); - builder._generator = self; - builder._styler = _styler; - builder._isEmpty = _isEmpty; + builder[GENERATOR] = self; + builder[STYLER] = _styler; + builder[IS_EMPTY] = _isEmpty; return builder; }; const applyStyle = (self, string) => { if (self.level <= 0 || !string) { - return self._isEmpty ? '' : string; + return self[IS_EMPTY] ? '' : string; } - let styler = self._styler; + let styler = self[STYLER]; if (styler === undefined) { return string; } const {openAll, closeAll} = styler; - if (string.indexOf('\u001B') !== -1) { + if (string.includes('\u001B')) { while (styler !== undefined) { // Replace any instances already present with a re-opening code // otherwise only the part of the string until said closing code @@ -192,38 +199,27 @@ const applyStyle = (self, string) => { return openAll + string + closeAll; }; -let template; -const chalkTag = (chalk, ...strings) => { - const [firstString] = strings; - - if (!isArray(firstString) || !isArray(firstString.raw)) { - // If chalk() was called by itself or with a string, - // return the string itself as a string. - return strings.join(' '); - } +Object.defineProperties(createChalk.prototype, styles); - const arguments_ = strings.slice(1); - const parts = [firstString.raw[0]]; +const chalk = createChalk(); +export const chalkStderr = createChalk({level: stderrColor ? stderrColor.level : 0}); - for (let i = 1; i < firstString.length; i++) { - parts.push( - String(arguments_[i - 1]).replace(/[{}\\]/g, '\\$&'), - String(firstString.raw[i]) - ); - } +export { + modifierNames, + foregroundColorNames, + backgroundColorNames, + colorNames, - if (template === undefined) { - template = require('./templates'); - } + // TODO: Remove these aliases in the next major version + modifierNames as modifiers, + foregroundColorNames as foregroundColors, + backgroundColorNames as backgroundColors, + colorNames as colors, +} from './vendor/ansi-styles/index.js'; - return template(chalk, parts.join('')); +export { + stdoutColor as supportsColor, + stderrColor as supportsColorStderr, }; -Object.defineProperties(Chalk.prototype, styles); - -const chalk = Chalk(); // eslint-disable-line new-cap -chalk.supportsColor = stdoutColor; -chalk.stderr = Chalk({level: stderrColor ? stderrColor.level : 0}); // eslint-disable-line new-cap -chalk.stderr.supportsColor = stderrColor; - -module.exports = chalk; +export default chalk; diff --git a/node_modules/chalk/source/templates.js b/node_modules/chalk/source/templates.js deleted file mode 100644 index b130949d646fd..0000000000000 --- a/node_modules/chalk/source/templates.js +++ /dev/null @@ -1,134 +0,0 @@ -'use strict'; -const TEMPLATE_REGEX = /(?:\\(u(?:[a-f\d]{4}|\{[a-f\d]{1,6}\})|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi; -const STYLE_REGEX = /(?:^|\.)(\w+)(?:\(([^)]*)\))?/g; -const STRING_REGEX = /^(['"])((?:\\.|(?!\1)[^\\])*)\1$/; -const ESCAPE_REGEX = /\\(u(?:[a-f\d]{4}|{[a-f\d]{1,6}})|x[a-f\d]{2}|.)|([^\\])/gi; - -const ESCAPES = new Map([ - ['n', '\n'], - ['r', '\r'], - ['t', '\t'], - ['b', '\b'], - ['f', '\f'], - ['v', '\v'], - ['0', '\0'], - ['\\', '\\'], - ['e', '\u001B'], - ['a', '\u0007'] -]); - -function unescape(c) { - const u = c[0] === 'u'; - const bracket = c[1] === '{'; - - if ((u && !bracket && c.length === 5) || (c[0] === 'x' && c.length === 3)) { - return String.fromCharCode(parseInt(c.slice(1), 16)); - } - - if (u && bracket) { - return String.fromCodePoint(parseInt(c.slice(2, -1), 16)); - } - - return ESCAPES.get(c) || c; -} - -function parseArguments(name, arguments_) { - const results = []; - const chunks = arguments_.trim().split(/\s*,\s*/g); - let matches; - - for (const chunk of chunks) { - const number = Number(chunk); - if (!Number.isNaN(number)) { - results.push(number); - } else if ((matches = chunk.match(STRING_REGEX))) { - results.push(matches[2].replace(ESCAPE_REGEX, (m, escape, character) => escape ? unescape(escape) : character)); - } else { - throw new Error(`Invalid Chalk template style argument: ${chunk} (in style '${name}')`); - } - } - - return results; -} - -function parseStyle(style) { - STYLE_REGEX.lastIndex = 0; - - const results = []; - let matches; - - while ((matches = STYLE_REGEX.exec(style)) !== null) { - const name = matches[1]; - - if (matches[2]) { - const args = parseArguments(name, matches[2]); - results.push([name].concat(args)); - } else { - results.push([name]); - } - } - - return results; -} - -function buildStyle(chalk, styles) { - const enabled = {}; - - for (const layer of styles) { - for (const style of layer.styles) { - enabled[style[0]] = layer.inverse ? null : style.slice(1); - } - } - - let current = chalk; - for (const [styleName, styles] of Object.entries(enabled)) { - if (!Array.isArray(styles)) { - continue; - } - - if (!(styleName in current)) { - throw new Error(`Unknown Chalk style: ${styleName}`); - } - - current = styles.length > 0 ? current[styleName](...styles) : current[styleName]; - } - - return current; -} - -module.exports = (chalk, temporary) => { - const styles = []; - const chunks = []; - let chunk = []; - - // eslint-disable-next-line max-params - temporary.replace(TEMPLATE_REGEX, (m, escapeCharacter, inverse, style, close, character) => { - if (escapeCharacter) { - chunk.push(unescape(escapeCharacter)); - } else if (style) { - const string = chunk.join(''); - chunk = []; - chunks.push(styles.length === 0 ? string : buildStyle(chalk, styles)(string)); - styles.push({inverse, styles: parseStyle(style)}); - } else if (close) { - if (styles.length === 0) { - throw new Error('Found extraneous } in Chalk template literal'); - } - - chunks.push(buildStyle(chalk, styles)(chunk.join(''))); - chunk = []; - styles.pop(); - } else { - chunk.push(character); - } - }); - - chunks.push(chunk.join('')); - - if (styles.length > 0) { - const errMessage = `Chalk template literal is missing ${styles.length} closing bracket${styles.length === 1 ? '' : 's'} (\`}\`)`; - throw new Error(errMessage); - } - - return chunks.join(''); -}; diff --git a/node_modules/chalk/source/util.js b/node_modules/chalk/source/util.js deleted file mode 100644 index ca466fd466c07..0000000000000 --- a/node_modules/chalk/source/util.js +++ /dev/null @@ -1,39 +0,0 @@ -'use strict'; - -const stringReplaceAll = (string, substring, replacer) => { - let index = string.indexOf(substring); - if (index === -1) { - return string; - } - - const substringLength = substring.length; - let endIndex = 0; - let returnValue = ''; - do { - returnValue += string.substr(endIndex, index - endIndex) + substring + replacer; - endIndex = index + substringLength; - index = string.indexOf(substring, endIndex); - } while (index !== -1); - - returnValue += string.substr(endIndex); - return returnValue; -}; - -const stringEncaseCRLFWithFirstIndex = (string, prefix, postfix, index) => { - let endIndex = 0; - let returnValue = ''; - do { - const gotCR = string[index - 1] === '\r'; - returnValue += string.substr(endIndex, (gotCR ? index - 1 : index) - endIndex) + prefix + (gotCR ? '\r\n' : '\n') + postfix; - endIndex = index + 1; - index = string.indexOf('\n', endIndex); - } while (index !== -1); - - returnValue += string.substr(endIndex); - return returnValue; -}; - -module.exports = { - stringReplaceAll, - stringEncaseCRLFWithFirstIndex -}; diff --git a/node_modules/chalk/source/utilities.js b/node_modules/chalk/source/utilities.js new file mode 100644 index 0000000000000..4366dee0d84d7 --- /dev/null +++ b/node_modules/chalk/source/utilities.js @@ -0,0 +1,33 @@ +// TODO: When targeting Node.js 16, use `String.prototype.replaceAll`. +export function stringReplaceAll(string, substring, replacer) { + let index = string.indexOf(substring); + if (index === -1) { + return string; + } + + const substringLength = substring.length; + let endIndex = 0; + let returnValue = ''; + do { + returnValue += string.slice(endIndex, index) + substring + replacer; + endIndex = index + substringLength; + index = string.indexOf(substring, endIndex); + } while (index !== -1); + + returnValue += string.slice(endIndex); + return returnValue; +} + +export function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) { + let endIndex = 0; + let returnValue = ''; + do { + const gotCR = string[index - 1] === '\r'; + returnValue += string.slice(endIndex, (gotCR ? index - 1 : index)) + prefix + (gotCR ? '\r\n' : '\n') + postfix; + endIndex = index + 1; + index = string.indexOf('\n', endIndex); + } while (index !== -1); + + returnValue += string.slice(endIndex); + return returnValue; +} diff --git a/node_modules/chalk/source/vendor/ansi-styles/index.js b/node_modules/chalk/source/vendor/ansi-styles/index.js new file mode 100644 index 0000000000000..eaa7bed6cb1ed --- /dev/null +++ b/node_modules/chalk/source/vendor/ansi-styles/index.js @@ -0,0 +1,223 @@ +const ANSI_BACKGROUND_OFFSET = 10; + +const wrapAnsi16 = (offset = 0) => code => `\u001B[${code + offset}m`; + +const wrapAnsi256 = (offset = 0) => code => `\u001B[${38 + offset};5;${code}m`; + +const wrapAnsi16m = (offset = 0) => (red, green, blue) => `\u001B[${38 + offset};2;${red};${green};${blue}m`; + +const styles = { + modifier: { + reset: [0, 0], + // 21 isn't widely supported and 22 does the same thing + bold: [1, 22], + dim: [2, 22], + italic: [3, 23], + underline: [4, 24], + overline: [53, 55], + inverse: [7, 27], + hidden: [8, 28], + strikethrough: [9, 29], + }, + color: { + black: [30, 39], + red: [31, 39], + green: [32, 39], + yellow: [33, 39], + blue: [34, 39], + magenta: [35, 39], + cyan: [36, 39], + white: [37, 39], + + // Bright color + blackBright: [90, 39], + gray: [90, 39], // Alias of `blackBright` + grey: [90, 39], // Alias of `blackBright` + redBright: [91, 39], + greenBright: [92, 39], + yellowBright: [93, 39], + blueBright: [94, 39], + magentaBright: [95, 39], + cyanBright: [96, 39], + whiteBright: [97, 39], + }, + bgColor: { + bgBlack: [40, 49], + bgRed: [41, 49], + bgGreen: [42, 49], + bgYellow: [43, 49], + bgBlue: [44, 49], + bgMagenta: [45, 49], + bgCyan: [46, 49], + bgWhite: [47, 49], + + // Bright color + bgBlackBright: [100, 49], + bgGray: [100, 49], // Alias of `bgBlackBright` + bgGrey: [100, 49], // Alias of `bgBlackBright` + bgRedBright: [101, 49], + bgGreenBright: [102, 49], + bgYellowBright: [103, 49], + bgBlueBright: [104, 49], + bgMagentaBright: [105, 49], + bgCyanBright: [106, 49], + bgWhiteBright: [107, 49], + }, +}; + +export const modifierNames = Object.keys(styles.modifier); +export const foregroundColorNames = Object.keys(styles.color); +export const backgroundColorNames = Object.keys(styles.bgColor); +export const colorNames = [...foregroundColorNames, ...backgroundColorNames]; + +function assembleStyles() { + const codes = new Map(); + + for (const [groupName, group] of Object.entries(styles)) { + for (const [styleName, style] of Object.entries(group)) { + styles[styleName] = { + open: `\u001B[${style[0]}m`, + close: `\u001B[${style[1]}m`, + }; + + group[styleName] = styles[styleName]; + + codes.set(style[0], style[1]); + } + + Object.defineProperty(styles, groupName, { + value: group, + enumerable: false, + }); + } + + Object.defineProperty(styles, 'codes', { + value: codes, + enumerable: false, + }); + + styles.color.close = '\u001B[39m'; + styles.bgColor.close = '\u001B[49m'; + + styles.color.ansi = wrapAnsi16(); + styles.color.ansi256 = wrapAnsi256(); + styles.color.ansi16m = wrapAnsi16m(); + styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET); + styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET); + styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET); + + // From https://github.com/Qix-/color-convert/blob/3f0e0d4e92e235796ccb17f6e85c72094a651f49/conversions.js + Object.defineProperties(styles, { + rgbToAnsi256: { + value(red, green, blue) { + // We use the extended greyscale palette here, with the exception of + // black and white. normal palette only has 4 greyscale shades. + if (red === green && green === blue) { + if (red < 8) { + return 16; + } + + if (red > 248) { + return 231; + } + + return Math.round(((red - 8) / 247) * 24) + 232; + } + + return 16 + + (36 * Math.round(red / 255 * 5)) + + (6 * Math.round(green / 255 * 5)) + + Math.round(blue / 255 * 5); + }, + enumerable: false, + }, + hexToRgb: { + value(hex) { + const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16)); + if (!matches) { + return [0, 0, 0]; + } + + let [colorString] = matches; + + if (colorString.length === 3) { + colorString = [...colorString].map(character => character + character).join(''); + } + + const integer = Number.parseInt(colorString, 16); + + return [ + /* eslint-disable no-bitwise */ + (integer >> 16) & 0xFF, + (integer >> 8) & 0xFF, + integer & 0xFF, + /* eslint-enable no-bitwise */ + ]; + }, + enumerable: false, + }, + hexToAnsi256: { + value: hex => styles.rgbToAnsi256(...styles.hexToRgb(hex)), + enumerable: false, + }, + ansi256ToAnsi: { + value(code) { + if (code < 8) { + return 30 + code; + } + + if (code < 16) { + return 90 + (code - 8); + } + + let red; + let green; + let blue; + + if (code >= 232) { + red = (((code - 232) * 10) + 8) / 255; + green = red; + blue = red; + } else { + code -= 16; + + const remainder = code % 36; + + red = Math.floor(code / 36) / 5; + green = Math.floor(remainder / 6) / 5; + blue = (remainder % 6) / 5; + } + + const value = Math.max(red, green, blue) * 2; + + if (value === 0) { + return 30; + } + + // eslint-disable-next-line no-bitwise + let result = 30 + ((Math.round(blue) << 2) | (Math.round(green) << 1) | Math.round(red)); + + if (value === 2) { + result += 60; + } + + return result; + }, + enumerable: false, + }, + rgbToAnsi: { + value: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)), + enumerable: false, + }, + hexToAnsi: { + value: hex => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)), + enumerable: false, + }, + }); + + return styles; +} + +const ansiStyles = assembleStyles(); + +export default ansiStyles; diff --git a/node_modules/chalk/source/vendor/supports-color/browser.js b/node_modules/chalk/source/vendor/supports-color/browser.js new file mode 100644 index 0000000000000..9fa6888f10288 --- /dev/null +++ b/node_modules/chalk/source/vendor/supports-color/browser.js @@ -0,0 +1,30 @@ +/* eslint-env browser */ + +const level = (() => { + if (navigator.userAgentData) { + const brand = navigator.userAgentData.brands.find(({brand}) => brand === 'Chromium'); + if (brand && brand.version > 93) { + return 3; + } + } + + if (/\b(Chrome|Chromium)\//.test(navigator.userAgent)) { + return 1; + } + + return 0; +})(); + +const colorSupport = level !== 0 && { + level, + hasBasic: true, + has256: level >= 2, + has16m: level >= 3, +}; + +const supportsColor = { + stdout: colorSupport, + stderr: colorSupport, +}; + +export default supportsColor; diff --git a/node_modules/chalk/source/vendor/supports-color/index.js b/node_modules/chalk/source/vendor/supports-color/index.js new file mode 100644 index 0000000000000..a7cea61e9eb5f --- /dev/null +++ b/node_modules/chalk/source/vendor/supports-color/index.js @@ -0,0 +1,181 @@ +import process from 'node:process'; +import os from 'node:os'; +import tty from 'node:tty'; + +// From: https://github.com/sindresorhus/has-flag/blob/main/index.js +function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process.argv) { + const prefix = flag.startsWith('-') ? '' : (flag.length === 1 ? '-' : '--'); + const position = argv.indexOf(prefix + flag); + const terminatorPosition = argv.indexOf('--'); + return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition); +} + +const {env} = process; + +let flagForceColor; +if ( + hasFlag('no-color') + || hasFlag('no-colors') + || hasFlag('color=false') + || hasFlag('color=never') +) { + flagForceColor = 0; +} else if ( + hasFlag('color') + || hasFlag('colors') + || hasFlag('color=true') + || hasFlag('color=always') +) { + flagForceColor = 1; +} + +function envForceColor() { + if ('FORCE_COLOR' in env) { + if (env.FORCE_COLOR === 'true') { + return 1; + } + + if (env.FORCE_COLOR === 'false') { + return 0; + } + + return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3); + } +} + +function translateLevel(level) { + if (level === 0) { + return false; + } + + return { + level, + hasBasic: true, + has256: level >= 2, + has16m: level >= 3, + }; +} + +function _supportsColor(haveStream, {streamIsTTY, sniffFlags = true} = {}) { + const noFlagForceColor = envForceColor(); + if (noFlagForceColor !== undefined) { + flagForceColor = noFlagForceColor; + } + + const forceColor = sniffFlags ? flagForceColor : noFlagForceColor; + + if (forceColor === 0) { + return 0; + } + + if (sniffFlags) { + if (hasFlag('color=16m') + || hasFlag('color=full') + || hasFlag('color=truecolor')) { + return 3; + } + + if (hasFlag('color=256')) { + return 2; + } + } + + // Check for Azure DevOps pipelines. + // Has to be above the `!streamIsTTY` check. + if ('TF_BUILD' in env && 'AGENT_NAME' in env) { + return 1; + } + + if (haveStream && !streamIsTTY && forceColor === undefined) { + return 0; + } + + const min = forceColor || 0; + + if (env.TERM === 'dumb') { + return min; + } + + if (process.platform === 'win32') { + // Windows 10 build 10586 is the first Windows release that supports 256 colors. + // Windows 10 build 14931 is the first release that supports 16m/TrueColor. + const osRelease = os.release().split('.'); + if ( + Number(osRelease[0]) >= 10 + && Number(osRelease[2]) >= 10_586 + ) { + return Number(osRelease[2]) >= 14_931 ? 3 : 2; + } + + return 1; + } + + if ('CI' in env) { + if ('GITHUB_ACTIONS' in env) { + return 3; + } + + if (['TRAVIS', 'CIRCLECI', 'APPVEYOR', 'GITLAB_CI', 'BUILDKITE', 'DRONE'].some(sign => sign in env) || env.CI_NAME === 'codeship') { + return 1; + } + + return min; + } + + if ('TEAMCITY_VERSION' in env) { + return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0; + } + + if (env.COLORTERM === 'truecolor') { + return 3; + } + + if (env.TERM === 'xterm-kitty') { + return 3; + } + + if ('TERM_PROGRAM' in env) { + const version = Number.parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10); + + switch (env.TERM_PROGRAM) { + case 'iTerm.app': { + return version >= 3 ? 3 : 2; + } + + case 'Apple_Terminal': { + return 2; + } + // No default + } + } + + if (/-256(color)?$/i.test(env.TERM)) { + return 2; + } + + if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) { + return 1; + } + + if ('COLORTERM' in env) { + return 1; + } + + return min; +} + +export function createSupportsColor(stream, options = {}) { + const level = _supportsColor(stream, { + streamIsTTY: stream && stream.isTTY, + ...options, + }); + + return translateLevel(level); +} + +const supportsColor = { + stdout: createSupportsColor({isTTY: tty.isatty(1)}), + stderr: createSupportsColor({isTTY: tty.isatty(2)}), +}; + +export default supportsColor; diff --git a/node_modules/exponential-backoff/LICENSE b/node_modules/exponential-backoff/LICENSE new file mode 100644 index 0000000000000..7a4a3ea2424c0 --- /dev/null +++ b/node_modules/exponential-backoff/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/node_modules/exponential-backoff/dist/backoff.js b/node_modules/exponential-backoff/dist/backoff.js new file mode 100644 index 0000000000000..a0aa0dc34b6b1 --- /dev/null +++ b/node_modules/exponential-backoff/dist/backoff.js @@ -0,0 +1,118 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var options_1 = require("./options"); +var delay_factory_1 = require("./delay/delay.factory"); +function backOff(request, options) { + if (options === void 0) { options = {}; } + return __awaiter(this, void 0, void 0, function () { + var sanitizedOptions, backOff; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + sanitizedOptions = options_1.getSanitizedOptions(options); + backOff = new BackOff(request, sanitizedOptions); + return [4 /*yield*/, backOff.execute()]; + case 1: return [2 /*return*/, _a.sent()]; + } + }); + }); +} +exports.backOff = backOff; +var BackOff = /** @class */ (function () { + function BackOff(request, options) { + this.request = request; + this.options = options; + this.attemptNumber = 0; + } + BackOff.prototype.execute = function () { + return __awaiter(this, void 0, void 0, function () { + var e_1, shouldRetry; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!!this.attemptLimitReached) return [3 /*break*/, 7]; + _a.label = 1; + case 1: + _a.trys.push([1, 4, , 6]); + return [4 /*yield*/, this.applyDelay()]; + case 2: + _a.sent(); + return [4 /*yield*/, this.request()]; + case 3: return [2 /*return*/, _a.sent()]; + case 4: + e_1 = _a.sent(); + this.attemptNumber++; + return [4 /*yield*/, this.options.retry(e_1, this.attemptNumber)]; + case 5: + shouldRetry = _a.sent(); + if (!shouldRetry || this.attemptLimitReached) { + throw e_1; + } + return [3 /*break*/, 6]; + case 6: return [3 /*break*/, 0]; + case 7: throw new Error("Something went wrong."); + } + }); + }); + }; + Object.defineProperty(BackOff.prototype, "attemptLimitReached", { + get: function () { + return this.attemptNumber >= this.options.numOfAttempts; + }, + enumerable: true, + configurable: true + }); + BackOff.prototype.applyDelay = function () { + return __awaiter(this, void 0, void 0, function () { + var delay; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + delay = delay_factory_1.DelayFactory(this.options, this.attemptNumber); + return [4 /*yield*/, delay.apply()]; + case 1: + _a.sent(); + return [2 /*return*/]; + } + }); + }); + }; + return BackOff; +}()); +//# sourceMappingURL=backoff.js.map \ No newline at end of file diff --git a/node_modules/exponential-backoff/dist/delay/always/always.delay.js b/node_modules/exponential-backoff/dist/delay/always/always.delay.js new file mode 100644 index 0000000000000..40e34071e493d --- /dev/null +++ b/node_modules/exponential-backoff/dist/delay/always/always.delay.js @@ -0,0 +1,25 @@ +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +var delay_base_1 = require("../delay.base"); +var AlwaysDelay = /** @class */ (function (_super) { + __extends(AlwaysDelay, _super); + function AlwaysDelay() { + return _super !== null && _super.apply(this, arguments) || this; + } + return AlwaysDelay; +}(delay_base_1.Delay)); +exports.AlwaysDelay = AlwaysDelay; +//# sourceMappingURL=always.delay.js.map \ No newline at end of file diff --git a/node_modules/exponential-backoff/dist/delay/delay.base.js b/node_modules/exponential-backoff/dist/delay/delay.base.js new file mode 100644 index 0000000000000..b146c2fa62041 --- /dev/null +++ b/node_modules/exponential-backoff/dist/delay/delay.base.js @@ -0,0 +1,45 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var jitter_factory_1 = require("../jitter/jitter.factory"); +var Delay = /** @class */ (function () { + function Delay(options) { + this.options = options; + this.attempt = 0; + } + Delay.prototype.apply = function () { + var _this = this; + return new Promise(function (resolve) { return setTimeout(resolve, _this.jitteredDelay); }); + }; + Delay.prototype.setAttemptNumber = function (attempt) { + this.attempt = attempt; + }; + Object.defineProperty(Delay.prototype, "jitteredDelay", { + get: function () { + var jitter = jitter_factory_1.JitterFactory(this.options); + return jitter(this.delay); + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Delay.prototype, "delay", { + get: function () { + var constant = this.options.startingDelay; + var base = this.options.timeMultiple; + var power = this.numOfDelayedAttempts; + var delay = constant * Math.pow(base, power); + return Math.min(delay, this.options.maxDelay); + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Delay.prototype, "numOfDelayedAttempts", { + get: function () { + return this.attempt; + }, + enumerable: true, + configurable: true + }); + return Delay; +}()); +exports.Delay = Delay; +//# sourceMappingURL=delay.base.js.map \ No newline at end of file diff --git a/node_modules/exponential-backoff/dist/delay/delay.factory.js b/node_modules/exponential-backoff/dist/delay/delay.factory.js new file mode 100644 index 0000000000000..33008dbfc51c4 --- /dev/null +++ b/node_modules/exponential-backoff/dist/delay/delay.factory.js @@ -0,0 +1,17 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var skip_first_delay_1 = require("./skip-first/skip-first.delay"); +var always_delay_1 = require("./always/always.delay"); +function DelayFactory(options, attempt) { + var delay = initDelayClass(options); + delay.setAttemptNumber(attempt); + return delay; +} +exports.DelayFactory = DelayFactory; +function initDelayClass(options) { + if (!options.delayFirstAttempt) { + return new skip_first_delay_1.SkipFirstDelay(options); + } + return new always_delay_1.AlwaysDelay(options); +} +//# sourceMappingURL=delay.factory.js.map \ No newline at end of file diff --git a/node_modules/exponential-backoff/dist/delay/delay.interface.js b/node_modules/exponential-backoff/dist/delay/delay.interface.js new file mode 100644 index 0000000000000..6fe2a5a0e9d23 --- /dev/null +++ b/node_modules/exponential-backoff/dist/delay/delay.interface.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=delay.interface.js.map \ No newline at end of file diff --git a/node_modules/exponential-backoff/dist/delay/skip-first/skip-first.delay.js b/node_modules/exponential-backoff/dist/delay/skip-first/skip-first.delay.js new file mode 100644 index 0000000000000..73f8841dadd01 --- /dev/null +++ b/node_modules/exponential-backoff/dist/delay/skip-first/skip-first.delay.js @@ -0,0 +1,82 @@ +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var delay_base_1 = require("../delay.base"); +var SkipFirstDelay = /** @class */ (function (_super) { + __extends(SkipFirstDelay, _super); + function SkipFirstDelay() { + return _super !== null && _super.apply(this, arguments) || this; + } + SkipFirstDelay.prototype.apply = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this.isFirstAttempt ? true : _super.prototype.apply.call(this)]; + }); + }); + }; + Object.defineProperty(SkipFirstDelay.prototype, "isFirstAttempt", { + get: function () { + return this.attempt === 0; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(SkipFirstDelay.prototype, "numOfDelayedAttempts", { + get: function () { + return this.attempt - 1; + }, + enumerable: true, + configurable: true + }); + return SkipFirstDelay; +}(delay_base_1.Delay)); +exports.SkipFirstDelay = SkipFirstDelay; +//# sourceMappingURL=skip-first.delay.js.map \ No newline at end of file diff --git a/node_modules/exponential-backoff/dist/jitter/full/full.jitter.js b/node_modules/exponential-backoff/dist/jitter/full/full.jitter.js new file mode 100644 index 0000000000000..16cee36bb5fa5 --- /dev/null +++ b/node_modules/exponential-backoff/dist/jitter/full/full.jitter.js @@ -0,0 +1,8 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +function fullJitter(delay) { + var jitteredDelay = Math.random() * delay; + return Math.round(jitteredDelay); +} +exports.fullJitter = fullJitter; +//# sourceMappingURL=full.jitter.js.map \ No newline at end of file diff --git a/node_modules/exponential-backoff/dist/jitter/jitter.factory.js b/node_modules/exponential-backoff/dist/jitter/jitter.factory.js new file mode 100644 index 0000000000000..8aafe45f8fbb0 --- /dev/null +++ b/node_modules/exponential-backoff/dist/jitter/jitter.factory.js @@ -0,0 +1,15 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var full_jitter_1 = require("./full/full.jitter"); +var no_jitter_1 = require("./no/no.jitter"); +function JitterFactory(options) { + switch (options.jitter) { + case "full": + return full_jitter_1.fullJitter; + case "none": + default: + return no_jitter_1.noJitter; + } +} +exports.JitterFactory = JitterFactory; +//# sourceMappingURL=jitter.factory.js.map \ No newline at end of file diff --git a/node_modules/exponential-backoff/dist/jitter/no/no.jitter.js b/node_modules/exponential-backoff/dist/jitter/no/no.jitter.js new file mode 100644 index 0000000000000..15a40bb2a7bd6 --- /dev/null +++ b/node_modules/exponential-backoff/dist/jitter/no/no.jitter.js @@ -0,0 +1,7 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +function noJitter(delay) { + return delay; +} +exports.noJitter = noJitter; +//# sourceMappingURL=no.jitter.js.map \ No newline at end of file diff --git a/node_modules/exponential-backoff/dist/options.js b/node_modules/exponential-backoff/dist/options.js new file mode 100644 index 0000000000000..1d2ca1705dcfd --- /dev/null +++ b/node_modules/exponential-backoff/dist/options.js @@ -0,0 +1,31 @@ +"use strict"; +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var defaultOptions = { + delayFirstAttempt: false, + jitter: "none", + maxDelay: Infinity, + numOfAttempts: 10, + retry: function () { return true; }, + startingDelay: 100, + timeMultiple: 2 +}; +function getSanitizedOptions(options) { + var sanitized = __assign(__assign({}, defaultOptions), options); + if (sanitized.numOfAttempts < 1) { + sanitized.numOfAttempts = 1; + } + return sanitized; +} +exports.getSanitizedOptions = getSanitizedOptions; +//# sourceMappingURL=options.js.map \ No newline at end of file diff --git a/node_modules/exponential-backoff/package.json b/node_modules/exponential-backoff/package.json new file mode 100644 index 0000000000000..23232a0df2c57 --- /dev/null +++ b/node_modules/exponential-backoff/package.json @@ -0,0 +1,61 @@ +{ + "name": "exponential-backoff", + "version": "3.1.1", + "description": "A utility that allows retrying a function with an exponential delay between attempts.", + "files": [ + "dist/" + ], + "main": "dist/backoff.js", + "types": "dist/backoff.d.ts", + "scripts": { + "build": "tsc", + "test": "jest", + "test:watch": "jest --watch" + }, + "husky": { + "hooks": { + "pre-commit": "lint-staged" + } + }, + "lint-staged": { + "*.{ts,json,md}": [ + "prettier --write", + "git add" + ] + }, + "jest": { + "transform": { + "^.+\\.ts$": "ts-jest" + }, + "testRegex": "\\.spec\\.ts$", + "moduleFileExtensions": [ + "ts", + "js" + ] + }, + "repository": { + "type": "git", + "url": "git+https://github.com/coveo/exponential-backoff.git" + }, + "keywords": [ + "exponential", + "backoff", + "retry" + ], + "author": "Sami Sayegh", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/coveo/exponential-backoff/issues" + }, + "homepage": "https://github.com/coveo/exponential-backoff#readme", + "devDependencies": { + "@types/jest": "^24.0.18", + "@types/node": "^10.14.21", + "husky": "^3.0.9", + "jest": "^24.9.0", + "lint-staged": "^9.4.2", + "prettier": "^1.18.2", + "ts-jest": "^24.1.0", + "typescript": "^3.6.4" + } +} diff --git a/node_modules/glob/dist/cjs/package.json b/node_modules/glob/dist/cjs/package.json index e225638de741d..44b67c307f1c8 100644 --- a/node_modules/glob/dist/cjs/package.json +++ b/node_modules/glob/dist/cjs/package.json @@ -1,99 +1,4 @@ { - "author": "Isaac Z. Schlueter (http://blog.izs.me/)", - "name": "glob", - "description": "the most correct and second fastest glob implementation in JavaScript", - "version": "10.2.2", - "bin": "./dist/cjs/src/bin.js", - "repository": { - "type": "git", - "url": "git://github.com/isaacs/node-glob.git" - }, - "main": "./dist/cjs/src/index.js", - "module": "./dist/mjs/index.js", - "types": "./dist/mjs/index.d.ts", - "exports": { - ".": { - "import": { - "types": "./dist/mjs/index.d.ts", - "default": "./dist/mjs/index.js" - }, - "require": { - "types": "./dist/cjs/src/index.d.ts", - "default": "./dist/cjs/src/index.js" - } - } - }, - "files": [ - "dist" - ], - "scripts": { - "preversion": "npm test", - "postversion": "npm publish", - "prepublishOnly": "git push origin --follow-tags", - "preprepare": "rm -rf dist", - "prepare": "tsc -p tsconfig.json && tsc -p tsconfig-esm.json", - "postprepare": "bash fixup.sh", - "pretest": "npm run prepare", - "presnap": "npm run prepare", - "test": "c8 tap", - "snap": "c8 tap", - "format": "prettier --write . --loglevel warn", - "typedoc": "typedoc --tsconfig tsconfig-esm.json ./src/*.ts", - "prepublish": "npm run benchclean", - "profclean": "rm -f v8.log profile.txt", - "test-regen": "npm run profclean && TEST_REGEN=1 node --no-warnings --loader ts-node/esm test/00-setup.ts", - "prebench": "npm run prepare", - "bench": "bash benchmark.sh", - "preprof": "npm run prepare", - "prof": "bash prof.sh", - "benchclean": "node benchclean.js" - }, - "prettier": { - "semi": false, - "printWidth": 75, - "tabWidth": 2, - "useTabs": false, - "singleQuote": true, - "jsxSingleQuote": false, - "bracketSameLine": true, - "arrowParens": "avoid", - "endOfLine": "lf" - }, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.0.3", - "minimatch": "^9.0.0", - "minipass": "^5.0.0", - "path-scurry": "^1.7.0" - }, - "devDependencies": { - "@types/node": "^18.11.18", - "@types/tap": "^15.0.7", - "c8": "^7.12.0", - "memfs": "^3.4.13", - "mkdirp": "^2.1.4", - "prettier": "^2.8.3", - "rimraf": "^4.1.3", - "tap": "^16.3.4", - "ts-node": "^10.9.1", - "typedoc": "^0.23.24", - "typescript": "^4.9.4" - }, - "tap": { - "before": "test/00-setup.ts", - "coverage": false, - "node-arg": [ - "--no-warnings", - "--loader", - "ts-node/esm" - ], - "ts": false - }, - "license": "ISC", - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } + "version": "10.2.7", + "type": "commonjs" } diff --git a/node_modules/glob/dist/cjs/src/glob.js b/node_modules/glob/dist/cjs/src/glob.js index a05d9f0eb3963..e7ad4deb980d3 100644 --- a/node_modules/glob/dist/cjs/src/glob.js +++ b/node_modules/glob/dist/cjs/src/glob.js @@ -130,6 +130,11 @@ class Glob { }); } this.nocase = this.scurry.nocase; + // If you do nocase:true on a case-sensitive file system, then + // we need to use regexps instead of strings for non-magic + // path portions, because statting `aBc` won't return results + // for the file `AbC` for example. + const nocaseMagicOnly = this.platform === 'darwin' || this.platform === 'win32'; const mmo = { // default nocase based on platform ...opts, @@ -137,7 +142,7 @@ class Glob { matchBase: this.matchBase, nobrace: this.nobrace, nocase: this.nocase, - nocaseMagicOnly: true, + nocaseMagicOnly, nocomment: true, noext: this.noext, nonegate: true, diff --git a/node_modules/glob/dist/mjs/glob.js b/node_modules/glob/dist/mjs/glob.js index a246019cd35f9..f158065746e58 100644 --- a/node_modules/glob/dist/mjs/glob.js +++ b/node_modules/glob/dist/mjs/glob.js @@ -127,6 +127,11 @@ export class Glob { }); } this.nocase = this.scurry.nocase; + // If you do nocase:true on a case-sensitive file system, then + // we need to use regexps instead of strings for non-magic + // path portions, because statting `aBc` won't return results + // for the file `AbC` for example. + const nocaseMagicOnly = this.platform === 'darwin' || this.platform === 'win32'; const mmo = { // default nocase based on platform ...opts, @@ -134,7 +139,7 @@ export class Glob { matchBase: this.matchBase, nobrace: this.nobrace, nocase: this.nocase, - nocaseMagicOnly: true, + nocaseMagicOnly, nocomment: true, noext: this.noext, nonegate: true, diff --git a/node_modules/glob/dist/mjs/package.json b/node_modules/glob/dist/mjs/package.json index ff3441b45957b..ac4c42f81fbd8 100644 --- a/node_modules/glob/dist/mjs/package.json +++ b/node_modules/glob/dist/mjs/package.json @@ -1,4 +1,4 @@ { - "version": "10.2.1", + "version": "10.2.7", "type": "module" } diff --git a/node_modules/glob/package.json b/node_modules/glob/package.json index b04d087e28d89..ba9732c0f6de5 100644 --- a/node_modules/glob/package.json +++ b/node_modules/glob/package.json @@ -1,8 +1,8 @@ { - "author": "Isaac Z. Schlueter (http://blog.izs.me/)", + "author": "Isaac Z. Schlueter (https://blog.izs.me/)", "name": "glob", "description": "the most correct and second fastest glob implementation in JavaScript", - "version": "10.2.2", + "version": "10.2.7", "bin": "./dist/cjs/src/bin.js", "repository": { "type": "git", @@ -31,8 +31,7 @@ "postversion": "npm publish", "prepublishOnly": "git push origin --follow-tags", "preprepare": "rm -rf dist", - "prepare": "tsc -p tsconfig.json && tsc -p tsconfig-esm.json", - "postprepare": "bash fixup.sh", + "prepare": "tsc -p tsconfig.json && tsc -p tsconfig-esm.json && bash fixup.sh", "pretest": "npm run prepare", "presnap": "npm run prepare", "test": "c8 tap", @@ -62,12 +61,12 @@ "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^2.0.3", - "minimatch": "^9.0.0", - "minipass": "^5.0.0", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2", "path-scurry": "^1.7.0" }, "devDependencies": { - "@types/node": "^18.11.18", + "@types/node": "^20.2.1", "@types/tap": "^15.0.7", "c8": "^7.12.0", "memfs": "^3.4.13", diff --git a/node_modules/has-flag/index.js b/node_modules/has-flag/index.js deleted file mode 100644 index b6f80b1f8ffd7..0000000000000 --- a/node_modules/has-flag/index.js +++ /dev/null @@ -1,8 +0,0 @@ -'use strict'; - -module.exports = (flag, argv = process.argv) => { - const prefix = flag.startsWith('-') ? '' : (flag.length === 1 ? '-' : '--'); - const position = argv.indexOf(prefix + flag); - const terminatorPosition = argv.indexOf('--'); - return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition); -}; diff --git a/node_modules/has-flag/license b/node_modules/has-flag/license deleted file mode 100644 index e7af2f77107d7..0000000000000 --- a/node_modules/has-flag/license +++ /dev/null @@ -1,9 +0,0 @@ -MIT License - -Copyright (c) Sindre Sorhus (sindresorhus.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/has-flag/package.json b/node_modules/has-flag/package.json deleted file mode 100644 index a9cba4b856d04..0000000000000 --- a/node_modules/has-flag/package.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "name": "has-flag", - "version": "4.0.0", - "description": "Check if argv has a specific flag", - "license": "MIT", - "repository": "sindresorhus/has-flag", - "author": { - "name": "Sindre Sorhus", - "email": "sindresorhus@gmail.com", - "url": "sindresorhus.com" - }, - "engines": { - "node": ">=8" - }, - "scripts": { - "test": "xo && ava && tsd" - }, - "files": [ - "index.js", - "index.d.ts" - ], - "keywords": [ - "has", - "check", - "detect", - "contains", - "find", - "flag", - "cli", - "command-line", - "argv", - "process", - "arg", - "args", - "argument", - "arguments", - "getopt", - "minimist", - "optimist" - ], - "devDependencies": { - "ava": "^1.4.1", - "tsd": "^0.7.2", - "xo": "^0.24.0" - } -} diff --git a/node_modules/infer-owner/LICENSE b/node_modules/infer-owner/LICENSE deleted file mode 100644 index 20a4762540923..0000000000000 --- a/node_modules/infer-owner/LICENSE +++ /dev/null @@ -1,15 +0,0 @@ -The ISC License - -Copyright (c) npm, Inc. 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/infer-owner/index.js b/node_modules/infer-owner/index.js deleted file mode 100644 index a7bddcbd2288b..0000000000000 --- a/node_modules/infer-owner/index.js +++ /dev/null @@ -1,71 +0,0 @@ -const cache = new Map() -const fs = require('fs') -const { dirname, resolve } = require('path') - - -const lstat = path => new Promise((res, rej) => - fs.lstat(path, (er, st) => er ? rej(er) : res(st))) - -const inferOwner = path => { - path = resolve(path) - if (cache.has(path)) - return Promise.resolve(cache.get(path)) - - const statThen = st => { - const { uid, gid } = st - cache.set(path, { uid, gid }) - return { uid, gid } - } - const parent = dirname(path) - const parentTrap = parent === path ? null : er => { - return inferOwner(parent).then((owner) => { - cache.set(path, owner) - return owner - }) - } - return lstat(path).then(statThen, parentTrap) -} - -const inferOwnerSync = path => { - path = resolve(path) - if (cache.has(path)) - return cache.get(path) - - const parent = dirname(path) - - // avoid obscuring call site by re-throwing - // "catch" the error by returning from a finally, - // only if we're not at the root, and the parent call works. - let threw = true - try { - const st = fs.lstatSync(path) - threw = false - const { uid, gid } = st - cache.set(path, { uid, gid }) - return { uid, gid } - } finally { - if (threw && parent !== path) { - const owner = inferOwnerSync(parent) - cache.set(path, owner) - return owner // eslint-disable-line no-unsafe-finally - } - } -} - -const inflight = new Map() -module.exports = path => { - path = resolve(path) - if (inflight.has(path)) - return Promise.resolve(inflight.get(path)) - const p = inferOwner(path).then(owner => { - inflight.delete(path) - return owner - }) - inflight.set(path, p) - return p -} -module.exports.sync = inferOwnerSync -module.exports.clearCache = () => { - cache.clear() - inflight.clear() -} diff --git a/node_modules/infer-owner/package.json b/node_modules/infer-owner/package.json deleted file mode 100644 index c4b2b6e6df206..0000000000000 --- a/node_modules/infer-owner/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "infer-owner", - "version": "1.0.4", - "description": "Infer the owner of a path based on the owner of its nearest existing parent", - "author": "Isaac Z. Schlueter (https://izs.me)", - "license": "ISC", - "scripts": { - "test": "tap -J test/*.js --100", - "snap": "TAP_SNAPSHOT=1 tap -J test/*.js --100", - "preversion": "npm test", - "postversion": "npm publish", - "postpublish": "git push origin --follow-tags" - }, - "devDependencies": { - "mutate-fs": "^2.1.1", - "tap": "^12.4.2" - }, - "main": "index.js", - "repository": "https://github.com/npm/infer-owner", - "publishConfig": { - "access": "public" - }, - "files": [ - "index.js" - ] -} diff --git a/node_modules/ini/lib/ini.js b/node_modules/ini/lib/ini.js index 763c829c6fc51..724d69d85a0e4 100644 --- a/node_modules/ini/lib/ini.js +++ b/node_modules/ini/lib/ini.js @@ -8,8 +8,9 @@ const encode = (obj, opt = {}) => { opt.newline = opt.newline === true opt.sort = opt.sort === true opt.whitespace = opt.whitespace === true || opt.align === true + // The `typeof` check is required because accessing the `process` directly fails on browsers. /* istanbul ignore next */ - opt.platform = opt.platform || process?.platform + opt.platform = opt.platform || (typeof process !== 'undefined' && process.platform) opt.bracketedArray = opt.bracketedArray !== false /* istanbul ignore next */ @@ -172,8 +173,8 @@ const decode = (str, opt = {}) => { const remove = [] for (const k of Object.keys(out)) { if (!hasOwnProperty.call(out, k) || - typeof out[k] !== 'object' || - Array.isArray(out[k])) { + typeof out[k] !== 'object' || + Array.isArray(out[k])) { continue } diff --git a/node_modules/ini/package.json b/node_modules/ini/package.json index 5dd968e0edb88..c1a50e93c07f9 100644 --- a/node_modules/ini/package.json +++ b/node_modules/ini/package.json @@ -2,7 +2,7 @@ "author": "GitHub Inc.", "name": "ini", "description": "An ini encoder/decoder for node", - "version": "4.1.0", + "version": "4.1.1", "repository": { "type": "git", "url": "https://github.com/npm/ini.git" @@ -20,7 +20,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", - "@npmcli/template-oss": "4.13.0", + "@npmcli/template-oss": "4.15.1", "tap": "^16.0.1" }, "license": "ISC", @@ -33,7 +33,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.13.0", + "version": "4.15.1", "publish": "true" }, "tap": { diff --git a/node_modules/is-core-module/core.json b/node_modules/is-core-module/core.json index 9a51663fc5ec7..af29f0b734b22 100644 --- a/node_modules/is-core-module/core.json +++ b/node_modules/is-core-module/core.json @@ -114,7 +114,7 @@ "node:string_decoder": [">= 14.18 && < 15", ">= 16"], "sys": [">= 0.4 && < 0.7", ">= 0.8"], "node:sys": [">= 14.18 && < 15", ">= 16"], - "test/reporters": [">= 19.9", ">= 20"], + "test/reporters": ">= 19.9 && < 20.2", "node:test/reporters": [">= 19.9", ">= 20"], "node:test": [">= 16.17 && < 17", ">= 18"], "timers": true, diff --git a/node_modules/is-core-module/package.json b/node_modules/is-core-module/package.json index 715299bd8d5c3..62bb065e8364a 100644 --- a/node_modules/is-core-module/package.json +++ b/node_modules/is-core-module/package.json @@ -1,6 +1,6 @@ { "name": "is-core-module", - "version": "2.12.0", + "version": "2.12.1", "description": "Is this specifier a node.js core module?", "main": "index.js", "sideEffects": false, diff --git a/node_modules/jackspeak/package.json b/node_modules/jackspeak/package.json index 8d85e7f09e915..afaa43e20ae4a 100644 --- a/node_modules/jackspeak/package.json +++ b/node_modules/jackspeak/package.json @@ -1,6 +1,6 @@ { "name": "jackspeak", - "version": "2.2.0", + "version": "2.2.1", "description": "A very strict and proper argument parser.", "main": "./dist/cjs/index.js", "module": "./dist/mjs/index.js", diff --git a/node_modules/minimatch/dist/cjs/index.js b/node_modules/minimatch/dist/cjs/index.js index 3cbc67f892f12..d70e681fef5d7 100644 --- a/node_modules/minimatch/dist/cjs/index.js +++ b/node_modules/minimatch/dist/cjs/index.js @@ -608,39 +608,35 @@ class Minimatch { // the parts match. matchOne(file, pattern, partial = false) { const options = this.options; - // a UNC pattern like //?/c:/* can match a path like c:/x - // and vice versa + // UNC paths like //?/X:/... can match X:/... and vice versa + // Drive letters in absolute drive or unc paths are always compared + // case-insensitively. if (this.isWindows) { - const fileUNC = file[0] === '' && + const fileDrive = typeof file[0] === 'string' && /^[a-z]:$/i.test(file[0]); + const fileUNC = !fileDrive && + file[0] === '' && file[1] === '' && file[2] === '?' && - typeof file[3] === 'string' && /^[a-z]:$/i.test(file[3]); - const patternUNC = pattern[0] === '' && + const patternDrive = typeof pattern[0] === 'string' && /^[a-z]:$/i.test(pattern[0]); + const patternUNC = !patternDrive && + pattern[0] === '' && pattern[1] === '' && pattern[2] === '?' && typeof pattern[3] === 'string' && /^[a-z]:$/i.test(pattern[3]); - if (fileUNC && patternUNC) { - const fd = file[3]; - const pd = pattern[3]; + const fdi = fileUNC ? 3 : fileDrive ? 0 : undefined; + const pdi = patternUNC ? 3 : patternDrive ? 0 : undefined; + if (typeof fdi === 'number' && typeof pdi === 'number') { + const [fd, pd] = [file[fdi], pattern[pdi]]; if (fd.toLowerCase() === pd.toLowerCase()) { - file[3] = pd; - } - } - else if (patternUNC && typeof file[0] === 'string') { - const pd = pattern[3]; - const fd = file[0]; - if (pd.toLowerCase() === fd.toLowerCase()) { - pattern[3] = fd; - pattern = pattern.slice(3); - } - } - else if (fileUNC && typeof pattern[0] === 'string') { - const fd = file[3]; - if (fd.toLowerCase() === pattern[0].toLowerCase()) { - pattern[0] = fd; - file = file.slice(3); + pattern[pdi] = fd; + if (pdi > fdi) { + pattern = pattern.slice(pdi); + } + else if (fdi > pdi) { + file = file.slice(fdi); + } } } } diff --git a/node_modules/minimatch/dist/mjs/index.js b/node_modules/minimatch/dist/mjs/index.js index 0d5e956be8818..831b6a67f63fb 100644 --- a/node_modules/minimatch/dist/mjs/index.js +++ b/node_modules/minimatch/dist/mjs/index.js @@ -596,39 +596,35 @@ export class Minimatch { // the parts match. matchOne(file, pattern, partial = false) { const options = this.options; - // a UNC pattern like //?/c:/* can match a path like c:/x - // and vice versa + // UNC paths like //?/X:/... can match X:/... and vice versa + // Drive letters in absolute drive or unc paths are always compared + // case-insensitively. if (this.isWindows) { - const fileUNC = file[0] === '' && + const fileDrive = typeof file[0] === 'string' && /^[a-z]:$/i.test(file[0]); + const fileUNC = !fileDrive && + file[0] === '' && file[1] === '' && file[2] === '?' && - typeof file[3] === 'string' && /^[a-z]:$/i.test(file[3]); - const patternUNC = pattern[0] === '' && + const patternDrive = typeof pattern[0] === 'string' && /^[a-z]:$/i.test(pattern[0]); + const patternUNC = !patternDrive && + pattern[0] === '' && pattern[1] === '' && pattern[2] === '?' && typeof pattern[3] === 'string' && /^[a-z]:$/i.test(pattern[3]); - if (fileUNC && patternUNC) { - const fd = file[3]; - const pd = pattern[3]; + const fdi = fileUNC ? 3 : fileDrive ? 0 : undefined; + const pdi = patternUNC ? 3 : patternDrive ? 0 : undefined; + if (typeof fdi === 'number' && typeof pdi === 'number') { + const [fd, pd] = [file[fdi], pattern[pdi]]; if (fd.toLowerCase() === pd.toLowerCase()) { - file[3] = pd; - } - } - else if (patternUNC && typeof file[0] === 'string') { - const pd = pattern[3]; - const fd = file[0]; - if (pd.toLowerCase() === fd.toLowerCase()) { - pattern[3] = fd; - pattern = pattern.slice(3); - } - } - else if (fileUNC && typeof pattern[0] === 'string') { - const fd = file[3]; - if (fd.toLowerCase() === pattern[0].toLowerCase()) { - pattern[0] = fd; - file = file.slice(3); + pattern[pdi] = fd; + if (pdi > fdi) { + pattern = pattern.slice(pdi); + } + else if (fdi > pdi) { + file = file.slice(fdi); + } } } } diff --git a/node_modules/minimatch/package.json b/node_modules/minimatch/package.json index 06d796a2e4143..d5ee74e334d6a 100644 --- a/node_modules/minimatch/package.json +++ b/node_modules/minimatch/package.json @@ -2,7 +2,7 @@ "author": "Isaac Z. Schlueter (http://blog.izs.me)", "name": "minimatch", "description": "a glob matcher in javascript", - "version": "9.0.0", + "version": "9.0.1", "repository": { "type": "git", "url": "git://github.com/isaacs/minimatch.git" diff --git a/node_modules/node-gyp/gyp/pylib/gyp/generator/eclipse.py b/node_modules/node-gyp/gyp/pylib/gyp/generator/eclipse.py index 1ff0dc83ae200..a851b4db757ed 100644 --- a/node_modules/node-gyp/gyp/pylib/gyp/generator/eclipse.py +++ b/node_modules/node-gyp/gyp/pylib/gyp/generator/eclipse.py @@ -24,7 +24,7 @@ import gyp.common import gyp.msvs_emulation import shlex -import xml.etree.cElementTree as ET +import xml.etree.ElementTree as ET generator_wants_static_library_dependencies_adjusted = False diff --git a/node_modules/node-gyp/gyp/pylib/gyp/xcodeproj_file.py b/node_modules/node-gyp/gyp/pylib/gyp/xcodeproj_file.py index 0e941eb4719ea..4e0ec5e8828f7 100644 --- a/node_modules/node-gyp/gyp/pylib/gyp/xcodeproj_file.py +++ b/node_modules/node-gyp/gyp/pylib/gyp/xcodeproj_file.py @@ -2770,7 +2770,7 @@ def __init__(self, properties=None, id=None, parent=None, path=None): self.path = path self._other_pbxprojects = {} # super - return XCContainerPortal.__init__(self, properties, id, parent) + XCContainerPortal.__init__(self, properties, id, parent) def Name(self): name = self.path diff --git a/node_modules/node-gyp/lib/find-visualstudio.js b/node_modules/node-gyp/lib/find-visualstudio.js index d3815112e65de..16f6e79559307 100644 --- a/node_modules/node-gyp/lib/find-visualstudio.js +++ b/node_modules/node-gyp/lib/find-visualstudio.js @@ -266,10 +266,15 @@ VisualStudioFinder.prototype = { return {} }, + msBuildPathExists: function msBuildPathExists (path) { + return fs.existsSync(path) + }, + // Helper - process MSBuild information getMSBuild: function getMSBuild (info, versionYear) { const pkg = 'Microsoft.VisualStudio.VC.MSBuild.Base' const msbuildPath = path.join(info.path, 'MSBuild', 'Current', 'Bin', 'MSBuild.exe') + const msbuildPathArm64 = path.join(info.path, 'MSBuild', 'Current', 'Bin', 'arm64', 'MSBuild.exe') if (info.packages.indexOf(pkg) !== -1) { this.log.silly('- found VC.MSBuild.Base') if (versionYear === 2017) { @@ -279,8 +284,14 @@ VisualStudioFinder.prototype = { return msbuildPath } } - // visual studio 2022 don't has msbuild pkg - if (fs.existsSync(msbuildPath)) { + /** + * Visual Studio 2022 doesn't have the MSBuild package. + * Support for compiling _on_ ARM64 was added in MSVC 14.32.31326, + * so let's leverage it if the user has an ARM64 device. + */ + if (process.arch === 'arm64' && this.msBuildPathExists(msbuildPathArm64)) { + return msbuildPathArm64 + } else if (this.msBuildPathExists(msbuildPath)) { return msbuildPath } return null diff --git a/node_modules/node-gyp/lib/install.js b/node_modules/node-gyp/lib/install.js index 99f6d8592a3fd..1eb9f14c6742a 100644 --- a/node_modules/node-gyp/lib/install.js +++ b/node_modules/node-gyp/lib/install.js @@ -2,6 +2,8 @@ const fs = require('graceful-fs') const os = require('os') +const { backOff } = require('exponential-backoff') +const rm = require('rimraf') const tar = require('tar') const path = require('path') const util = require('util') @@ -20,6 +22,10 @@ const streamPipeline = util.promisify(stream.pipeline) async function install (fs, gyp, argv) { const release = processRelease(argv, gyp, process.version, process.release) + // Detecting target_arch based on logic from create-cnfig-gyp.js. Used on Windows only. + const arch = win ? (gyp.opts.target_arch || gyp.opts.arch || process.arch || 'ia32') : '' + // Used to prevent downloading tarball if only new node.lib is required on Windows. + let shouldDownloadTarball = true // Determine which node dev files version we are installing log.verbose('install', 'input version string %j', release.version) @@ -90,6 +96,26 @@ async function install (fs, gyp, argv) { } } log.verbose('install', 'version is good') + if (win) { + log.verbose('on Windows; need to check node.lib') + const nodeLibPath = path.resolve(devDir, arch, 'node.lib') + try { + await fs.promises.stat(nodeLibPath) + } catch (err) { + if (err.code === 'ENOENT') { + log.verbose('install', `version not already installed for ${arch}, continuing with install`, release.version) + try { + shouldDownloadTarball = false + return await go() + } catch (err) { + return rollback(err) + } + } else if (err.code === 'EACCES') { + return eaccesFallback(err) + } + throw err + } + } } else { try { return await go() @@ -98,15 +124,49 @@ async function install (fs, gyp, argv) { } } + async function copyDirectory (src, dest) { + try { + await fs.promises.stat(src) + } catch { + throw new Error(`Missing source directory for copy: ${src}`) + } + await fs.promises.mkdir(dest, { recursive: true }) + const entries = await fs.promises.readdir(src, { withFileTypes: true }) + for (const entry of entries) { + if (entry.isDirectory()) { + await copyDirectory(path.join(src, entry.name), path.join(dest, entry.name)) + } else if (entry.isFile()) { + // with parallel installs, copying files may cause file errors on + // Windows so use an exponential backoff to resolve collisions + await backOff(async () => { + try { + await fs.promises.copyFile(path.join(src, entry.name), path.join(dest, entry.name)) + } catch (err) { + // if ensure, check if file already exists and that's good enough + if (gyp.opts.ensure && err.code === 'EBUSY') { + try { + await fs.promises.stat(path.join(dest, entry.name)) + return + } catch {} + } + throw err + } + }) + } else { + throw new Error('Unexpected file directory entry type') + } + } + } + async function go () { - log.verbose('ensuring nodedir is created', devDir) + log.verbose('ensuring devDir is created', devDir) // first create the dir for the node dev files try { const created = await fs.promises.mkdir(devDir, { recursive: true }) if (created) { - log.verbose('created nodedir', created) + log.verbose('created devDir', created) } } catch (err) { if (err.code === 'EACCES') { @@ -118,6 +178,7 @@ async function install (fs, gyp, argv) { // now download the node tarball const tarPath = gyp.opts.tarball + let extractErrors = false let extractCount = 0 const contentShasums = {} const expectShasums = {} @@ -136,71 +197,102 @@ async function install (fs, gyp, argv) { return isValid } - // download the tarball and extract! + function onwarn (code, message) { + extractErrors = true + log.error('error while extracting tarball', code, message) + } - if (tarPath) { - await tar.extract({ - file: tarPath, - strip: 1, - filter: isValid, - cwd: devDir - }) - } else { - try { - const res = await download(gyp, release.tarballUrl) + // download the tarball and extract! + // Ommited on Windows if only new node.lib is required - if (res.status !== 200) { - throw new Error(`${res.status} response downloading ${release.tarballUrl}`) - } + // on Windows there can be file errors from tar if parallel installs + // are happening (not uncommon with multiple native modules) so + // extract the tarball to a temp directory first and then copy over + const tarExtractDir = win ? await fs.promises.mkdtemp(path.join(os.tmpdir(), 'node-gyp-tmp-')) : devDir - await streamPipeline( - res.body, - // content checksum - new ShaSum((_, checksum) => { - const filename = path.basename(release.tarballUrl).trim() - contentShasums[filename] = checksum - log.verbose('content checksum', filename, checksum) - }), - tar.extract({ + try { + if (shouldDownloadTarball) { + if (tarPath) { + await tar.extract({ + file: tarPath, strip: 1, - cwd: devDir, - filter: isValid + filter: isValid, + onwarn, + cwd: tarExtractDir }) - ) - } catch (err) { - // something went wrong downloading the tarball? - if (err.code === 'ENOTFOUND') { - throw new Error('This is most likely not a problem with node-gyp or the package itself and\n' + - 'is related to network connectivity. In most cases you are behind a proxy or have bad \n' + - 'network settings.') + } else { + try { + const res = await download(gyp, release.tarballUrl) + + if (res.status !== 200) { + throw new Error(`${res.status} response downloading ${release.tarballUrl}`) + } + + await streamPipeline( + res.body, + // content checksum + new ShaSum((_, checksum) => { + const filename = path.basename(release.tarballUrl).trim() + contentShasums[filename] = checksum + log.verbose('content checksum', filename, checksum) + }), + tar.extract({ + strip: 1, + cwd: tarExtractDir, + filter: isValid, + onwarn + }) + ) + } catch (err) { + // something went wrong downloading the tarball? + if (err.code === 'ENOTFOUND') { + throw new Error('This is most likely not a problem with node-gyp or the package itself and\n' + + 'is related to network connectivity. In most cases you are behind a proxy or have bad \n' + + 'network settings.') + } + throw err + } } - throw err - } - } - // invoked after the tarball has finished being extracted - if (extractCount === 0) { - throw new Error('There was a fatal problem while downloading/extracting the tarball') - } + // invoked after the tarball has finished being extracted + if (extractErrors || extractCount === 0) { + throw new Error('There was a fatal problem while downloading/extracting the tarball') + } - log.verbose('tarball', 'done parsing tarball') + log.verbose('tarball', 'done parsing tarball') + } - const installVersionPath = path.resolve(devDir, 'installVersion') - await Promise.all([ + const installVersionPath = path.resolve(tarExtractDir, 'installVersion') + await Promise.all([ // need to download node.lib - ...(win ? downloadNodeLib() : []), - // write the "installVersion" file - fs.promises.writeFile(installVersionPath, gyp.package.installVersion + '\n'), - // Only download SHASUMS.txt if we downloaded something in need of SHA verification - ...(!tarPath || win ? [downloadShasums()] : []) - ]) - - log.verbose('download contents checksum', JSON.stringify(contentShasums)) - // check content shasums - for (const k in contentShasums) { - log.verbose('validating download checksum for ' + k, '(%s == %s)', contentShasums[k], expectShasums[k]) - if (contentShasums[k] !== expectShasums[k]) { - throw new Error(k + ' local checksum ' + contentShasums[k] + ' not match remote ' + expectShasums[k]) + ...(win ? [downloadNodeLib()] : []), + // write the "installVersion" file + fs.promises.writeFile(installVersionPath, gyp.package.installVersion + '\n'), + // Only download SHASUMS.txt if we downloaded something in need of SHA verification + ...(!tarPath || win ? [downloadShasums()] : []) + ]) + + log.verbose('download contents checksum', JSON.stringify(contentShasums)) + // check content shasums + for (const k in contentShasums) { + log.verbose('validating download checksum for ' + k, '(%s == %s)', contentShasums[k], expectShasums[k]) + if (contentShasums[k] !== expectShasums[k]) { + throw new Error(k + ' local checksum ' + contentShasums[k] + ' not match remote ' + expectShasums[k]) + } + } + + // copy over the files from the temp tarball extract directory to devDir + if (tarExtractDir !== devDir) { + await copyDirectory(tarExtractDir, devDir) + } + } finally { + if (tarExtractDir !== devDir) { + try { + // try to cleanup temp dir + await util.promisify(rm)(tarExtractDir) + } catch { + log.warn('failed to clean up temp tarball extract directory') + } } } @@ -228,43 +320,33 @@ async function install (fs, gyp, argv) { log.verbose('checksum data', JSON.stringify(expectShasums)) } - function downloadNodeLib () { + async function downloadNodeLib () { log.verbose('on Windows; need to download `' + release.name + '.lib`...') - const archs = ['ia32', 'x64', 'arm64'] - return archs.map(async (arch) => { - const dir = path.resolve(devDir, arch) - const targetLibPath = path.resolve(dir, release.name + '.lib') - const { libUrl, libPath } = release[arch] - const name = `${arch} ${release.name}.lib` - log.verbose(name, 'dir', dir) - log.verbose(name, 'url', libUrl) - - await fs.promises.mkdir(dir, { recursive: true }) - log.verbose('streaming', name, 'to:', targetLibPath) - - const res = await download(gyp, libUrl) - - if (res.status === 403 || res.status === 404) { - if (arch === 'arm64') { - // Arm64 is a newer platform on Windows and not all node distributions provide it. - log.verbose(`${name} was not found in ${libUrl}`) - } else { - log.warn(`${name} was not found in ${libUrl}`) - } - return - } else if (res.status !== 200) { - throw new Error(`${res.status} status code downloading ${name}`) - } + const dir = path.resolve(tarExtractDir, arch) + const targetLibPath = path.resolve(dir, release.name + '.lib') + const { libUrl, libPath } = release[arch] + const name = `${arch} ${release.name}.lib` + log.verbose(name, 'dir', dir) + log.verbose(name, 'url', libUrl) + + await fs.promises.mkdir(dir, { recursive: true }) + log.verbose('streaming', name, 'to:', targetLibPath) + + const res = await download(gyp, libUrl) + + // Since only required node.lib is downloaded throw error if it is not fetched + if (res.status !== 200) { + throw new Error(`${res.status} status code downloading ${name}`) + } - return streamPipeline( - res.body, - new ShaSum((_, checksum) => { - contentShasums[libPath] = checksum - log.verbose('content checksum', libPath, checksum) - }), - fs.createWriteStream(targetLibPath) - ) - }) + return streamPipeline( + res.body, + new ShaSum((_, checksum) => { + contentShasums[libPath] = checksum + log.verbose('content checksum', libPath, checksum) + }), + fs.createWriteStream(targetLibPath) + ) } // downloadNodeLib() } // go() diff --git a/node_modules/node-gyp/node_modules/@npmcli/fs/LICENSE.md b/node_modules/node-gyp/node_modules/@npmcli/fs/LICENSE.md deleted file mode 100644 index 5fc208ff122e0..0000000000000 --- a/node_modules/node-gyp/node_modules/@npmcli/fs/LICENSE.md +++ /dev/null @@ -1,20 +0,0 @@ - - -ISC License - -Copyright npm, Inc. - -Permission to use, copy, modify, and/or distribute this -software for any purpose with or without fee is hereby -granted, provided that the above copyright notice and this -permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND NPM DISCLAIMS ALL -WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO -EVENT SHALL NPM BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE -USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/common/get-options.js b/node_modules/node-gyp/node_modules/@npmcli/fs/lib/common/get-options.js deleted file mode 100644 index cb5982f79077a..0000000000000 --- a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/common/get-options.js +++ /dev/null @@ -1,20 +0,0 @@ -// given an input that may or may not be an object, return an object that has -// a copy of every defined property listed in 'copy'. if the input is not an -// object, assign it to the property named by 'wrap' -const getOptions = (input, { copy, wrap }) => { - const result = {} - - if (input && typeof input === 'object') { - for (const prop of copy) { - if (input[prop] !== undefined) { - result[prop] = input[prop] - } - } - } else { - result[wrap] = input - } - - return result -} - -module.exports = getOptions diff --git a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/common/node.js b/node_modules/node-gyp/node_modules/@npmcli/fs/lib/common/node.js deleted file mode 100644 index 4d13bc037359d..0000000000000 --- a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/common/node.js +++ /dev/null @@ -1,9 +0,0 @@ -const semver = require('semver') - -const satisfies = (range) => { - return semver.satisfies(process.version, range, { includePrerelease: true }) -} - -module.exports = { - satisfies, -} diff --git a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/common/owner-sync.js b/node_modules/node-gyp/node_modules/@npmcli/fs/lib/common/owner-sync.js deleted file mode 100644 index 3704aa6d18e1e..0000000000000 --- a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/common/owner-sync.js +++ /dev/null @@ -1,96 +0,0 @@ -const { dirname, resolve } = require('path') -const url = require('url') - -const fs = require('../fs.js') - -// given a path, find the owner of the nearest parent -const find = (path) => { - // if we have no getuid, permissions are irrelevant on this platform - if (!process.getuid) { - return {} - } - - // fs methods accept URL objects with a scheme of file: so we need to unwrap - // those into an actual path string before we can resolve it - const resolved = path != null && path.href && path.origin - ? resolve(url.fileURLToPath(path)) - : resolve(path) - - let stat - - try { - stat = fs.lstatSync(resolved) - } finally { - // if we got a stat, return its contents - if (stat) { - return { uid: stat.uid, gid: stat.gid } - } - - // try the parent directory - if (resolved !== dirname(resolved)) { - return find(dirname(resolved)) - } - - // no more parents, never got a stat, just return an empty object - return {} - } -} - -// given a path, uid, and gid update the ownership of the path if necessary -const update = (path, uid, gid) => { - // nothing to update, just exit - if (uid === undefined && gid === undefined) { - return - } - - try { - // see if the permissions are already the same, if they are we don't - // need to do anything, so return early - const stat = fs.statSync(path) - if (uid === stat.uid && gid === stat.gid) { - return - } - } catch { - // ignore errors - } - - try { - fs.chownSync(path, uid, gid) - } catch { - // ignore errors - } -} - -// accepts a `path` and the `owner` property of an options object and normalizes -// it into an object with numerical `uid` and `gid` -const validate = (path, input) => { - let uid - let gid - - if (typeof input === 'string' || typeof input === 'number') { - uid = input - gid = input - } else if (input && typeof input === 'object') { - uid = input.uid - gid = input.gid - } - - if (uid === 'inherit' || gid === 'inherit') { - const owner = find(path) - if (uid === 'inherit') { - uid = owner.uid - } - - if (gid === 'inherit') { - gid = owner.gid - } - } - - return { uid, gid } -} - -module.exports = { - find, - update, - validate, -} diff --git a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/common/owner.js b/node_modules/node-gyp/node_modules/@npmcli/fs/lib/common/owner.js deleted file mode 100644 index 9f02d41a5e4b3..0000000000000 --- a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/common/owner.js +++ /dev/null @@ -1,96 +0,0 @@ -const { dirname, resolve } = require('path') -const url = require('url') - -const fs = require('../fs.js') - -// given a path, find the owner of the nearest parent -const find = async (path) => { - // if we have no getuid, permissions are irrelevant on this platform - if (!process.getuid) { - return {} - } - - // fs methods accept URL objects with a scheme of file: so we need to unwrap - // those into an actual path string before we can resolve it - const resolved = path != null && path.href && path.origin - ? resolve(url.fileURLToPath(path)) - : resolve(path) - - let stat - - try { - stat = await fs.lstat(resolved) - } finally { - // if we got a stat, return its contents - if (stat) { - return { uid: stat.uid, gid: stat.gid } - } - - // try the parent directory - if (resolved !== dirname(resolved)) { - return find(dirname(resolved)) - } - - // no more parents, never got a stat, just return an empty object - return {} - } -} - -// given a path, uid, and gid update the ownership of the path if necessary -const update = async (path, uid, gid) => { - // nothing to update, just exit - if (uid === undefined && gid === undefined) { - return - } - - try { - // see if the permissions are already the same, if they are we don't - // need to do anything, so return early - const stat = await fs.stat(path) - if (uid === stat.uid && gid === stat.gid) { - return - } - } catch { - // ignore errors - } - - try { - await fs.chown(path, uid, gid) - } catch { - // ignore errors - } -} - -// accepts a `path` and the `owner` property of an options object and normalizes -// it into an object with numerical `uid` and `gid` -const validate = async (path, input) => { - let uid - let gid - - if (typeof input === 'string' || typeof input === 'number') { - uid = input - gid = input - } else if (input && typeof input === 'object') { - uid = input.uid - gid = input.gid - } - - if (uid === 'inherit' || gid === 'inherit') { - const owner = await find(path) - if (uid === 'inherit') { - uid = owner.uid - } - - if (gid === 'inherit') { - gid = owner.gid - } - } - - return { uid, gid } -} - -module.exports = { - find, - update, - validate, -} diff --git a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/copy-file.js b/node_modules/node-gyp/node_modules/@npmcli/fs/lib/copy-file.js deleted file mode 100644 index 8888266d627f0..0000000000000 --- a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/copy-file.js +++ /dev/null @@ -1,16 +0,0 @@ -const fs = require('./fs.js') -const getOptions = require('./common/get-options.js') -const withOwner = require('./with-owner.js') - -const copyFile = async (src, dest, opts) => { - const options = getOptions(opts, { - copy: ['mode'], - wrap: 'mode', - }) - - // the node core method as of 16.5.0 does not support the mode being in an - // object, so we have to pass the mode value directly - return withOwner(dest, () => fs.copyFile(src, dest, options.mode), opts) -} - -module.exports = copyFile diff --git a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/cp/LICENSE b/node_modules/node-gyp/node_modules/@npmcli/fs/lib/cp/LICENSE deleted file mode 100644 index 93546dfb7655b..0000000000000 --- a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/cp/LICENSE +++ /dev/null @@ -1,15 +0,0 @@ -(The MIT License) - -Copyright (c) 2011-2017 JP Richardson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files -(the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, - merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS -OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/cp/index.js b/node_modules/node-gyp/node_modules/@npmcli/fs/lib/cp/index.js deleted file mode 100644 index 5da4739bdd528..0000000000000 --- a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/cp/index.js +++ /dev/null @@ -1,22 +0,0 @@ -const fs = require('../fs.js') -const getOptions = require('../common/get-options.js') -const node = require('../common/node.js') -const polyfill = require('./polyfill.js') - -// node 16.7.0 added fs.cp -const useNative = node.satisfies('>=16.7.0') - -const cp = async (src, dest, opts) => { - const options = getOptions(opts, { - copy: ['dereference', 'errorOnExist', 'filter', 'force', 'preserveTimestamps', 'recursive'], - }) - - // the polyfill is tested separately from this module, no need to hack - // process.version to try to trigger it just for coverage - // istanbul ignore next - return useNative - ? fs.cp(src, dest, options) - : polyfill(src, dest, options) -} - -module.exports = cp diff --git a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/cp/polyfill.js b/node_modules/node-gyp/node_modules/@npmcli/fs/lib/cp/polyfill.js deleted file mode 100644 index f83ccbf57ecc9..0000000000000 --- a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/cp/polyfill.js +++ /dev/null @@ -1,428 +0,0 @@ -// this file is a modified version of the code in node 17.2.0 -// which is, in turn, a modified version of the fs-extra module on npm -// node core changes: -// - Use of the assert module has been replaced with core's error system. -// - All code related to the glob dependency has been removed. -// - Bring your own custom fs module is not currently supported. -// - Some basic code cleanup. -// changes here: -// - remove all callback related code -// - drop sync support -// - change assertions back to non-internal methods (see options.js) -// - throws ENOTDIR when rmdir gets an ENOENT for a path that exists in Windows -'use strict' - -const { - ERR_FS_CP_DIR_TO_NON_DIR, - ERR_FS_CP_EEXIST, - ERR_FS_CP_EINVAL, - ERR_FS_CP_FIFO_PIPE, - ERR_FS_CP_NON_DIR_TO_DIR, - ERR_FS_CP_SOCKET, - ERR_FS_CP_SYMLINK_TO_SUBDIRECTORY, - ERR_FS_CP_UNKNOWN, - ERR_FS_EISDIR, - ERR_INVALID_ARG_TYPE, -} = require('../errors.js') -const { - constants: { - errno: { - EEXIST, - EISDIR, - EINVAL, - ENOTDIR, - }, - }, -} = require('os') -const { - chmod, - copyFile, - lstat, - mkdir, - readdir, - readlink, - stat, - symlink, - unlink, - utimes, -} = require('../fs.js') -const { - dirname, - isAbsolute, - join, - parse, - resolve, - sep, - toNamespacedPath, -} = require('path') -const { fileURLToPath } = require('url') - -const defaultOptions = { - dereference: false, - errorOnExist: false, - filter: undefined, - force: true, - preserveTimestamps: false, - recursive: false, -} - -async function cp (src, dest, opts) { - if (opts != null && typeof opts !== 'object') { - throw new ERR_INVALID_ARG_TYPE('options', ['Object'], opts) - } - return cpFn( - toNamespacedPath(getValidatedPath(src)), - toNamespacedPath(getValidatedPath(dest)), - { ...defaultOptions, ...opts }) -} - -function getValidatedPath (fileURLOrPath) { - const path = fileURLOrPath != null && fileURLOrPath.href - && fileURLOrPath.origin - ? fileURLToPath(fileURLOrPath) - : fileURLOrPath - return path -} - -async function cpFn (src, dest, opts) { - // Warn about using preserveTimestamps on 32-bit node - // istanbul ignore next - if (opts.preserveTimestamps && process.arch === 'ia32') { - const warning = 'Using the preserveTimestamps option in 32-bit ' + - 'node is not recommended' - process.emitWarning(warning, 'TimestampPrecisionWarning') - } - const stats = await checkPaths(src, dest, opts) - const { srcStat, destStat } = stats - await checkParentPaths(src, srcStat, dest) - if (opts.filter) { - return handleFilter(checkParentDir, destStat, src, dest, opts) - } - return checkParentDir(destStat, src, dest, opts) -} - -async function checkPaths (src, dest, opts) { - const { 0: srcStat, 1: destStat } = await getStats(src, dest, opts) - if (destStat) { - if (areIdentical(srcStat, destStat)) { - throw new ERR_FS_CP_EINVAL({ - message: 'src and dest cannot be the same', - path: dest, - syscall: 'cp', - errno: EINVAL, - }) - } - if (srcStat.isDirectory() && !destStat.isDirectory()) { - throw new ERR_FS_CP_DIR_TO_NON_DIR({ - message: `cannot overwrite directory ${src} ` + - `with non-directory ${dest}`, - path: dest, - syscall: 'cp', - errno: EISDIR, - }) - } - if (!srcStat.isDirectory() && destStat.isDirectory()) { - throw new ERR_FS_CP_NON_DIR_TO_DIR({ - message: `cannot overwrite non-directory ${src} ` + - `with directory ${dest}`, - path: dest, - syscall: 'cp', - errno: ENOTDIR, - }) - } - } - - if (srcStat.isDirectory() && isSrcSubdir(src, dest)) { - throw new ERR_FS_CP_EINVAL({ - message: `cannot copy ${src} to a subdirectory of self ${dest}`, - path: dest, - syscall: 'cp', - errno: EINVAL, - }) - } - return { srcStat, destStat } -} - -function areIdentical (srcStat, destStat) { - return destStat.ino && destStat.dev && destStat.ino === srcStat.ino && - destStat.dev === srcStat.dev -} - -function getStats (src, dest, opts) { - const statFunc = opts.dereference ? - (file) => stat(file, { bigint: true }) : - (file) => lstat(file, { bigint: true }) - return Promise.all([ - statFunc(src), - statFunc(dest).catch((err) => { - // istanbul ignore next: unsure how to cover. - if (err.code === 'ENOENT') { - return null - } - // istanbul ignore next: unsure how to cover. - throw err - }), - ]) -} - -async function checkParentDir (destStat, src, dest, opts) { - const destParent = dirname(dest) - const dirExists = await pathExists(destParent) - if (dirExists) { - return getStatsForCopy(destStat, src, dest, opts) - } - await mkdir(destParent, { recursive: true }) - return getStatsForCopy(destStat, src, dest, opts) -} - -function pathExists (dest) { - return stat(dest).then( - () => true, - // istanbul ignore next: not sure when this would occur - (err) => (err.code === 'ENOENT' ? false : Promise.reject(err))) -} - -// Recursively check if dest parent is a subdirectory of src. -// It works for all file types including symlinks since it -// checks the src and dest inodes. It starts from the deepest -// parent and stops once it reaches the src parent or the root path. -async function checkParentPaths (src, srcStat, dest) { - const srcParent = resolve(dirname(src)) - const destParent = resolve(dirname(dest)) - if (destParent === srcParent || destParent === parse(destParent).root) { - return - } - let destStat - try { - destStat = await stat(destParent, { bigint: true }) - } catch (err) { - // istanbul ignore else: not sure when this would occur - if (err.code === 'ENOENT') { - return - } - // istanbul ignore next: not sure when this would occur - throw err - } - if (areIdentical(srcStat, destStat)) { - throw new ERR_FS_CP_EINVAL({ - message: `cannot copy ${src} to a subdirectory of self ${dest}`, - path: dest, - syscall: 'cp', - errno: EINVAL, - }) - } - return checkParentPaths(src, srcStat, destParent) -} - -const normalizePathToArray = (path) => - resolve(path).split(sep).filter(Boolean) - -// Return true if dest is a subdir of src, otherwise false. -// It only checks the path strings. -function isSrcSubdir (src, dest) { - const srcArr = normalizePathToArray(src) - const destArr = normalizePathToArray(dest) - return srcArr.every((cur, i) => destArr[i] === cur) -} - -async function handleFilter (onInclude, destStat, src, dest, opts, cb) { - const include = await opts.filter(src, dest) - if (include) { - return onInclude(destStat, src, dest, opts, cb) - } -} - -function startCopy (destStat, src, dest, opts) { - if (opts.filter) { - return handleFilter(getStatsForCopy, destStat, src, dest, opts) - } - return getStatsForCopy(destStat, src, dest, opts) -} - -async function getStatsForCopy (destStat, src, dest, opts) { - const statFn = opts.dereference ? stat : lstat - const srcStat = await statFn(src) - // istanbul ignore else: can't portably test FIFO - if (srcStat.isDirectory() && opts.recursive) { - return onDir(srcStat, destStat, src, dest, opts) - } else if (srcStat.isDirectory()) { - throw new ERR_FS_EISDIR({ - message: `${src} is a directory (not copied)`, - path: src, - syscall: 'cp', - errno: EINVAL, - }) - } else if (srcStat.isFile() || - srcStat.isCharacterDevice() || - srcStat.isBlockDevice()) { - return onFile(srcStat, destStat, src, dest, opts) - } else if (srcStat.isSymbolicLink()) { - return onLink(destStat, src, dest) - } else if (srcStat.isSocket()) { - throw new ERR_FS_CP_SOCKET({ - message: `cannot copy a socket file: ${dest}`, - path: dest, - syscall: 'cp', - errno: EINVAL, - }) - } else if (srcStat.isFIFO()) { - throw new ERR_FS_CP_FIFO_PIPE({ - message: `cannot copy a FIFO pipe: ${dest}`, - path: dest, - syscall: 'cp', - errno: EINVAL, - }) - } - // istanbul ignore next: should be unreachable - throw new ERR_FS_CP_UNKNOWN({ - message: `cannot copy an unknown file type: ${dest}`, - path: dest, - syscall: 'cp', - errno: EINVAL, - }) -} - -function onFile (srcStat, destStat, src, dest, opts) { - if (!destStat) { - return _copyFile(srcStat, src, dest, opts) - } - return mayCopyFile(srcStat, src, dest, opts) -} - -async function mayCopyFile (srcStat, src, dest, opts) { - if (opts.force) { - await unlink(dest) - return _copyFile(srcStat, src, dest, opts) - } else if (opts.errorOnExist) { - throw new ERR_FS_CP_EEXIST({ - message: `${dest} already exists`, - path: dest, - syscall: 'cp', - errno: EEXIST, - }) - } -} - -async function _copyFile (srcStat, src, dest, opts) { - await copyFile(src, dest) - if (opts.preserveTimestamps) { - return handleTimestampsAndMode(srcStat.mode, src, dest) - } - return setDestMode(dest, srcStat.mode) -} - -async function handleTimestampsAndMode (srcMode, src, dest) { - // Make sure the file is writable before setting the timestamp - // otherwise open fails with EPERM when invoked with 'r+' - // (through utimes call) - if (fileIsNotWritable(srcMode)) { - await makeFileWritable(dest, srcMode) - return setDestTimestampsAndMode(srcMode, src, dest) - } - return setDestTimestampsAndMode(srcMode, src, dest) -} - -function fileIsNotWritable (srcMode) { - return (srcMode & 0o200) === 0 -} - -function makeFileWritable (dest, srcMode) { - return setDestMode(dest, srcMode | 0o200) -} - -async function setDestTimestampsAndMode (srcMode, src, dest) { - await setDestTimestamps(src, dest) - return setDestMode(dest, srcMode) -} - -function setDestMode (dest, srcMode) { - return chmod(dest, srcMode) -} - -async function setDestTimestamps (src, dest) { - // The initial srcStat.atime cannot be trusted - // because it is modified by the read(2) system call - // (See https://nodejs.org/api/fs.html#fs_stat_time_values) - const updatedSrcStat = await stat(src) - return utimes(dest, updatedSrcStat.atime, updatedSrcStat.mtime) -} - -function onDir (srcStat, destStat, src, dest, opts) { - if (!destStat) { - return mkDirAndCopy(srcStat.mode, src, dest, opts) - } - return copyDir(src, dest, opts) -} - -async function mkDirAndCopy (srcMode, src, dest, opts) { - await mkdir(dest) - await copyDir(src, dest, opts) - return setDestMode(dest, srcMode) -} - -async function copyDir (src, dest, opts) { - const dir = await readdir(src) - for (let i = 0; i < dir.length; i++) { - const item = dir[i] - const srcItem = join(src, item) - const destItem = join(dest, item) - const { destStat } = await checkPaths(srcItem, destItem, opts) - await startCopy(destStat, srcItem, destItem, opts) - } -} - -async function onLink (destStat, src, dest) { - let resolvedSrc = await readlink(src) - if (!isAbsolute(resolvedSrc)) { - resolvedSrc = resolve(dirname(src), resolvedSrc) - } - if (!destStat) { - return symlink(resolvedSrc, dest) - } - let resolvedDest - try { - resolvedDest = await readlink(dest) - } catch (err) { - // Dest exists and is a regular file or directory, - // Windows may throw UNKNOWN error. If dest already exists, - // fs throws error anyway, so no need to guard against it here. - // istanbul ignore next: can only test on windows - if (err.code === 'EINVAL' || err.code === 'UNKNOWN') { - return symlink(resolvedSrc, dest) - } - // istanbul ignore next: should not be possible - throw err - } - if (!isAbsolute(resolvedDest)) { - resolvedDest = resolve(dirname(dest), resolvedDest) - } - if (isSrcSubdir(resolvedSrc, resolvedDest)) { - throw new ERR_FS_CP_EINVAL({ - message: `cannot copy ${resolvedSrc} to a subdirectory of self ` + - `${resolvedDest}`, - path: dest, - syscall: 'cp', - errno: EINVAL, - }) - } - // Do not copy if src is a subdir of dest since unlinking - // dest in this case would result in removing src contents - // and therefore a broken symlink would be created. - const srcStat = await stat(src) - if (srcStat.isDirectory() && isSrcSubdir(resolvedDest, resolvedSrc)) { - throw new ERR_FS_CP_SYMLINK_TO_SUBDIRECTORY({ - message: `cannot overwrite ${resolvedDest} with ${resolvedSrc}`, - path: dest, - syscall: 'cp', - errno: EINVAL, - }) - } - return copyLink(resolvedSrc, dest) -} - -async function copyLink (resolvedSrc, dest) { - await unlink(dest) - return symlink(resolvedSrc, dest) -} - -module.exports = cp diff --git a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/errors.js b/node_modules/node-gyp/node_modules/@npmcli/fs/lib/errors.js deleted file mode 100644 index 1cd1e05d0c533..0000000000000 --- a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/errors.js +++ /dev/null @@ -1,129 +0,0 @@ -'use strict' -const { inspect } = require('util') - -// adapted from node's internal/errors -// https://github.com/nodejs/node/blob/c8a04049/lib/internal/errors.js - -// close copy of node's internal SystemError class. -class SystemError { - constructor (code, prefix, context) { - // XXX context.code is undefined in all constructors used in cp/polyfill - // that may be a bug copied from node, maybe the constructor should use - // `code` not `errno`? nodejs/node#41104 - let message = `${prefix}: ${context.syscall} returned ` + - `${context.code} (${context.message})` - - if (context.path !== undefined) { - message += ` ${context.path}` - } - if (context.dest !== undefined) { - message += ` => ${context.dest}` - } - - this.code = code - Object.defineProperties(this, { - name: { - value: 'SystemError', - enumerable: false, - writable: true, - configurable: true, - }, - message: { - value: message, - enumerable: false, - writable: true, - configurable: true, - }, - info: { - value: context, - enumerable: true, - configurable: true, - writable: false, - }, - errno: { - get () { - return context.errno - }, - set (value) { - context.errno = value - }, - enumerable: true, - configurable: true, - }, - syscall: { - get () { - return context.syscall - }, - set (value) { - context.syscall = value - }, - enumerable: true, - configurable: true, - }, - }) - - if (context.path !== undefined) { - Object.defineProperty(this, 'path', { - get () { - return context.path - }, - set (value) { - context.path = value - }, - enumerable: true, - configurable: true, - }) - } - - if (context.dest !== undefined) { - Object.defineProperty(this, 'dest', { - get () { - return context.dest - }, - set (value) { - context.dest = value - }, - enumerable: true, - configurable: true, - }) - } - } - - toString () { - return `${this.name} [${this.code}]: ${this.message}` - } - - [Symbol.for('nodejs.util.inspect.custom')] (_recurseTimes, ctx) { - return inspect(this, { - ...ctx, - getters: true, - customInspect: false, - }) - } -} - -function E (code, message) { - module.exports[code] = class NodeError extends SystemError { - constructor (ctx) { - super(code, message, ctx) - } - } -} - -E('ERR_FS_CP_DIR_TO_NON_DIR', 'Cannot overwrite directory with non-directory') -E('ERR_FS_CP_EEXIST', 'Target already exists') -E('ERR_FS_CP_EINVAL', 'Invalid src or dest') -E('ERR_FS_CP_FIFO_PIPE', 'Cannot copy a FIFO pipe') -E('ERR_FS_CP_NON_DIR_TO_DIR', 'Cannot overwrite non-directory with directory') -E('ERR_FS_CP_SOCKET', 'Cannot copy a socket file') -E('ERR_FS_CP_SYMLINK_TO_SUBDIRECTORY', 'Cannot overwrite symlink in subdirectory of self') -E('ERR_FS_CP_UNKNOWN', 'Cannot copy an unknown file type') -E('ERR_FS_EISDIR', 'Path is a directory') - -module.exports.ERR_INVALID_ARG_TYPE = class ERR_INVALID_ARG_TYPE extends Error { - constructor (name, expected, actual) { - super() - this.code = 'ERR_INVALID_ARG_TYPE' - this.message = `The ${name} argument must be ${expected}. Received ${typeof actual}` - } -} diff --git a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/fs.js b/node_modules/node-gyp/node_modules/@npmcli/fs/lib/fs.js deleted file mode 100644 index 457da10eed03e..0000000000000 --- a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/fs.js +++ /dev/null @@ -1,14 +0,0 @@ -const fs = require('fs') -const promisify = require('@gar/promisify') - -const isLower = (s) => s === s.toLowerCase() && s !== s.toUpperCase() - -const fsSync = Object.fromEntries(Object.entries(fs).filter(([k, v]) => - typeof v === 'function' && (k.endsWith('Sync') || !isLower(k[0])) -)) - -// this module returns the core fs async fns wrapped in a proxy that promisifies -// method calls within the getter. we keep it in a separate module so that the -// overridden methods have a consistent way to get to promisified fs methods -// without creating a circular dependency. the ctors and sync methods are kept untouched -module.exports = { ...promisify(fs), ...fsSync } diff --git a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/index.js b/node_modules/node-gyp/node_modules/@npmcli/fs/lib/index.js deleted file mode 100644 index 3a98648eca9a1..0000000000000 --- a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/index.js +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = { - ...require('./fs.js'), - copyFile: require('./copy-file.js'), - cp: require('./cp/index.js'), - mkdir: require('./mkdir.js'), - mkdtemp: require('./mkdtemp.js'), - rm: require('./rm/index.js'), - withTempDir: require('./with-temp-dir.js'), - withOwner: require('./with-owner.js'), - withOwnerSync: require('./with-owner-sync.js'), - writeFile: require('./write-file.js'), -} diff --git a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/mkdir.js b/node_modules/node-gyp/node_modules/@npmcli/fs/lib/mkdir.js deleted file mode 100644 index 098d8d0a09ae3..0000000000000 --- a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/mkdir.js +++ /dev/null @@ -1,19 +0,0 @@ -const fs = require('./fs.js') -const getOptions = require('./common/get-options.js') -const withOwner = require('./with-owner.js') - -// extends mkdir with the ability to specify an owner of the new dir -const mkdir = async (path, opts) => { - const options = getOptions(opts, { - copy: ['mode', 'recursive'], - wrap: 'mode', - }) - - return withOwner( - path, - () => fs.mkdir(path, options), - opts - ) -} - -module.exports = mkdir diff --git a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/mkdtemp.js b/node_modules/node-gyp/node_modules/@npmcli/fs/lib/mkdtemp.js deleted file mode 100644 index 60b12a788de90..0000000000000 --- a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/mkdtemp.js +++ /dev/null @@ -1,23 +0,0 @@ -const { dirname, sep } = require('path') - -const fs = require('./fs.js') -const getOptions = require('./common/get-options.js') -const withOwner = require('./with-owner.js') - -const mkdtemp = async (prefix, opts) => { - const options = getOptions(opts, { - copy: ['encoding'], - wrap: 'encoding', - }) - - // mkdtemp relies on the trailing path separator to indicate if it should - // create a directory inside of the prefix. if that's the case then the root - // we infer ownership from is the prefix itself, otherwise it's the dirname - // /tmp -> /tmpABCDEF, infers from / - // /tmp/ -> /tmp/ABCDEF, infers from /tmp - const root = prefix.endsWith(sep) ? prefix : dirname(prefix) - - return withOwner(root, () => fs.mkdtemp(prefix, options), opts) -} - -module.exports = mkdtemp diff --git a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/rm/index.js b/node_modules/node-gyp/node_modules/@npmcli/fs/lib/rm/index.js deleted file mode 100644 index cb81fbdf8cc47..0000000000000 --- a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/rm/index.js +++ /dev/null @@ -1,22 +0,0 @@ -const fs = require('../fs.js') -const getOptions = require('../common/get-options.js') -const node = require('../common/node.js') -const polyfill = require('./polyfill.js') - -// node 14.14.0 added fs.rm, which allows both the force and recursive options -const useNative = node.satisfies('>=14.14.0') - -const rm = async (path, opts) => { - const options = getOptions(opts, { - copy: ['retryDelay', 'maxRetries', 'recursive', 'force'], - }) - - // the polyfill is tested separately from this module, no need to hack - // process.version to try to trigger it just for coverage - // istanbul ignore next - return useNative - ? fs.rm(path, options) - : polyfill(path, options) -} - -module.exports = rm diff --git a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/rm/polyfill.js b/node_modules/node-gyp/node_modules/@npmcli/fs/lib/rm/polyfill.js deleted file mode 100644 index a25c17483b001..0000000000000 --- a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/rm/polyfill.js +++ /dev/null @@ -1,239 +0,0 @@ -// this file is a modified version of the code in node core >=14.14.0 -// which is, in turn, a modified version of the rimraf module on npm -// node core changes: -// - Use of the assert module has been replaced with core's error system. -// - All code related to the glob dependency has been removed. -// - Bring your own custom fs module is not currently supported. -// - Some basic code cleanup. -// changes here: -// - remove all callback related code -// - drop sync support -// - change assertions back to non-internal methods (see options.js) -// - throws ENOTDIR when rmdir gets an ENOENT for a path that exists in Windows -const errnos = require('os').constants.errno -const { join } = require('path') -const fs = require('../fs.js') - -// error codes that mean we need to remove contents -const notEmptyCodes = new Set([ - 'ENOTEMPTY', - 'EEXIST', - 'EPERM', -]) - -// error codes we can retry later -const retryCodes = new Set([ - 'EBUSY', - 'EMFILE', - 'ENFILE', - 'ENOTEMPTY', - 'EPERM', -]) - -const isWindows = process.platform === 'win32' - -const defaultOptions = { - retryDelay: 100, - maxRetries: 0, - recursive: false, - force: false, -} - -// this is drastically simplified, but should be roughly equivalent to what -// node core throws -class ERR_FS_EISDIR extends Error { - constructor (path) { - super() - this.info = { - code: 'EISDIR', - message: 'is a directory', - path, - syscall: 'rm', - errno: errnos.EISDIR, - } - this.name = 'SystemError' - this.code = 'ERR_FS_EISDIR' - this.errno = errnos.EISDIR - this.syscall = 'rm' - this.path = path - this.message = `Path is a directory: ${this.syscall} returned ` + - `${this.info.code} (is a directory) ${path}` - } - - toString () { - return `${this.name} [${this.code}]: ${this.message}` - } -} - -class ENOTDIR extends Error { - constructor (path) { - super() - this.name = 'Error' - this.code = 'ENOTDIR' - this.errno = errnos.ENOTDIR - this.syscall = 'rmdir' - this.path = path - this.message = `not a directory, ${this.syscall} '${this.path}'` - } - - toString () { - return `${this.name}: ${this.code}: ${this.message}` - } -} - -// force is passed separately here because we respect it for the first entry -// into rimraf only, any further calls that are spawned as a result (i.e. to -// delete content within the target) will ignore ENOENT errors -const rimraf = async (path, options, isTop = false) => { - const force = isTop ? options.force : true - const stat = await fs.lstat(path) - .catch((err) => { - // we only ignore ENOENT if we're forcing this call - if (err.code === 'ENOENT' && force) { - return - } - - if (isWindows && err.code === 'EPERM') { - return fixEPERM(path, options, err, isTop) - } - - throw err - }) - - // no stat object here means either lstat threw an ENOENT, or lstat threw - // an EPERM and the fixPERM function took care of things. either way, we're - // already done, so return early - if (!stat) { - return - } - - if (stat.isDirectory()) { - return rmdir(path, options, null, isTop) - } - - return fs.unlink(path) - .catch((err) => { - if (err.code === 'ENOENT' && force) { - return - } - - if (err.code === 'EISDIR') { - return rmdir(path, options, err, isTop) - } - - if (err.code === 'EPERM') { - // in windows, we handle this through fixEPERM which will also try to - // delete things again. everywhere else since deleting the target as a - // file didn't work we go ahead and try to delete it as a directory - return isWindows - ? fixEPERM(path, options, err, isTop) - : rmdir(path, options, err, isTop) - } - - throw err - }) -} - -const fixEPERM = async (path, options, originalErr, isTop) => { - const force = isTop ? options.force : true - const targetMissing = await fs.chmod(path, 0o666) - .catch((err) => { - if (err.code === 'ENOENT' && force) { - return true - } - - throw originalErr - }) - - // got an ENOENT above, return now. no file = no problem - if (targetMissing) { - return - } - - // this function does its own lstat rather than calling rimraf again to avoid - // infinite recursion for a repeating EPERM - const stat = await fs.lstat(path) - .catch((err) => { - if (err.code === 'ENOENT' && force) { - return - } - - throw originalErr - }) - - if (!stat) { - return - } - - if (stat.isDirectory()) { - return rmdir(path, options, originalErr, isTop) - } - - return fs.unlink(path) -} - -const rmdir = async (path, options, originalErr, isTop) => { - if (!options.recursive && isTop) { - throw originalErr || new ERR_FS_EISDIR(path) - } - const force = isTop ? options.force : true - - return fs.rmdir(path) - .catch(async (err) => { - // in Windows, calling rmdir on a file path will fail with ENOENT rather - // than ENOTDIR. to determine if that's what happened, we have to do - // another lstat on the path. if the path isn't actually gone, we throw - // away the ENOENT and replace it with our own ENOTDIR - if (isWindows && err.code === 'ENOENT') { - const stillExists = await fs.lstat(path).then(() => true, () => false) - if (stillExists) { - err = new ENOTDIR(path) - } - } - - // not there, not a problem - if (err.code === 'ENOENT' && force) { - return - } - - // we may not have originalErr if lstat tells us our target is a - // directory but that changes before we actually remove it, so - // only throw it here if it's set - if (originalErr && err.code === 'ENOTDIR') { - throw originalErr - } - - // the directory isn't empty, remove the contents and try again - if (notEmptyCodes.has(err.code)) { - const files = await fs.readdir(path) - await Promise.all(files.map((file) => { - const target = join(path, file) - return rimraf(target, options) - })) - return fs.rmdir(path) - } - - throw err - }) -} - -const rm = async (path, opts) => { - const options = { ...defaultOptions, ...opts } - let retries = 0 - - const errHandler = async (err) => { - if (retryCodes.has(err.code) && ++retries < options.maxRetries) { - const delay = retries * options.retryDelay - await promiseTimeout(delay) - return rimraf(path, options, true).catch(errHandler) - } - - throw err - } - - return rimraf(path, options, true).catch(errHandler) -} - -const promiseTimeout = (ms) => new Promise((r) => setTimeout(r, ms)) - -module.exports = rm diff --git a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/with-owner-sync.js b/node_modules/node-gyp/node_modules/@npmcli/fs/lib/with-owner-sync.js deleted file mode 100644 index 3597d1c810475..0000000000000 --- a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/with-owner-sync.js +++ /dev/null @@ -1,21 +0,0 @@ -const getOptions = require('./common/get-options.js') -const owner = require('./common/owner-sync.js') - -const withOwnerSync = (path, fn, opts) => { - const options = getOptions(opts, { - copy: ['owner'], - }) - - const { uid, gid } = owner.validate(path, options.owner) - - const result = fn({ uid, gid }) - - owner.update(path, uid, gid) - if (typeof result === 'string') { - owner.update(result, uid, gid) - } - - return result -} - -module.exports = withOwnerSync diff --git a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/with-owner.js b/node_modules/node-gyp/node_modules/@npmcli/fs/lib/with-owner.js deleted file mode 100644 index a679102883dbb..0000000000000 --- a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/with-owner.js +++ /dev/null @@ -1,21 +0,0 @@ -const getOptions = require('./common/get-options.js') -const owner = require('./common/owner.js') - -const withOwner = async (path, fn, opts) => { - const options = getOptions(opts, { - copy: ['owner'], - }) - - const { uid, gid } = await owner.validate(path, options.owner) - - const result = await fn({ uid, gid }) - - await Promise.all([ - owner.update(path, uid, gid), - typeof result === 'string' ? owner.update(result, uid, gid) : null, - ]) - - return result -} - -module.exports = withOwner diff --git a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/with-temp-dir.js b/node_modules/node-gyp/node_modules/@npmcli/fs/lib/with-temp-dir.js deleted file mode 100644 index 81db59dd054b4..0000000000000 --- a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/with-temp-dir.js +++ /dev/null @@ -1,41 +0,0 @@ -const { join, sep } = require('path') - -const getOptions = require('./common/get-options.js') -const mkdir = require('./mkdir.js') -const mkdtemp = require('./mkdtemp.js') -const rm = require('./rm/index.js') - -// create a temp directory, ensure its permissions match its parent, then call -// the supplied function passing it the path to the directory. clean up after -// the function finishes, whether it throws or not -const withTempDir = async (root, fn, opts) => { - const options = getOptions(opts, { - copy: ['tmpPrefix'], - }) - // create the directory, and fix its ownership - await mkdir(root, { recursive: true, owner: 'inherit' }) - - const target = await mkdtemp(join(`${root}${sep}`, options.tmpPrefix || ''), { owner: 'inherit' }) - let err - let result - - try { - result = await fn(target) - } catch (_err) { - err = _err - } - - try { - await rm(target, { force: true, recursive: true }) - } catch { - // ignore errors - } - - if (err) { - throw err - } - - return result -} - -module.exports = withTempDir diff --git a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/write-file.js b/node_modules/node-gyp/node_modules/@npmcli/fs/lib/write-file.js deleted file mode 100644 index ff900571a1f28..0000000000000 --- a/node_modules/node-gyp/node_modules/@npmcli/fs/lib/write-file.js +++ /dev/null @@ -1,14 +0,0 @@ -const fs = require('./fs.js') -const getOptions = require('./common/get-options.js') -const withOwner = require('./with-owner.js') - -const writeFile = async (file, data, opts) => { - const options = getOptions(opts, { - copy: ['encoding', 'mode', 'flag', 'signal'], - wrap: 'encoding', - }) - - return withOwner(file, () => fs.writeFile(file, data, options), opts) -} - -module.exports = writeFile diff --git a/node_modules/node-gyp/node_modules/@npmcli/fs/package.json b/node_modules/node-gyp/node_modules/@npmcli/fs/package.json deleted file mode 100644 index 1512fd6e4b0ac..0000000000000 --- a/node_modules/node-gyp/node_modules/@npmcli/fs/package.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "name": "@npmcli/fs", - "version": "2.1.2", - "description": "filesystem utilities for the npm cli", - "main": "lib/index.js", - "files": [ - "bin/", - "lib/" - ], - "scripts": { - "preversion": "npm test", - "postversion": "npm publish", - "prepublishOnly": "git push origin --follow-tags", - "snap": "tap", - "test": "tap", - "npmclilint": "npmcli-lint", - "lint": "eslint \"**/*.js\"", - "lintfix": "npm run lint -- --fix", - "posttest": "npm run lint", - "postsnap": "npm run lintfix --", - "postlint": "template-oss-check", - "template-oss-apply": "template-oss-apply --force" - }, - "repository": { - "type": "git", - "url": "https://github.com/npm/fs.git" - }, - "keywords": [ - "npm", - "oss" - ], - "author": "GitHub Inc.", - "license": "ISC", - "devDependencies": { - "@npmcli/eslint-config": "^3.0.1", - "@npmcli/template-oss": "3.5.0", - "tap": "^16.0.1" - }, - "dependencies": { - "@gar/promisify": "^1.1.3", - "semver": "^7.3.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - }, - "templateOSS": { - "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "3.5.0" - } -} diff --git a/node_modules/node-gyp/node_modules/cacache/LICENSE.md b/node_modules/node-gyp/node_modules/cacache/LICENSE.md deleted file mode 100644 index 8d28acf866d93..0000000000000 --- a/node_modules/node-gyp/node_modules/cacache/LICENSE.md +++ /dev/null @@ -1,16 +0,0 @@ -ISC License - -Copyright (c) npm, Inc. - -Permission to use, copy, modify, and/or distribute this software for -any purpose with or without fee is hereby granted, provided that the -above copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE COPYRIGHT HOLDER DISCLAIMS -ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE -COPYRIGHT HOLDER 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/node-gyp/node_modules/cacache/lib/content/path.js b/node_modules/node-gyp/node_modules/cacache/lib/content/path.js deleted file mode 100644 index ad5a76a4f73f2..0000000000000 --- a/node_modules/node-gyp/node_modules/cacache/lib/content/path.js +++ /dev/null @@ -1,29 +0,0 @@ -'use strict' - -const contentVer = require('../../package.json')['cache-version'].content -const hashToSegments = require('../util/hash-to-segments') -const path = require('path') -const ssri = require('ssri') - -// Current format of content file path: -// -// sha512-BaSE64Hex= -> -// ~/.my-cache/content-v2/sha512/ba/da/55deadbeefc0ffee -// -module.exports = contentPath - -function contentPath (cache, integrity) { - const sri = ssri.parse(integrity, { single: true }) - // contentPath is the *strongest* algo given - return path.join( - contentDir(cache), - sri.algorithm, - ...hashToSegments(sri.hexDigest()) - ) -} - -module.exports.contentDir = contentDir - -function contentDir (cache) { - return path.join(cache, `content-v${contentVer}`) -} diff --git a/node_modules/node-gyp/node_modules/cacache/lib/content/read.js b/node_modules/node-gyp/node_modules/cacache/lib/content/read.js deleted file mode 100644 index 7c20c75257b4f..0000000000000 --- a/node_modules/node-gyp/node_modules/cacache/lib/content/read.js +++ /dev/null @@ -1,241 +0,0 @@ -'use strict' - -const fs = require('@npmcli/fs') -const fsm = require('fs-minipass') -const ssri = require('ssri') -const contentPath = require('./path') -const Pipeline = require('minipass-pipeline') - -module.exports = read - -const MAX_SINGLE_READ_SIZE = 64 * 1024 * 1024 -async function read (cache, integrity, opts = {}) { - const { size } = opts - const { stat, cpath, sri } = await withContentSri(cache, integrity, async (cpath, sri) => { - // get size - const stat = await fs.stat(cpath) - return { stat, cpath, sri } - }) - if (typeof size === 'number' && stat.size !== size) { - throw sizeError(size, stat.size) - } - - if (stat.size > MAX_SINGLE_READ_SIZE) { - return readPipeline(cpath, stat.size, sri, new Pipeline()).concat() - } - - const data = await fs.readFile(cpath, { encoding: null }) - if (!ssri.checkData(data, sri)) { - throw integrityError(sri, cpath) - } - - return data -} - -const readPipeline = (cpath, size, sri, stream) => { - stream.push( - new fsm.ReadStream(cpath, { - size, - readSize: MAX_SINGLE_READ_SIZE, - }), - ssri.integrityStream({ - integrity: sri, - size, - }) - ) - return stream -} - -module.exports.sync = readSync - -function readSync (cache, integrity, opts = {}) { - const { size } = opts - return withContentSriSync(cache, integrity, (cpath, sri) => { - const data = fs.readFileSync(cpath, { encoding: null }) - if (typeof size === 'number' && size !== data.length) { - throw sizeError(size, data.length) - } - - if (ssri.checkData(data, sri)) { - return data - } - - throw integrityError(sri, cpath) - }) -} - -module.exports.stream = readStream -module.exports.readStream = readStream - -function readStream (cache, integrity, opts = {}) { - const { size } = opts - const stream = new Pipeline() - // Set all this up to run on the stream and then just return the stream - Promise.resolve().then(async () => { - const { stat, cpath, sri } = await withContentSri(cache, integrity, async (cpath, sri) => { - // just stat to ensure it exists - const stat = await fs.stat(cpath) - return { stat, cpath, sri } - }) - if (typeof size === 'number' && size !== stat.size) { - return stream.emit('error', sizeError(size, stat.size)) - } - - return readPipeline(cpath, stat.size, sri, stream) - }).catch(err => stream.emit('error', err)) - - return stream -} - -module.exports.copy = copy -module.exports.copy.sync = copySync - -function copy (cache, integrity, dest) { - return withContentSri(cache, integrity, (cpath, sri) => { - return fs.copyFile(cpath, dest) - }) -} - -function copySync (cache, integrity, dest) { - return withContentSriSync(cache, integrity, (cpath, sri) => { - return fs.copyFileSync(cpath, dest) - }) -} - -module.exports.hasContent = hasContent - -async function hasContent (cache, integrity) { - if (!integrity) { - return false - } - - try { - return await withContentSri(cache, integrity, async (cpath, sri) => { - const stat = await fs.stat(cpath) - return { size: stat.size, sri, stat } - }) - } catch (err) { - if (err.code === 'ENOENT') { - return false - } - - if (err.code === 'EPERM') { - /* istanbul ignore else */ - if (process.platform !== 'win32') { - throw err - } else { - return false - } - } - } -} - -module.exports.hasContent.sync = hasContentSync - -function hasContentSync (cache, integrity) { - if (!integrity) { - return false - } - - return withContentSriSync(cache, integrity, (cpath, sri) => { - try { - const stat = fs.statSync(cpath) - return { size: stat.size, sri, stat } - } catch (err) { - if (err.code === 'ENOENT') { - return false - } - - if (err.code === 'EPERM') { - /* istanbul ignore else */ - if (process.platform !== 'win32') { - throw err - } else { - return false - } - } - } - }) -} - -async function withContentSri (cache, integrity, fn) { - const sri = ssri.parse(integrity) - // If `integrity` has multiple entries, pick the first digest - // with available local data. - const algo = sri.pickAlgorithm() - const digests = sri[algo] - - if (digests.length <= 1) { - const cpath = contentPath(cache, digests[0]) - return fn(cpath, digests[0]) - } else { - // Can't use race here because a generic error can happen before - // a ENOENT error, and can happen before a valid result - const results = await Promise.all(digests.map(async (meta) => { - try { - return await withContentSri(cache, meta, fn) - } catch (err) { - if (err.code === 'ENOENT') { - return Object.assign( - new Error('No matching content found for ' + sri.toString()), - { code: 'ENOENT' } - ) - } - return err - } - })) - // Return the first non error if it is found - const result = results.find((r) => !(r instanceof Error)) - if (result) { - return result - } - - // Throw the No matching content found error - const enoentError = results.find((r) => r.code === 'ENOENT') - if (enoentError) { - throw enoentError - } - - // Throw generic error - throw results.find((r) => r instanceof Error) - } -} - -function withContentSriSync (cache, integrity, fn) { - const sri = ssri.parse(integrity) - // If `integrity` has multiple entries, pick the first digest - // with available local data. - const algo = sri.pickAlgorithm() - const digests = sri[algo] - if (digests.length <= 1) { - const cpath = contentPath(cache, digests[0]) - return fn(cpath, digests[0]) - } else { - let lastErr = null - for (const meta of digests) { - try { - return withContentSriSync(cache, meta, fn) - } catch (err) { - lastErr = err - } - } - throw lastErr - } -} - -function sizeError (expected, found) { - /* eslint-disable-next-line max-len */ - const err = new Error(`Bad data size: expected inserted data to be ${expected} bytes, but got ${found} instead`) - err.expected = expected - err.found = found - err.code = 'EBADSIZE' - return err -} - -function integrityError (sri, path) { - const err = new Error(`Integrity verification failed for ${sri} (${path})`) - err.code = 'EINTEGRITY' - err.sri = sri - err.path = path - return err -} diff --git a/node_modules/node-gyp/node_modules/cacache/lib/content/rm.js b/node_modules/node-gyp/node_modules/cacache/lib/content/rm.js deleted file mode 100644 index f7333053b393f..0000000000000 --- a/node_modules/node-gyp/node_modules/cacache/lib/content/rm.js +++ /dev/null @@ -1,20 +0,0 @@ -'use strict' - -const util = require('util') - -const contentPath = require('./path') -const { hasContent } = require('./read') -const rimraf = util.promisify(require('rimraf')) - -module.exports = rm - -async function rm (cache, integrity) { - const content = await hasContent(cache, integrity) - // ~pretty~ sure we can't end up with a content lacking sri, but be safe - if (content && content.sri) { - await rimraf(contentPath(cache, content.sri)) - return true - } else { - return false - } -} diff --git a/node_modules/node-gyp/node_modules/cacache/lib/content/write.js b/node_modules/node-gyp/node_modules/cacache/lib/content/write.js deleted file mode 100644 index 0e8c0f4936064..0000000000000 --- a/node_modules/node-gyp/node_modules/cacache/lib/content/write.js +++ /dev/null @@ -1,189 +0,0 @@ -'use strict' - -const events = require('events') -const util = require('util') - -const contentPath = require('./path') -const fixOwner = require('../util/fix-owner') -const fs = require('@npmcli/fs') -const moveFile = require('../util/move-file') -const Minipass = require('minipass') -const Pipeline = require('minipass-pipeline') -const Flush = require('minipass-flush') -const path = require('path') -const rimraf = util.promisify(require('rimraf')) -const ssri = require('ssri') -const uniqueFilename = require('unique-filename') -const fsm = require('fs-minipass') - -module.exports = write - -async function write (cache, data, opts = {}) { - const { algorithms, size, integrity } = opts - if (algorithms && algorithms.length > 1) { - throw new Error('opts.algorithms only supports a single algorithm for now') - } - - if (typeof size === 'number' && data.length !== size) { - throw sizeError(size, data.length) - } - - const sri = ssri.fromData(data, algorithms ? { algorithms } : {}) - if (integrity && !ssri.checkData(data, integrity, opts)) { - throw checksumError(integrity, sri) - } - - const tmp = await makeTmp(cache, opts) - try { - await fs.writeFile(tmp.target, data, { flag: 'wx' }) - await moveToDestination(tmp, cache, sri, opts) - return { integrity: sri, size: data.length } - } finally { - if (!tmp.moved) { - await rimraf(tmp.target) - } - } -} - -module.exports.stream = writeStream - -// writes proxied to the 'inputStream' that is passed to the Promise -// 'end' is deferred until content is handled. -class CacacheWriteStream extends Flush { - constructor (cache, opts) { - super() - this.opts = opts - this.cache = cache - this.inputStream = new Minipass() - this.inputStream.on('error', er => this.emit('error', er)) - this.inputStream.on('drain', () => this.emit('drain')) - this.handleContentP = null - } - - write (chunk, encoding, cb) { - if (!this.handleContentP) { - this.handleContentP = handleContent( - this.inputStream, - this.cache, - this.opts - ) - } - return this.inputStream.write(chunk, encoding, cb) - } - - flush (cb) { - this.inputStream.end(() => { - if (!this.handleContentP) { - const e = new Error('Cache input stream was empty') - e.code = 'ENODATA' - // empty streams are probably emitting end right away. - // defer this one tick by rejecting a promise on it. - return Promise.reject(e).catch(cb) - } - // eslint-disable-next-line promise/catch-or-return - this.handleContentP.then( - (res) => { - res.integrity && this.emit('integrity', res.integrity) - // eslint-disable-next-line promise/always-return - res.size !== null && this.emit('size', res.size) - cb() - }, - (er) => cb(er) - ) - }) - } -} - -function writeStream (cache, opts = {}) { - return new CacacheWriteStream(cache, opts) -} - -async function handleContent (inputStream, cache, opts) { - const tmp = await makeTmp(cache, opts) - try { - const res = await pipeToTmp(inputStream, cache, tmp.target, opts) - await moveToDestination( - tmp, - cache, - res.integrity, - opts - ) - return res - } finally { - if (!tmp.moved) { - await rimraf(tmp.target) - } - } -} - -async function pipeToTmp (inputStream, cache, tmpTarget, opts) { - const outStream = new fsm.WriteStream(tmpTarget, { - flags: 'wx', - }) - - if (opts.integrityEmitter) { - // we need to create these all simultaneously since they can fire in any order - const [integrity, size] = await Promise.all([ - events.once(opts.integrityEmitter, 'integrity').then(res => res[0]), - events.once(opts.integrityEmitter, 'size').then(res => res[0]), - new Pipeline(inputStream, outStream).promise(), - ]) - return { integrity, size } - } - - let integrity - let size - const hashStream = ssri.integrityStream({ - integrity: opts.integrity, - algorithms: opts.algorithms, - size: opts.size, - }) - hashStream.on('integrity', i => { - integrity = i - }) - hashStream.on('size', s => { - size = s - }) - - const pipeline = new Pipeline(inputStream, hashStream, outStream) - await pipeline.promise() - return { integrity, size } -} - -async function makeTmp (cache, opts) { - const tmpTarget = uniqueFilename(path.join(cache, 'tmp'), opts.tmpPrefix) - await fixOwner.mkdirfix(cache, path.dirname(tmpTarget)) - return { - target: tmpTarget, - moved: false, - } -} - -async function moveToDestination (tmp, cache, sri, opts) { - const destination = contentPath(cache, sri) - const destDir = path.dirname(destination) - - await fixOwner.mkdirfix(cache, destDir) - await moveFile(tmp.target, destination) - tmp.moved = true - await fixOwner.chownr(cache, destination) -} - -function sizeError (expected, found) { - /* eslint-disable-next-line max-len */ - const err = new Error(`Bad data size: expected inserted data to be ${expected} bytes, but got ${found} instead`) - err.expected = expected - err.found = found - err.code = 'EBADSIZE' - return err -} - -function checksumError (expected, found) { - const err = new Error(`Integrity check failed: - Wanted: ${expected} - Found: ${found}`) - err.code = 'EINTEGRITY' - err.expected = expected - err.found = found - return err -} diff --git a/node_modules/node-gyp/node_modules/cacache/lib/entry-index.js b/node_modules/node-gyp/node_modules/cacache/lib/entry-index.js deleted file mode 100644 index 1dc73a93f6b29..0000000000000 --- a/node_modules/node-gyp/node_modules/cacache/lib/entry-index.js +++ /dev/null @@ -1,404 +0,0 @@ -'use strict' - -const util = require('util') -const crypto = require('crypto') -const fs = require('@npmcli/fs') -const Minipass = require('minipass') -const path = require('path') -const ssri = require('ssri') -const uniqueFilename = require('unique-filename') - -const contentPath = require('./content/path') -const fixOwner = require('./util/fix-owner') -const hashToSegments = require('./util/hash-to-segments') -const indexV = require('../package.json')['cache-version'].index -const moveFile = require('@npmcli/move-file') -const _rimraf = require('rimraf') -const rimraf = util.promisify(_rimraf) -rimraf.sync = _rimraf.sync - -module.exports.NotFoundError = class NotFoundError extends Error { - constructor (cache, key) { - super(`No cache entry for ${key} found in ${cache}`) - this.code = 'ENOENT' - this.cache = cache - this.key = key - } -} - -module.exports.compact = compact - -async function compact (cache, key, matchFn, opts = {}) { - const bucket = bucketPath(cache, key) - const entries = await bucketEntries(bucket) - const newEntries = [] - // we loop backwards because the bottom-most result is the newest - // since we add new entries with appendFile - for (let i = entries.length - 1; i >= 0; --i) { - const entry = entries[i] - // a null integrity could mean either a delete was appended - // or the user has simply stored an index that does not map - // to any content. we determine if the user wants to keep the - // null integrity based on the validateEntry function passed in options. - // if the integrity is null and no validateEntry is provided, we break - // as we consider the null integrity to be a deletion of everything - // that came before it. - if (entry.integrity === null && !opts.validateEntry) { - break - } - - // if this entry is valid, and it is either the first entry or - // the newEntries array doesn't already include an entry that - // matches this one based on the provided matchFn, then we add - // it to the beginning of our list - if ((!opts.validateEntry || opts.validateEntry(entry) === true) && - (newEntries.length === 0 || - !newEntries.find((oldEntry) => matchFn(oldEntry, entry)))) { - newEntries.unshift(entry) - } - } - - const newIndex = '\n' + newEntries.map((entry) => { - const stringified = JSON.stringify(entry) - const hash = hashEntry(stringified) - return `${hash}\t${stringified}` - }).join('\n') - - const setup = async () => { - const target = uniqueFilename(path.join(cache, 'tmp'), opts.tmpPrefix) - await fixOwner.mkdirfix(cache, path.dirname(target)) - return { - target, - moved: false, - } - } - - const teardown = async (tmp) => { - if (!tmp.moved) { - return rimraf(tmp.target) - } - } - - const write = async (tmp) => { - await fs.writeFile(tmp.target, newIndex, { flag: 'wx' }) - await fixOwner.mkdirfix(cache, path.dirname(bucket)) - // we use @npmcli/move-file directly here because we - // want to overwrite the existing file - await moveFile(tmp.target, bucket) - tmp.moved = true - try { - await fixOwner.chownr(cache, bucket) - } catch (err) { - if (err.code !== 'ENOENT') { - throw err - } - } - } - - // write the file atomically - const tmp = await setup() - try { - await write(tmp) - } finally { - await teardown(tmp) - } - - // we reverse the list we generated such that the newest - // entries come first in order to make looping through them easier - // the true passed to formatEntry tells it to keep null - // integrity values, if they made it this far it's because - // validateEntry returned true, and as such we should return it - return newEntries.reverse().map((entry) => formatEntry(cache, entry, true)) -} - -module.exports.insert = insert - -async function insert (cache, key, integrity, opts = {}) { - const { metadata, size } = opts - const bucket = bucketPath(cache, key) - const entry = { - key, - integrity: integrity && ssri.stringify(integrity), - time: Date.now(), - size, - metadata, - } - try { - await fixOwner.mkdirfix(cache, path.dirname(bucket)) - const stringified = JSON.stringify(entry) - // NOTE - Cleverness ahoy! - // - // This works because it's tremendously unlikely for an entry to corrupt - // another while still preserving the string length of the JSON in - // question. So, we just slap the length in there and verify it on read. - // - // Thanks to @isaacs for the whiteboarding session that ended up with - // this. - await fs.appendFile(bucket, `\n${hashEntry(stringified)}\t${stringified}`) - await fixOwner.chownr(cache, bucket) - } catch (err) { - if (err.code === 'ENOENT') { - return undefined - } - - throw err - // There's a class of race conditions that happen when things get deleted - // during fixOwner, or between the two mkdirfix/chownr calls. - // - // It's perfectly fine to just not bother in those cases and lie - // that the index entry was written. Because it's a cache. - } - return formatEntry(cache, entry) -} - -module.exports.insert.sync = insertSync - -function insertSync (cache, key, integrity, opts = {}) { - const { metadata, size } = opts - const bucket = bucketPath(cache, key) - const entry = { - key, - integrity: integrity && ssri.stringify(integrity), - time: Date.now(), - size, - metadata, - } - fixOwner.mkdirfix.sync(cache, path.dirname(bucket)) - const stringified = JSON.stringify(entry) - fs.appendFileSync(bucket, `\n${hashEntry(stringified)}\t${stringified}`) - try { - fixOwner.chownr.sync(cache, bucket) - } catch (err) { - if (err.code !== 'ENOENT') { - throw err - } - } - return formatEntry(cache, entry) -} - -module.exports.find = find - -async function find (cache, key) { - const bucket = bucketPath(cache, key) - try { - const entries = await bucketEntries(bucket) - return entries.reduce((latest, next) => { - if (next && next.key === key) { - return formatEntry(cache, next) - } else { - return latest - } - }, null) - } catch (err) { - if (err.code === 'ENOENT') { - return null - } else { - throw err - } - } -} - -module.exports.find.sync = findSync - -function findSync (cache, key) { - const bucket = bucketPath(cache, key) - try { - return bucketEntriesSync(bucket).reduce((latest, next) => { - if (next && next.key === key) { - return formatEntry(cache, next) - } else { - return latest - } - }, null) - } catch (err) { - if (err.code === 'ENOENT') { - return null - } else { - throw err - } - } -} - -module.exports.delete = del - -function del (cache, key, opts = {}) { - if (!opts.removeFully) { - return insert(cache, key, null, opts) - } - - const bucket = bucketPath(cache, key) - return rimraf(bucket) -} - -module.exports.delete.sync = delSync - -function delSync (cache, key, opts = {}) { - if (!opts.removeFully) { - return insertSync(cache, key, null, opts) - } - - const bucket = bucketPath(cache, key) - return rimraf.sync(bucket) -} - -module.exports.lsStream = lsStream - -function lsStream (cache) { - const indexDir = bucketDir(cache) - const stream = new Minipass({ objectMode: true }) - - // Set all this up to run on the stream and then just return the stream - Promise.resolve().then(async () => { - const buckets = await readdirOrEmpty(indexDir) - await Promise.all(buckets.map(async (bucket) => { - const bucketPath = path.join(indexDir, bucket) - const subbuckets = await readdirOrEmpty(bucketPath) - await Promise.all(subbuckets.map(async (subbucket) => { - const subbucketPath = path.join(bucketPath, subbucket) - - // "/cachename//./*" - const subbucketEntries = await readdirOrEmpty(subbucketPath) - await Promise.all(subbucketEntries.map(async (entry) => { - const entryPath = path.join(subbucketPath, entry) - try { - const entries = await bucketEntries(entryPath) - // using a Map here prevents duplicate keys from showing up - // twice, I guess? - const reduced = entries.reduce((acc, entry) => { - acc.set(entry.key, entry) - return acc - }, new Map()) - // reduced is a map of key => entry - for (const entry of reduced.values()) { - const formatted = formatEntry(cache, entry) - if (formatted) { - stream.write(formatted) - } - } - } catch (err) { - if (err.code === 'ENOENT') { - return undefined - } - throw err - } - })) - })) - })) - stream.end() - return stream - }).catch(err => stream.emit('error', err)) - - return stream -} - -module.exports.ls = ls - -async function ls (cache) { - const entries = await lsStream(cache).collect() - return entries.reduce((acc, xs) => { - acc[xs.key] = xs - return acc - }, {}) -} - -module.exports.bucketEntries = bucketEntries - -async function bucketEntries (bucket, filter) { - const data = await fs.readFile(bucket, 'utf8') - return _bucketEntries(data, filter) -} - -module.exports.bucketEntries.sync = bucketEntriesSync - -function bucketEntriesSync (bucket, filter) { - const data = fs.readFileSync(bucket, 'utf8') - return _bucketEntries(data, filter) -} - -function _bucketEntries (data, filter) { - const entries = [] - data.split('\n').forEach((entry) => { - if (!entry) { - return - } - - const pieces = entry.split('\t') - if (!pieces[1] || hashEntry(pieces[1]) !== pieces[0]) { - // Hash is no good! Corruption or malice? Doesn't matter! - // EJECT EJECT - return - } - let obj - try { - obj = JSON.parse(pieces[1]) - } catch (e) { - // Entry is corrupted! - return - } - if (obj) { - entries.push(obj) - } - }) - return entries -} - -module.exports.bucketDir = bucketDir - -function bucketDir (cache) { - return path.join(cache, `index-v${indexV}`) -} - -module.exports.bucketPath = bucketPath - -function bucketPath (cache, key) { - const hashed = hashKey(key) - return path.join.apply( - path, - [bucketDir(cache)].concat(hashToSegments(hashed)) - ) -} - -module.exports.hashKey = hashKey - -function hashKey (key) { - return hash(key, 'sha256') -} - -module.exports.hashEntry = hashEntry - -function hashEntry (str) { - return hash(str, 'sha1') -} - -function hash (str, digest) { - return crypto - .createHash(digest) - .update(str) - .digest('hex') -} - -function formatEntry (cache, entry, keepAll) { - // Treat null digests as deletions. They'll shadow any previous entries. - if (!entry.integrity && !keepAll) { - return null - } - - return { - key: entry.key, - integrity: entry.integrity, - path: entry.integrity ? contentPath(cache, entry.integrity) : undefined, - size: entry.size, - time: entry.time, - metadata: entry.metadata, - } -} - -function readdirOrEmpty (dir) { - return fs.readdir(dir).catch((err) => { - if (err.code === 'ENOENT' || err.code === 'ENOTDIR') { - return [] - } - - throw err - }) -} diff --git a/node_modules/node-gyp/node_modules/cacache/lib/get.js b/node_modules/node-gyp/node_modules/cacache/lib/get.js deleted file mode 100644 index 254b4ecc38b57..0000000000000 --- a/node_modules/node-gyp/node_modules/cacache/lib/get.js +++ /dev/null @@ -1,225 +0,0 @@ -'use strict' - -const Collect = require('minipass-collect') -const Minipass = require('minipass') -const Pipeline = require('minipass-pipeline') - -const index = require('./entry-index') -const memo = require('./memoization') -const read = require('./content/read') - -async function getData (cache, key, opts = {}) { - const { integrity, memoize, size } = opts - const memoized = memo.get(cache, key, opts) - if (memoized && memoize !== false) { - return { - metadata: memoized.entry.metadata, - data: memoized.data, - integrity: memoized.entry.integrity, - size: memoized.entry.size, - } - } - - const entry = await index.find(cache, key, opts) - if (!entry) { - throw new index.NotFoundError(cache, key) - } - const data = await read(cache, entry.integrity, { integrity, size }) - if (memoize) { - memo.put(cache, entry, data, opts) - } - - return { - data, - metadata: entry.metadata, - size: entry.size, - integrity: entry.integrity, - } -} -module.exports = getData - -async function getDataByDigest (cache, key, opts = {}) { - const { integrity, memoize, size } = opts - const memoized = memo.get.byDigest(cache, key, opts) - if (memoized && memoize !== false) { - return memoized - } - - const res = await read(cache, key, { integrity, size }) - if (memoize) { - memo.put.byDigest(cache, key, res, opts) - } - return res -} -module.exports.byDigest = getDataByDigest - -function getDataSync (cache, key, opts = {}) { - const { integrity, memoize, size } = opts - const memoized = memo.get(cache, key, opts) - - if (memoized && memoize !== false) { - return { - metadata: memoized.entry.metadata, - data: memoized.data, - integrity: memoized.entry.integrity, - size: memoized.entry.size, - } - } - const entry = index.find.sync(cache, key, opts) - if (!entry) { - throw new index.NotFoundError(cache, key) - } - const data = read.sync(cache, entry.integrity, { - integrity: integrity, - size: size, - }) - const res = { - metadata: entry.metadata, - data: data, - size: entry.size, - integrity: entry.integrity, - } - if (memoize) { - memo.put(cache, entry, res.data, opts) - } - - return res -} - -module.exports.sync = getDataSync - -function getDataByDigestSync (cache, digest, opts = {}) { - const { integrity, memoize, size } = opts - const memoized = memo.get.byDigest(cache, digest, opts) - - if (memoized && memoize !== false) { - return memoized - } - - const res = read.sync(cache, digest, { - integrity: integrity, - size: size, - }) - if (memoize) { - memo.put.byDigest(cache, digest, res, opts) - } - - return res -} -module.exports.sync.byDigest = getDataByDigestSync - -const getMemoizedStream = (memoized) => { - const stream = new Minipass() - stream.on('newListener', function (ev, cb) { - ev === 'metadata' && cb(memoized.entry.metadata) - ev === 'integrity' && cb(memoized.entry.integrity) - ev === 'size' && cb(memoized.entry.size) - }) - stream.end(memoized.data) - return stream -} - -function getStream (cache, key, opts = {}) { - const { memoize, size } = opts - const memoized = memo.get(cache, key, opts) - if (memoized && memoize !== false) { - return getMemoizedStream(memoized) - } - - const stream = new Pipeline() - // Set all this up to run on the stream and then just return the stream - Promise.resolve().then(async () => { - const entry = await index.find(cache, key) - if (!entry) { - throw new index.NotFoundError(cache, key) - } - - stream.emit('metadata', entry.metadata) - stream.emit('integrity', entry.integrity) - stream.emit('size', entry.size) - stream.on('newListener', function (ev, cb) { - ev === 'metadata' && cb(entry.metadata) - ev === 'integrity' && cb(entry.integrity) - ev === 'size' && cb(entry.size) - }) - - const src = read.readStream( - cache, - entry.integrity, - { ...opts, size: typeof size !== 'number' ? entry.size : size } - ) - - if (memoize) { - const memoStream = new Collect.PassThrough() - memoStream.on('collect', data => memo.put(cache, entry, data, opts)) - stream.unshift(memoStream) - } - stream.unshift(src) - return stream - }).catch((err) => stream.emit('error', err)) - - return stream -} - -module.exports.stream = getStream - -function getStreamDigest (cache, integrity, opts = {}) { - const { memoize } = opts - const memoized = memo.get.byDigest(cache, integrity, opts) - if (memoized && memoize !== false) { - const stream = new Minipass() - stream.end(memoized) - return stream - } else { - const stream = read.readStream(cache, integrity, opts) - if (!memoize) { - return stream - } - - const memoStream = new Collect.PassThrough() - memoStream.on('collect', data => memo.put.byDigest( - cache, - integrity, - data, - opts - )) - return new Pipeline(stream, memoStream) - } -} - -module.exports.stream.byDigest = getStreamDigest - -function info (cache, key, opts = {}) { - const { memoize } = opts - const memoized = memo.get(cache, key, opts) - if (memoized && memoize !== false) { - return Promise.resolve(memoized.entry) - } else { - return index.find(cache, key) - } -} -module.exports.info = info - -async function copy (cache, key, dest, opts = {}) { - const entry = await index.find(cache, key, opts) - if (!entry) { - throw new index.NotFoundError(cache, key) - } - await read.copy(cache, entry.integrity, dest, opts) - return { - metadata: entry.metadata, - size: entry.size, - integrity: entry.integrity, - } -} - -module.exports.copy = copy - -async function copyByDigest (cache, key, dest, opts = {}) { - await read.copy(cache, key, dest, opts) - return key -} - -module.exports.copy.byDigest = copyByDigest - -module.exports.hasContent = read.hasContent diff --git a/node_modules/node-gyp/node_modules/cacache/lib/index.js b/node_modules/node-gyp/node_modules/cacache/lib/index.js deleted file mode 100644 index 1c56be68dd8fd..0000000000000 --- a/node_modules/node-gyp/node_modules/cacache/lib/index.js +++ /dev/null @@ -1,45 +0,0 @@ -'use strict' - -const get = require('./get.js') -const put = require('./put.js') -const rm = require('./rm.js') -const verify = require('./verify.js') -const { clearMemoized } = require('./memoization.js') -const tmp = require('./util/tmp.js') -const index = require('./entry-index.js') - -module.exports.index = {} -module.exports.index.compact = index.compact -module.exports.index.insert = index.insert - -module.exports.ls = index.ls -module.exports.ls.stream = index.lsStream - -module.exports.get = get -module.exports.get.byDigest = get.byDigest -module.exports.get.sync = get.sync -module.exports.get.sync.byDigest = get.sync.byDigest -module.exports.get.stream = get.stream -module.exports.get.stream.byDigest = get.stream.byDigest -module.exports.get.copy = get.copy -module.exports.get.copy.byDigest = get.copy.byDigest -module.exports.get.info = get.info -module.exports.get.hasContent = get.hasContent -module.exports.get.hasContent.sync = get.hasContent.sync - -module.exports.put = put -module.exports.put.stream = put.stream - -module.exports.rm = rm.entry -module.exports.rm.all = rm.all -module.exports.rm.entry = module.exports.rm -module.exports.rm.content = rm.content - -module.exports.clearMemoized = clearMemoized - -module.exports.tmp = {} -module.exports.tmp.mkdir = tmp.mkdir -module.exports.tmp.withTmp = tmp.withTmp - -module.exports.verify = verify -module.exports.verify.lastRun = verify.lastRun diff --git a/node_modules/node-gyp/node_modules/cacache/lib/memoization.js b/node_modules/node-gyp/node_modules/cacache/lib/memoization.js deleted file mode 100644 index 0ff604a479c9c..0000000000000 --- a/node_modules/node-gyp/node_modules/cacache/lib/memoization.js +++ /dev/null @@ -1,72 +0,0 @@ -'use strict' - -const LRU = require('lru-cache') - -const MEMOIZED = new LRU({ - max: 500, - maxSize: 50 * 1024 * 1024, // 50MB - ttl: 3 * 60 * 1000, // 3 minutes - sizeCalculation: (entry, key) => key.startsWith('key:') ? entry.data.length : entry.length, -}) - -module.exports.clearMemoized = clearMemoized - -function clearMemoized () { - const old = {} - MEMOIZED.forEach((v, k) => { - old[k] = v - }) - MEMOIZED.clear() - return old -} - -module.exports.put = put - -function put (cache, entry, data, opts) { - pickMem(opts).set(`key:${cache}:${entry.key}`, { entry, data }) - putDigest(cache, entry.integrity, data, opts) -} - -module.exports.put.byDigest = putDigest - -function putDigest (cache, integrity, data, opts) { - pickMem(opts).set(`digest:${cache}:${integrity}`, data) -} - -module.exports.get = get - -function get (cache, key, opts) { - return pickMem(opts).get(`key:${cache}:${key}`) -} - -module.exports.get.byDigest = getDigest - -function getDigest (cache, integrity, opts) { - return pickMem(opts).get(`digest:${cache}:${integrity}`) -} - -class ObjProxy { - constructor (obj) { - this.obj = obj - } - - get (key) { - return this.obj[key] - } - - set (key, val) { - this.obj[key] = val - } -} - -function pickMem (opts) { - if (!opts || !opts.memoize) { - return MEMOIZED - } else if (opts.memoize.get && opts.memoize.set) { - return opts.memoize - } else if (typeof opts.memoize === 'object') { - return new ObjProxy(opts.memoize) - } else { - return MEMOIZED - } -} diff --git a/node_modules/node-gyp/node_modules/cacache/lib/put.js b/node_modules/node-gyp/node_modules/cacache/lib/put.js deleted file mode 100644 index 9fc932d5f6dec..0000000000000 --- a/node_modules/node-gyp/node_modules/cacache/lib/put.js +++ /dev/null @@ -1,80 +0,0 @@ -'use strict' - -const index = require('./entry-index') -const memo = require('./memoization') -const write = require('./content/write') -const Flush = require('minipass-flush') -const { PassThrough } = require('minipass-collect') -const Pipeline = require('minipass-pipeline') - -const putOpts = (opts) => ({ - algorithms: ['sha512'], - ...opts, -}) - -module.exports = putData - -async function putData (cache, key, data, opts = {}) { - const { memoize } = opts - opts = putOpts(opts) - const res = await write(cache, data, opts) - const entry = await index.insert(cache, key, res.integrity, { ...opts, size: res.size }) - if (memoize) { - memo.put(cache, entry, data, opts) - } - - return res.integrity -} - -module.exports.stream = putStream - -function putStream (cache, key, opts = {}) { - const { memoize } = opts - opts = putOpts(opts) - let integrity - let size - let error - - let memoData - const pipeline = new Pipeline() - // first item in the pipeline is the memoizer, because we need - // that to end first and get the collected data. - if (memoize) { - const memoizer = new PassThrough().on('collect', data => { - memoData = data - }) - pipeline.push(memoizer) - } - - // contentStream is a write-only, not a passthrough - // no data comes out of it. - const contentStream = write.stream(cache, opts) - .on('integrity', (int) => { - integrity = int - }) - .on('size', (s) => { - size = s - }) - .on('error', (err) => { - error = err - }) - - pipeline.push(contentStream) - - // last but not least, we write the index and emit hash and size, - // and memoize if we're doing that - pipeline.push(new Flush({ - async flush () { - if (!error) { - const entry = await index.insert(cache, key, integrity, { ...opts, size }) - if (memoize && memoData) { - memo.put(cache, entry, memoData, opts) - } - pipeline.emit('integrity', integrity) - pipeline.emit('size', size) - } - }, - })) - - return pipeline -} diff --git a/node_modules/node-gyp/node_modules/cacache/lib/rm.js b/node_modules/node-gyp/node_modules/cacache/lib/rm.js deleted file mode 100644 index 5f00071770b8d..0000000000000 --- a/node_modules/node-gyp/node_modules/cacache/lib/rm.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict' - -const util = require('util') - -const index = require('./entry-index') -const memo = require('./memoization') -const path = require('path') -const rimraf = util.promisify(require('rimraf')) -const rmContent = require('./content/rm') - -module.exports = entry -module.exports.entry = entry - -function entry (cache, key, opts) { - memo.clearMemoized() - return index.delete(cache, key, opts) -} - -module.exports.content = content - -function content (cache, integrity) { - memo.clearMemoized() - return rmContent(cache, integrity) -} - -module.exports.all = all - -function all (cache) { - memo.clearMemoized() - return rimraf(path.join(cache, '*(content-*|index-*)')) -} diff --git a/node_modules/node-gyp/node_modules/cacache/lib/util/fix-owner.js b/node_modules/node-gyp/node_modules/cacache/lib/util/fix-owner.js deleted file mode 100644 index 182fcb028f06c..0000000000000 --- a/node_modules/node-gyp/node_modules/cacache/lib/util/fix-owner.js +++ /dev/null @@ -1,145 +0,0 @@ -'use strict' - -const util = require('util') - -const chownr = util.promisify(require('chownr')) -const mkdirp = require('mkdirp') -const inflight = require('promise-inflight') -const inferOwner = require('infer-owner') - -// Memoize getuid()/getgid() calls. -// patch process.setuid/setgid to invalidate cached value on change -const self = { uid: null, gid: null } -const getSelf = () => { - if (typeof self.uid !== 'number') { - self.uid = process.getuid() - const setuid = process.setuid - process.setuid = (uid) => { - self.uid = null - process.setuid = setuid - return process.setuid(uid) - } - } - if (typeof self.gid !== 'number') { - self.gid = process.getgid() - const setgid = process.setgid - process.setgid = (gid) => { - self.gid = null - process.setgid = setgid - return process.setgid(gid) - } - } -} - -module.exports.chownr = fixOwner - -async function fixOwner (cache, filepath) { - if (!process.getuid) { - // This platform doesn't need ownership fixing - return - } - - getSelf() - if (self.uid !== 0) { - // almost certainly can't chown anyway - return - } - - const { uid, gid } = await inferOwner(cache) - - // No need to override if it's already what we used. - if (self.uid === uid && self.gid === gid) { - return - } - - return inflight('fixOwner: fixing ownership on ' + filepath, () => - chownr( - filepath, - typeof uid === 'number' ? uid : self.uid, - typeof gid === 'number' ? gid : self.gid - ).catch((err) => { - if (err.code === 'ENOENT') { - return null - } - - throw err - }) - ) -} - -module.exports.chownr.sync = fixOwnerSync - -function fixOwnerSync (cache, filepath) { - if (!process.getuid) { - // This platform doesn't need ownership fixing - return - } - const { uid, gid } = inferOwner.sync(cache) - getSelf() - if (self.uid !== 0) { - // almost certainly can't chown anyway - return - } - - if (self.uid === uid && self.gid === gid) { - // No need to override if it's already what we used. - return - } - try { - chownr.sync( - filepath, - typeof uid === 'number' ? uid : self.uid, - typeof gid === 'number' ? gid : self.gid - ) - } catch (err) { - // only catch ENOENT, any other error is a problem. - if (err.code === 'ENOENT') { - return null - } - - throw err - } -} - -module.exports.mkdirfix = mkdirfix - -async function mkdirfix (cache, p, cb) { - // we have to infer the owner _before_ making the directory, even though - // we aren't going to use the results, since the cache itself might not - // exist yet. If we mkdirp it, then our current uid/gid will be assumed - // to be correct if it creates the cache folder in the process. - await inferOwner(cache) - try { - const made = await mkdirp(p) - if (made) { - await fixOwner(cache, made) - return made - } - } catch (err) { - if (err.code === 'EEXIST') { - await fixOwner(cache, p) - return null - } - throw err - } -} - -module.exports.mkdirfix.sync = mkdirfixSync - -function mkdirfixSync (cache, p) { - try { - inferOwner.sync(cache) - const made = mkdirp.sync(p) - if (made) { - fixOwnerSync(cache, made) - return made - } - } catch (err) { - if (err.code === 'EEXIST') { - fixOwnerSync(cache, p) - return null - } else { - throw err - } - } -} diff --git a/node_modules/node-gyp/node_modules/cacache/lib/util/hash-to-segments.js b/node_modules/node-gyp/node_modules/cacache/lib/util/hash-to-segments.js deleted file mode 100644 index 445599b503808..0000000000000 --- a/node_modules/node-gyp/node_modules/cacache/lib/util/hash-to-segments.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict' - -module.exports = hashToSegments - -function hashToSegments (hash) { - return [hash.slice(0, 2), hash.slice(2, 4), hash.slice(4)] -} diff --git a/node_modules/node-gyp/node_modules/cacache/lib/util/move-file.js b/node_modules/node-gyp/node_modules/cacache/lib/util/move-file.js deleted file mode 100644 index a0b40413cb56e..0000000000000 --- a/node_modules/node-gyp/node_modules/cacache/lib/util/move-file.js +++ /dev/null @@ -1,56 +0,0 @@ -'use strict' - -const fs = require('@npmcli/fs') -const move = require('@npmcli/move-file') -const pinflight = require('promise-inflight') - -module.exports = moveFile - -async function moveFile (src, dest) { - const isWindows = process.platform === 'win32' - - // This isn't quite an fs.rename -- the assumption is that - // if `dest` already exists, and we get certain errors while - // trying to move it, we should just not bother. - // - // In the case of cache corruption, users will receive an - // EINTEGRITY error elsewhere, and can remove the offending - // content their own way. - // - // Note that, as the name suggests, this strictly only supports file moves. - try { - await fs.link(src, dest) - } catch (err) { - if (isWindows && err.code === 'EPERM') { - // XXX This is a really weird way to handle this situation, as it - // results in the src file being deleted even though the dest - // might not exist. Since we pretty much always write files to - // deterministic locations based on content hash, this is likely - // ok (or at worst, just ends in a future cache miss). But it would - // be worth investigating at some time in the future if this is - // really what we want to do here. - } else if (err.code === 'EEXIST' || err.code === 'EBUSY') { - // file already exists, so whatever - } else { - throw err - } - } - try { - await Promise.all([ - fs.unlink(src), - !isWindows && fs.chmod(dest, '0444'), - ]) - } catch (e) { - return pinflight('cacache-move-file:' + dest, async () => { - await fs.stat(dest).catch((err) => { - if (err.code !== 'ENOENT') { - // Something else is wrong here. Bail bail bail - throw err - } - }) - // file doesn't already exist! let's try a rename -> copy fallback - // only delete if it successfully copies - return move(src, dest) - }) - } -} diff --git a/node_modules/node-gyp/node_modules/cacache/lib/util/tmp.js b/node_modules/node-gyp/node_modules/cacache/lib/util/tmp.js deleted file mode 100644 index b4437cfcbeed6..0000000000000 --- a/node_modules/node-gyp/node_modules/cacache/lib/util/tmp.js +++ /dev/null @@ -1,33 +0,0 @@ -'use strict' - -const fs = require('@npmcli/fs') - -const fixOwner = require('./fix-owner') -const path = require('path') - -module.exports.mkdir = mktmpdir - -async function mktmpdir (cache, opts = {}) { - const { tmpPrefix } = opts - const tmpDir = path.join(cache, 'tmp') - await fs.mkdir(tmpDir, { recursive: true, owner: 'inherit' }) - // do not use path.join(), it drops the trailing / if tmpPrefix is unset - const target = `${tmpDir}${path.sep}${tmpPrefix || ''}` - return fs.mkdtemp(target, { owner: 'inherit' }) -} - -module.exports.withTmp = withTmp - -function withTmp (cache, opts, cb) { - if (!cb) { - cb = opts - opts = {} - } - return fs.withTempDir(path.join(cache, 'tmp'), cb, opts) -} - -module.exports.fix = fixtmpdir - -function fixtmpdir (cache) { - return fixOwner(cache, path.join(cache, 'tmp')) -} diff --git a/node_modules/node-gyp/node_modules/cacache/lib/verify.js b/node_modules/node-gyp/node_modules/cacache/lib/verify.js deleted file mode 100644 index 52692a01d192f..0000000000000 --- a/node_modules/node-gyp/node_modules/cacache/lib/verify.js +++ /dev/null @@ -1,257 +0,0 @@ -'use strict' - -const util = require('util') - -const pMap = require('p-map') -const contentPath = require('./content/path') -const fixOwner = require('./util/fix-owner') -const fs = require('@npmcli/fs') -const fsm = require('fs-minipass') -const glob = util.promisify(require('glob')) -const index = require('./entry-index') -const path = require('path') -const rimraf = util.promisify(require('rimraf')) -const ssri = require('ssri') - -const globify = pattern => pattern.split('\\').join('/') - -const hasOwnProperty = (obj, key) => - Object.prototype.hasOwnProperty.call(obj, key) - -const verifyOpts = (opts) => ({ - concurrency: 20, - log: { silly () {} }, - ...opts, -}) - -module.exports = verify - -async function verify (cache, opts) { - opts = verifyOpts(opts) - opts.log.silly('verify', 'verifying cache at', cache) - - const steps = [ - markStartTime, - fixPerms, - garbageCollect, - rebuildIndex, - cleanTmp, - writeVerifile, - markEndTime, - ] - - const stats = {} - for (const step of steps) { - const label = step.name - const start = new Date() - const s = await step(cache, opts) - if (s) { - Object.keys(s).forEach((k) => { - stats[k] = s[k] - }) - } - const end = new Date() - if (!stats.runTime) { - stats.runTime = {} - } - stats.runTime[label] = end - start - } - stats.runTime.total = stats.endTime - stats.startTime - opts.log.silly( - 'verify', - 'verification finished for', - cache, - 'in', - `${stats.runTime.total}ms` - ) - return stats -} - -async function markStartTime (cache, opts) { - return { startTime: new Date() } -} - -async function markEndTime (cache, opts) { - return { endTime: new Date() } -} - -async function fixPerms (cache, opts) { - opts.log.silly('verify', 'fixing cache permissions') - await fixOwner.mkdirfix(cache, cache) - // TODO - fix file permissions too - await fixOwner.chownr(cache, cache) - return null -} - -// Implements a naive mark-and-sweep tracing garbage collector. -// -// The algorithm is basically as follows: -// 1. Read (and filter) all index entries ("pointers") -// 2. Mark each integrity value as "live" -// 3. Read entire filesystem tree in `content-vX/` dir -// 4. If content is live, verify its checksum and delete it if it fails -// 5. If content is not marked as live, rimraf it. -// -async function garbageCollect (cache, opts) { - opts.log.silly('verify', 'garbage collecting content') - const indexStream = index.lsStream(cache) - const liveContent = new Set() - indexStream.on('data', (entry) => { - if (opts.filter && !opts.filter(entry)) { - return - } - - liveContent.add(entry.integrity.toString()) - }) - await new Promise((resolve, reject) => { - indexStream.on('end', resolve).on('error', reject) - }) - const contentDir = contentPath.contentDir(cache) - const files = await glob(globify(path.join(contentDir, '**')), { - follow: false, - nodir: true, - nosort: true, - }) - const stats = { - verifiedContent: 0, - reclaimedCount: 0, - reclaimedSize: 0, - badContentCount: 0, - keptSize: 0, - } - await pMap( - files, - async (f) => { - const split = f.split(/[/\\]/) - const digest = split.slice(split.length - 3).join('') - const algo = split[split.length - 4] - const integrity = ssri.fromHex(digest, algo) - if (liveContent.has(integrity.toString())) { - const info = await verifyContent(f, integrity) - if (!info.valid) { - stats.reclaimedCount++ - stats.badContentCount++ - stats.reclaimedSize += info.size - } else { - stats.verifiedContent++ - stats.keptSize += info.size - } - } else { - // No entries refer to this content. We can delete. - stats.reclaimedCount++ - const s = await fs.stat(f) - await rimraf(f) - stats.reclaimedSize += s.size - } - return stats - }, - { concurrency: opts.concurrency } - ) - return stats -} - -async function verifyContent (filepath, sri) { - const contentInfo = {} - try { - const { size } = await fs.stat(filepath) - contentInfo.size = size - contentInfo.valid = true - await ssri.checkStream(new fsm.ReadStream(filepath), sri) - } catch (err) { - if (err.code === 'ENOENT') { - return { size: 0, valid: false } - } - if (err.code !== 'EINTEGRITY') { - throw err - } - - await rimraf(filepath) - contentInfo.valid = false - } - return contentInfo -} - -async function rebuildIndex (cache, opts) { - opts.log.silly('verify', 'rebuilding index') - const entries = await index.ls(cache) - const stats = { - missingContent: 0, - rejectedEntries: 0, - totalEntries: 0, - } - const buckets = {} - for (const k in entries) { - /* istanbul ignore else */ - if (hasOwnProperty(entries, k)) { - const hashed = index.hashKey(k) - const entry = entries[k] - const excluded = opts.filter && !opts.filter(entry) - excluded && stats.rejectedEntries++ - if (buckets[hashed] && !excluded) { - buckets[hashed].push(entry) - } else if (buckets[hashed] && excluded) { - // skip - } else if (excluded) { - buckets[hashed] = [] - buckets[hashed]._path = index.bucketPath(cache, k) - } else { - buckets[hashed] = [entry] - buckets[hashed]._path = index.bucketPath(cache, k) - } - } - } - await pMap( - Object.keys(buckets), - (key) => { - return rebuildBucket(cache, buckets[key], stats, opts) - }, - { concurrency: opts.concurrency } - ) - return stats -} - -async function rebuildBucket (cache, bucket, stats, opts) { - await fs.truncate(bucket._path) - // This needs to be serialized because cacache explicitly - // lets very racy bucket conflicts clobber each other. - for (const entry of bucket) { - const content = contentPath(cache, entry.integrity) - try { - await fs.stat(content) - await index.insert(cache, entry.key, entry.integrity, { - metadata: entry.metadata, - size: entry.size, - }) - stats.totalEntries++ - } catch (err) { - if (err.code === 'ENOENT') { - stats.rejectedEntries++ - stats.missingContent++ - } else { - throw err - } - } - } -} - -function cleanTmp (cache, opts) { - opts.log.silly('verify', 'cleaning tmp directory') - return rimraf(path.join(cache, 'tmp')) -} - -function writeVerifile (cache, opts) { - const verifile = path.join(cache, '_lastverified') - opts.log.silly('verify', 'writing verifile to ' + verifile) - try { - return fs.writeFile(verifile, `${Date.now()}`) - } finally { - fixOwner.chownr.sync(cache, verifile) - } -} - -module.exports.lastRun = lastRun - -async function lastRun (cache) { - const data = await fs.readFile(path.join(cache, '_lastverified'), { encoding: 'utf8' }) - return new Date(+data) -} diff --git a/node_modules/node-gyp/node_modules/cacache/node_modules/brace-expansion/LICENSE b/node_modules/node-gyp/node_modules/cacache/node_modules/brace-expansion/LICENSE deleted file mode 100644 index de3226673c387..0000000000000 --- a/node_modules/node-gyp/node_modules/cacache/node_modules/brace-expansion/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2013 Julian Gruber - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/node_modules/node-gyp/node_modules/cacache/node_modules/brace-expansion/index.js b/node_modules/node-gyp/node_modules/cacache/node_modules/brace-expansion/index.js deleted file mode 100644 index 4af9ddee463f4..0000000000000 --- a/node_modules/node-gyp/node_modules/cacache/node_modules/brace-expansion/index.js +++ /dev/null @@ -1,203 +0,0 @@ -var balanced = require('balanced-match'); - -module.exports = expandTop; - -var escSlash = '\0SLASH'+Math.random()+'\0'; -var escOpen = '\0OPEN'+Math.random()+'\0'; -var escClose = '\0CLOSE'+Math.random()+'\0'; -var escComma = '\0COMMA'+Math.random()+'\0'; -var escPeriod = '\0PERIOD'+Math.random()+'\0'; - -function numeric(str) { - return parseInt(str, 10) == str - ? parseInt(str, 10) - : str.charCodeAt(0); -} - -function escapeBraces(str) { - return str.split('\\\\').join(escSlash) - .split('\\{').join(escOpen) - .split('\\}').join(escClose) - .split('\\,').join(escComma) - .split('\\.').join(escPeriod); -} - -function unescapeBraces(str) { - return str.split(escSlash).join('\\') - .split(escOpen).join('{') - .split(escClose).join('}') - .split(escComma).join(',') - .split(escPeriod).join('.'); -} - - -// Basically just str.split(","), but handling cases -// where we have nested braced sections, which should be -// treated as individual members, like {a,{b,c},d} -function parseCommaParts(str) { - if (!str) - return ['']; - - var parts = []; - var m = balanced('{', '}', str); - - if (!m) - return str.split(','); - - var pre = m.pre; - var body = m.body; - var post = m.post; - var p = pre.split(','); - - p[p.length-1] += '{' + body + '}'; - var postParts = parseCommaParts(post); - if (post.length) { - p[p.length-1] += postParts.shift(); - p.push.apply(p, postParts); - } - - parts.push.apply(parts, p); - - return parts; -} - -function expandTop(str) { - if (!str) - return []; - - // I don't know why Bash 4.3 does this, but it does. - // Anything starting with {} will have the first two bytes preserved - // but *only* at the top level, so {},a}b will not expand to anything, - // but a{},b}c will be expanded to [a}c,abc]. - // One could argue that this is a bug in Bash, but since the goal of - // this module is to match Bash's rules, we escape a leading {} - if (str.substr(0, 2) === '{}') { - str = '\\{\\}' + str.substr(2); - } - - return expand(escapeBraces(str), true).map(unescapeBraces); -} - -function embrace(str) { - return '{' + str + '}'; -} -function isPadded(el) { - return /^-?0\d/.test(el); -} - -function lte(i, y) { - return i <= y; -} -function gte(i, y) { - return i >= y; -} - -function expand(str, isTop) { - var expansions = []; - - var m = balanced('{', '}', str); - if (!m) return [str]; - - // no need to expand pre, since it is guaranteed to be free of brace-sets - var pre = m.pre; - var post = m.post.length - ? expand(m.post, false) - : ['']; - - if (/\$$/.test(m.pre)) { - for (var k = 0; k < post.length; k++) { - var expansion = pre+ '{' + m.body + '}' + post[k]; - expansions.push(expansion); - } - } else { - var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body); - var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body); - var isSequence = isNumericSequence || isAlphaSequence; - var isOptions = m.body.indexOf(',') >= 0; - if (!isSequence && !isOptions) { - // {a},b} - if (m.post.match(/,.*\}/)) { - str = m.pre + '{' + m.body + escClose + m.post; - return expand(str); - } - return [str]; - } - - var n; - if (isSequence) { - n = m.body.split(/\.\./); - } else { - n = parseCommaParts(m.body); - if (n.length === 1) { - // x{{a,b}}y ==> x{a}y x{b}y - n = expand(n[0], false).map(embrace); - if (n.length === 1) { - return post.map(function(p) { - return m.pre + n[0] + p; - }); - } - } - } - - // at this point, n is the parts, and we know it's not a comma set - // with a single entry. - var N; - - if (isSequence) { - var x = numeric(n[0]); - var y = numeric(n[1]); - var width = Math.max(n[0].length, n[1].length) - var incr = n.length == 3 - ? Math.abs(numeric(n[2])) - : 1; - var test = lte; - var reverse = y < x; - if (reverse) { - incr *= -1; - test = gte; - } - var pad = n.some(isPadded); - - N = []; - - for (var i = x; test(i, y); i += incr) { - var c; - if (isAlphaSequence) { - c = String.fromCharCode(i); - if (c === '\\') - c = ''; - } else { - c = String(i); - if (pad) { - var need = width - c.length; - if (need > 0) { - var z = new Array(need + 1).join('0'); - if (i < 0) - c = '-' + z + c.slice(1); - else - c = z + c; - } - } - } - N.push(c); - } - } else { - N = []; - - for (var j = 0; j < n.length; j++) { - N.push.apply(N, expand(n[j], false)); - } - } - - for (var j = 0; j < N.length; j++) { - for (var k = 0; k < post.length; k++) { - var expansion = pre + N[j] + post[k]; - if (!isTop || isSequence || expansion) - expansions.push(expansion); - } - } - } - - return expansions; -} - diff --git a/node_modules/node-gyp/node_modules/cacache/node_modules/brace-expansion/package.json b/node_modules/node-gyp/node_modules/cacache/node_modules/brace-expansion/package.json deleted file mode 100644 index 7097d41e39de5..0000000000000 --- a/node_modules/node-gyp/node_modules/cacache/node_modules/brace-expansion/package.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "name": "brace-expansion", - "description": "Brace expansion as known from sh/bash", - "version": "2.0.1", - "repository": { - "type": "git", - "url": "git://github.com/juliangruber/brace-expansion.git" - }, - "homepage": "https://github.com/juliangruber/brace-expansion", - "main": "index.js", - "scripts": { - "test": "tape test/*.js", - "gentest": "bash test/generate.sh", - "bench": "matcha test/perf/bench.js" - }, - "dependencies": { - "balanced-match": "^1.0.0" - }, - "devDependencies": { - "@c4312/matcha": "^1.3.1", - "tape": "^4.6.0" - }, - "keywords": [], - "author": { - "name": "Julian Gruber", - "email": "mail@juliangruber.com", - "url": "http://juliangruber.com" - }, - "license": "MIT", - "testling": { - "files": "test/*.js", - "browsers": [ - "ie/8..latest", - "firefox/20..latest", - "firefox/nightly", - "chrome/25..latest", - "chrome/canary", - "opera/12..latest", - "opera/next", - "safari/5.1..latest", - "ipad/6.0..latest", - "iphone/6.0..latest", - "android-browser/4.2..latest" - ] - } -} diff --git a/node_modules/node-gyp/node_modules/cacache/node_modules/glob/LICENSE b/node_modules/node-gyp/node_modules/cacache/node_modules/glob/LICENSE deleted file mode 100644 index 39e8fe16f665a..0000000000000 --- a/node_modules/node-gyp/node_modules/cacache/node_modules/glob/LICENSE +++ /dev/null @@ -1,15 +0,0 @@ -The ISC License - -Copyright (c) 2009-2022 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/node-gyp/node_modules/cacache/node_modules/glob/common.js b/node_modules/node-gyp/node_modules/cacache/node_modules/glob/common.js deleted file mode 100644 index 61a4452f097dc..0000000000000 --- a/node_modules/node-gyp/node_modules/cacache/node_modules/glob/common.js +++ /dev/null @@ -1,244 +0,0 @@ -exports.setopts = setopts -exports.ownProp = ownProp -exports.makeAbs = makeAbs -exports.finish = finish -exports.mark = mark -exports.isIgnored = isIgnored -exports.childrenIgnored = childrenIgnored - -function ownProp (obj, field) { - return Object.prototype.hasOwnProperty.call(obj, field) -} - -var fs = require("fs") -var path = require("path") -var minimatch = require("minimatch") -var isAbsolute = require("path").isAbsolute -var Minimatch = minimatch.Minimatch - -function alphasort (a, b) { - return a.localeCompare(b, 'en') -} - -function setupIgnores (self, options) { - self.ignore = options.ignore || [] - - if (!Array.isArray(self.ignore)) - self.ignore = [self.ignore] - - if (self.ignore.length) { - self.ignore = self.ignore.map(ignoreMap) - } -} - -// ignore patterns are always in dot:true mode. -function ignoreMap (pattern) { - var gmatcher = null - if (pattern.slice(-3) === '/**') { - var gpattern = pattern.replace(/(\/\*\*)+$/, '') - gmatcher = new Minimatch(gpattern, { dot: true }) - } - - return { - matcher: new Minimatch(pattern, { dot: true }), - gmatcher: gmatcher - } -} - -function setopts (self, pattern, options) { - if (!options) - options = {} - - // base-matching: just use globstar for that. - if (options.matchBase && -1 === pattern.indexOf("/")) { - if (options.noglobstar) { - throw new Error("base matching requires globstar") - } - pattern = "**/" + pattern - } - - self.windowsPathsNoEscape = !!options.windowsPathsNoEscape || - options.allowWindowsEscape === false - if (self.windowsPathsNoEscape) { - pattern = pattern.replace(/\\/g, '/') - } - - self.silent = !!options.silent - self.pattern = pattern - self.strict = options.strict !== false - self.realpath = !!options.realpath - self.realpathCache = options.realpathCache || Object.create(null) - self.follow = !!options.follow - self.dot = !!options.dot - self.mark = !!options.mark - self.nodir = !!options.nodir - if (self.nodir) - self.mark = true - self.sync = !!options.sync - self.nounique = !!options.nounique - self.nonull = !!options.nonull - self.nosort = !!options.nosort - self.nocase = !!options.nocase - self.stat = !!options.stat - self.noprocess = !!options.noprocess - self.absolute = !!options.absolute - self.fs = options.fs || fs - - self.maxLength = options.maxLength || Infinity - self.cache = options.cache || Object.create(null) - self.statCache = options.statCache || Object.create(null) - self.symlinks = options.symlinks || Object.create(null) - - setupIgnores(self, options) - - self.changedCwd = false - var cwd = process.cwd() - if (!ownProp(options, "cwd")) - self.cwd = path.resolve(cwd) - else { - self.cwd = path.resolve(options.cwd) - self.changedCwd = self.cwd !== cwd - } - - self.root = options.root || path.resolve(self.cwd, "/") - self.root = path.resolve(self.root) - - // TODO: is an absolute `cwd` supposed to be resolved against `root`? - // e.g. { cwd: '/test', root: __dirname } === path.join(__dirname, '/test') - self.cwdAbs = isAbsolute(self.cwd) ? self.cwd : makeAbs(self, self.cwd) - self.nomount = !!options.nomount - - if (process.platform === "win32") { - self.root = self.root.replace(/\\/g, "/") - self.cwd = self.cwd.replace(/\\/g, "/") - self.cwdAbs = self.cwdAbs.replace(/\\/g, "/") - } - - // disable comments and negation in Minimatch. - // Note that they are not supported in Glob itself anyway. - options.nonegate = true - options.nocomment = true - - self.minimatch = new Minimatch(pattern, options) - self.options = self.minimatch.options -} - -function finish (self) { - var nou = self.nounique - var all = nou ? [] : Object.create(null) - - for (var i = 0, l = self.matches.length; i < l; i ++) { - var matches = self.matches[i] - if (!matches || Object.keys(matches).length === 0) { - if (self.nonull) { - // do like the shell, and spit out the literal glob - var literal = self.minimatch.globSet[i] - if (nou) - all.push(literal) - else - all[literal] = true - } - } else { - // had matches - var m = Object.keys(matches) - if (nou) - all.push.apply(all, m) - else - m.forEach(function (m) { - all[m] = true - }) - } - } - - if (!nou) - all = Object.keys(all) - - if (!self.nosort) - all = all.sort(alphasort) - - // at *some* point we statted all of these - if (self.mark) { - for (var i = 0; i < all.length; i++) { - all[i] = self._mark(all[i]) - } - if (self.nodir) { - all = all.filter(function (e) { - var notDir = !(/\/$/.test(e)) - var c = self.cache[e] || self.cache[makeAbs(self, e)] - if (notDir && c) - notDir = c !== 'DIR' && !Array.isArray(c) - return notDir - }) - } - } - - if (self.ignore.length) - all = all.filter(function(m) { - return !isIgnored(self, m) - }) - - self.found = all -} - -function mark (self, p) { - var abs = makeAbs(self, p) - var c = self.cache[abs] - var m = p - if (c) { - var isDir = c === 'DIR' || Array.isArray(c) - var slash = p.slice(-1) === '/' - - if (isDir && !slash) - m += '/' - else if (!isDir && slash) - m = m.slice(0, -1) - - if (m !== p) { - var mabs = makeAbs(self, m) - self.statCache[mabs] = self.statCache[abs] - self.cache[mabs] = self.cache[abs] - } - } - - return m -} - -// lotta situps... -function makeAbs (self, f) { - var abs = f - if (f.charAt(0) === '/') { - abs = path.join(self.root, f) - } else if (isAbsolute(f) || f === '') { - abs = f - } else if (self.changedCwd) { - abs = path.resolve(self.cwd, f) - } else { - abs = path.resolve(f) - } - - if (process.platform === 'win32') - abs = abs.replace(/\\/g, '/') - - return abs -} - - -// Return true, if pattern ends with globstar '**', for the accompanying parent directory. -// Ex:- If node_modules/** is the pattern, add 'node_modules' to ignore list along with it's contents -function isIgnored (self, path) { - if (!self.ignore.length) - return false - - return self.ignore.some(function(item) { - return item.matcher.match(path) || !!(item.gmatcher && item.gmatcher.match(path)) - }) -} - -function childrenIgnored (self, path) { - if (!self.ignore.length) - return false - - return self.ignore.some(function(item) { - return !!(item.gmatcher && item.gmatcher.match(path)) - }) -} diff --git a/node_modules/node-gyp/node_modules/cacache/node_modules/glob/glob.js b/node_modules/node-gyp/node_modules/cacache/node_modules/glob/glob.js deleted file mode 100644 index 2112a957dc501..0000000000000 --- a/node_modules/node-gyp/node_modules/cacache/node_modules/glob/glob.js +++ /dev/null @@ -1,790 +0,0 @@ -// Approach: -// -// 1. Get the minimatch set -// 2. For each pattern in the set, PROCESS(pattern, false) -// 3. Store matches per-set, then uniq them -// -// PROCESS(pattern, inGlobStar) -// Get the first [n] items from pattern that are all strings -// Join these together. This is PREFIX. -// If there is no more remaining, then stat(PREFIX) and -// add to matches if it succeeds. END. -// -// If inGlobStar and PREFIX is symlink and points to dir -// set ENTRIES = [] -// else readdir(PREFIX) as ENTRIES -// If fail, END -// -// with ENTRIES -// If pattern[n] is GLOBSTAR -// // handle the case where the globstar match is empty -// // by pruning it out, and testing the resulting pattern -// PROCESS(pattern[0..n] + pattern[n+1 .. $], false) -// // handle other cases. -// for ENTRY in ENTRIES (not dotfiles) -// // attach globstar + tail onto the entry -// // Mark that this entry is a globstar match -// PROCESS(pattern[0..n] + ENTRY + pattern[n .. $], true) -// -// else // not globstar -// for ENTRY in ENTRIES (not dotfiles, unless pattern[n] is dot) -// Test ENTRY against pattern[n] -// If fails, continue -// If passes, PROCESS(pattern[0..n] + item + pattern[n+1 .. $]) -// -// Caveat: -// Cache all stats and readdirs results to minimize syscall. Since all -// we ever care about is existence and directory-ness, we can just keep -// `true` for files, and [children,...] for directories, or `false` for -// things that don't exist. - -module.exports = glob - -var rp = require('fs.realpath') -var minimatch = require('minimatch') -var Minimatch = minimatch.Minimatch -var inherits = require('inherits') -var EE = require('events').EventEmitter -var path = require('path') -var assert = require('assert') -var isAbsolute = require('path').isAbsolute -var globSync = require('./sync.js') -var common = require('./common.js') -var setopts = common.setopts -var ownProp = common.ownProp -var inflight = require('inflight') -var util = require('util') -var childrenIgnored = common.childrenIgnored -var isIgnored = common.isIgnored - -var once = require('once') - -function glob (pattern, options, cb) { - if (typeof options === 'function') cb = options, options = {} - if (!options) options = {} - - if (options.sync) { - if (cb) - throw new TypeError('callback provided to sync glob') - return globSync(pattern, options) - } - - return new Glob(pattern, options, cb) -} - -glob.sync = globSync -var GlobSync = glob.GlobSync = globSync.GlobSync - -// old api surface -glob.glob = glob - -function extend (origin, add) { - if (add === null || typeof add !== 'object') { - return origin - } - - var keys = Object.keys(add) - var i = keys.length - while (i--) { - origin[keys[i]] = add[keys[i]] - } - return origin -} - -glob.hasMagic = function (pattern, options_) { - var options = extend({}, options_) - options.noprocess = true - - var g = new Glob(pattern, options) - var set = g.minimatch.set - - if (!pattern) - return false - - if (set.length > 1) - return true - - for (var j = 0; j < set[0].length; j++) { - if (typeof set[0][j] !== 'string') - return true - } - - return false -} - -glob.Glob = Glob -inherits(Glob, EE) -function Glob (pattern, options, cb) { - if (typeof options === 'function') { - cb = options - options = null - } - - if (options && options.sync) { - if (cb) - throw new TypeError('callback provided to sync glob') - return new GlobSync(pattern, options) - } - - if (!(this instanceof Glob)) - return new Glob(pattern, options, cb) - - setopts(this, pattern, options) - this._didRealPath = false - - // process each pattern in the minimatch set - var n = this.minimatch.set.length - - // The matches are stored as {: true,...} so that - // duplicates are automagically pruned. - // Later, we do an Object.keys() on these. - // Keep them as a list so we can fill in when nonull is set. - this.matches = new Array(n) - - if (typeof cb === 'function') { - cb = once(cb) - this.on('error', cb) - this.on('end', function (matches) { - cb(null, matches) - }) - } - - var self = this - this._processing = 0 - - this._emitQueue = [] - this._processQueue = [] - this.paused = false - - if (this.noprocess) - return this - - if (n === 0) - return done() - - var sync = true - for (var i = 0; i < n; i ++) { - this._process(this.minimatch.set[i], i, false, done) - } - sync = false - - function done () { - --self._processing - if (self._processing <= 0) { - if (sync) { - process.nextTick(function () { - self._finish() - }) - } else { - self._finish() - } - } - } -} - -Glob.prototype._finish = function () { - assert(this instanceof Glob) - if (this.aborted) - return - - if (this.realpath && !this._didRealpath) - return this._realpath() - - common.finish(this) - this.emit('end', this.found) -} - -Glob.prototype._realpath = function () { - if (this._didRealpath) - return - - this._didRealpath = true - - var n = this.matches.length - if (n === 0) - return this._finish() - - var self = this - for (var i = 0; i < this.matches.length; i++) - this._realpathSet(i, next) - - function next () { - if (--n === 0) - self._finish() - } -} - -Glob.prototype._realpathSet = function (index, cb) { - var matchset = this.matches[index] - if (!matchset) - return cb() - - var found = Object.keys(matchset) - var self = this - var n = found.length - - if (n === 0) - return cb() - - var set = this.matches[index] = Object.create(null) - found.forEach(function (p, i) { - // If there's a problem with the stat, then it means that - // one or more of the links in the realpath couldn't be - // resolved. just return the abs value in that case. - p = self._makeAbs(p) - rp.realpath(p, self.realpathCache, function (er, real) { - if (!er) - set[real] = true - else if (er.syscall === 'stat') - set[p] = true - else - self.emit('error', er) // srsly wtf right here - - if (--n === 0) { - self.matches[index] = set - cb() - } - }) - }) -} - -Glob.prototype._mark = function (p) { - return common.mark(this, p) -} - -Glob.prototype._makeAbs = function (f) { - return common.makeAbs(this, f) -} - -Glob.prototype.abort = function () { - this.aborted = true - this.emit('abort') -} - -Glob.prototype.pause = function () { - if (!this.paused) { - this.paused = true - this.emit('pause') - } -} - -Glob.prototype.resume = function () { - if (this.paused) { - this.emit('resume') - this.paused = false - if (this._emitQueue.length) { - var eq = this._emitQueue.slice(0) - this._emitQueue.length = 0 - for (var i = 0; i < eq.length; i ++) { - var e = eq[i] - this._emitMatch(e[0], e[1]) - } - } - if (this._processQueue.length) { - var pq = this._processQueue.slice(0) - this._processQueue.length = 0 - for (var i = 0; i < pq.length; i ++) { - var p = pq[i] - this._processing-- - this._process(p[0], p[1], p[2], p[3]) - } - } - } -} - -Glob.prototype._process = function (pattern, index, inGlobStar, cb) { - assert(this instanceof Glob) - assert(typeof cb === 'function') - - if (this.aborted) - return - - this._processing++ - if (this.paused) { - this._processQueue.push([pattern, index, inGlobStar, cb]) - return - } - - //console.error('PROCESS %d', this._processing, pattern) - - // Get the first [n] parts of pattern that are all strings. - var n = 0 - while (typeof pattern[n] === 'string') { - n ++ - } - // now n is the index of the first one that is *not* a string. - - // see if there's anything else - var prefix - switch (n) { - // if not, then this is rather simple - case pattern.length: - this._processSimple(pattern.join('/'), index, cb) - return - - case 0: - // pattern *starts* with some non-trivial item. - // going to readdir(cwd), but not include the prefix in matches. - prefix = null - break - - default: - // pattern has some string bits in the front. - // whatever it starts with, whether that's 'absolute' like /foo/bar, - // or 'relative' like '../baz' - prefix = pattern.slice(0, n).join('/') - break - } - - var remain = pattern.slice(n) - - // get the list of entries. - var read - if (prefix === null) - read = '.' - else if (isAbsolute(prefix) || - isAbsolute(pattern.map(function (p) { - return typeof p === 'string' ? p : '[*]' - }).join('/'))) { - if (!prefix || !isAbsolute(prefix)) - prefix = '/' + prefix - read = prefix - } else - read = prefix - - var abs = this._makeAbs(read) - - //if ignored, skip _processing - if (childrenIgnored(this, read)) - return cb() - - var isGlobStar = remain[0] === minimatch.GLOBSTAR - if (isGlobStar) - this._processGlobStar(prefix, read, abs, remain, index, inGlobStar, cb) - else - this._processReaddir(prefix, read, abs, remain, index, inGlobStar, cb) -} - -Glob.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar, cb) { - var self = this - this._readdir(abs, inGlobStar, function (er, entries) { - return self._processReaddir2(prefix, read, abs, remain, index, inGlobStar, entries, cb) - }) -} - -Glob.prototype._processReaddir2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) { - - // if the abs isn't a dir, then nothing can match! - if (!entries) - return cb() - - // It will only match dot entries if it starts with a dot, or if - // dot is set. Stuff like @(.foo|.bar) isn't allowed. - var pn = remain[0] - var negate = !!this.minimatch.negate - var rawGlob = pn._glob - var dotOk = this.dot || rawGlob.charAt(0) === '.' - - var matchedEntries = [] - for (var i = 0; i < entries.length; i++) { - var e = entries[i] - if (e.charAt(0) !== '.' || dotOk) { - var m - if (negate && !prefix) { - m = !e.match(pn) - } else { - m = e.match(pn) - } - if (m) - matchedEntries.push(e) - } - } - - //console.error('prd2', prefix, entries, remain[0]._glob, matchedEntries) - - var len = matchedEntries.length - // If there are no matched entries, then nothing matches. - if (len === 0) - return cb() - - // if this is the last remaining pattern bit, then no need for - // an additional stat *unless* the user has specified mark or - // stat explicitly. We know they exist, since readdir returned - // them. - - if (remain.length === 1 && !this.mark && !this.stat) { - if (!this.matches[index]) - this.matches[index] = Object.create(null) - - for (var i = 0; i < len; i ++) { - var e = matchedEntries[i] - if (prefix) { - if (prefix !== '/') - e = prefix + '/' + e - else - e = prefix + e - } - - if (e.charAt(0) === '/' && !this.nomount) { - e = path.join(this.root, e) - } - this._emitMatch(index, e) - } - // This was the last one, and no stats were needed - return cb() - } - - // now test all matched entries as stand-ins for that part - // of the pattern. - remain.shift() - for (var i = 0; i < len; i ++) { - var e = matchedEntries[i] - var newPattern - if (prefix) { - if (prefix !== '/') - e = prefix + '/' + e - else - e = prefix + e - } - this._process([e].concat(remain), index, inGlobStar, cb) - } - cb() -} - -Glob.prototype._emitMatch = function (index, e) { - if (this.aborted) - return - - if (isIgnored(this, e)) - return - - if (this.paused) { - this._emitQueue.push([index, e]) - return - } - - var abs = isAbsolute(e) ? e : this._makeAbs(e) - - if (this.mark) - e = this._mark(e) - - if (this.absolute) - e = abs - - if (this.matches[index][e]) - return - - if (this.nodir) { - var c = this.cache[abs] - if (c === 'DIR' || Array.isArray(c)) - return - } - - this.matches[index][e] = true - - var st = this.statCache[abs] - if (st) - this.emit('stat', e, st) - - this.emit('match', e) -} - -Glob.prototype._readdirInGlobStar = function (abs, cb) { - if (this.aborted) - return - - // follow all symlinked directories forever - // just proceed as if this is a non-globstar situation - if (this.follow) - return this._readdir(abs, false, cb) - - var lstatkey = 'lstat\0' + abs - var self = this - var lstatcb = inflight(lstatkey, lstatcb_) - - if (lstatcb) - self.fs.lstat(abs, lstatcb) - - function lstatcb_ (er, lstat) { - if (er && er.code === 'ENOENT') - return cb() - - var isSym = lstat && lstat.isSymbolicLink() - self.symlinks[abs] = isSym - - // If it's not a symlink or a dir, then it's definitely a regular file. - // don't bother doing a readdir in that case. - if (!isSym && lstat && !lstat.isDirectory()) { - self.cache[abs] = 'FILE' - cb() - } else - self._readdir(abs, false, cb) - } -} - -Glob.prototype._readdir = function (abs, inGlobStar, cb) { - if (this.aborted) - return - - cb = inflight('readdir\0'+abs+'\0'+inGlobStar, cb) - if (!cb) - return - - //console.error('RD %j %j', +inGlobStar, abs) - if (inGlobStar && !ownProp(this.symlinks, abs)) - return this._readdirInGlobStar(abs, cb) - - if (ownProp(this.cache, abs)) { - var c = this.cache[abs] - if (!c || c === 'FILE') - return cb() - - if (Array.isArray(c)) - return cb(null, c) - } - - var self = this - self.fs.readdir(abs, readdirCb(this, abs, cb)) -} - -function readdirCb (self, abs, cb) { - return function (er, entries) { - if (er) - self._readdirError(abs, er, cb) - else - self._readdirEntries(abs, entries, cb) - } -} - -Glob.prototype._readdirEntries = function (abs, entries, cb) { - if (this.aborted) - return - - // if we haven't asked to stat everything, then just - // assume that everything in there exists, so we can avoid - // having to stat it a second time. - if (!this.mark && !this.stat) { - for (var i = 0; i < entries.length; i ++) { - var e = entries[i] - if (abs === '/') - e = abs + e - else - e = abs + '/' + e - this.cache[e] = true - } - } - - this.cache[abs] = entries - return cb(null, entries) -} - -Glob.prototype._readdirError = function (f, er, cb) { - if (this.aborted) - return - - // handle errors, and cache the information - switch (er.code) { - case 'ENOTSUP': // https://github.com/isaacs/node-glob/issues/205 - case 'ENOTDIR': // totally normal. means it *does* exist. - var abs = this._makeAbs(f) - this.cache[abs] = 'FILE' - if (abs === this.cwdAbs) { - var error = new Error(er.code + ' invalid cwd ' + this.cwd) - error.path = this.cwd - error.code = er.code - this.emit('error', error) - this.abort() - } - break - - case 'ENOENT': // not terribly unusual - case 'ELOOP': - case 'ENAMETOOLONG': - case 'UNKNOWN': - this.cache[this._makeAbs(f)] = false - break - - default: // some unusual error. Treat as failure. - this.cache[this._makeAbs(f)] = false - if (this.strict) { - this.emit('error', er) - // If the error is handled, then we abort - // if not, we threw out of here - this.abort() - } - if (!this.silent) - console.error('glob error', er) - break - } - - return cb() -} - -Glob.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar, cb) { - var self = this - this._readdir(abs, inGlobStar, function (er, entries) { - self._processGlobStar2(prefix, read, abs, remain, index, inGlobStar, entries, cb) - }) -} - - -Glob.prototype._processGlobStar2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) { - //console.error('pgs2', prefix, remain[0], entries) - - // no entries means not a dir, so it can never have matches - // foo.txt/** doesn't match foo.txt - if (!entries) - return cb() - - // test without the globstar, and with every child both below - // and replacing the globstar. - var remainWithoutGlobStar = remain.slice(1) - var gspref = prefix ? [ prefix ] : [] - var noGlobStar = gspref.concat(remainWithoutGlobStar) - - // the noGlobStar pattern exits the inGlobStar state - this._process(noGlobStar, index, false, cb) - - var isSym = this.symlinks[abs] - var len = entries.length - - // If it's a symlink, and we're in a globstar, then stop - if (isSym && inGlobStar) - return cb() - - for (var i = 0; i < len; i++) { - var e = entries[i] - if (e.charAt(0) === '.' && !this.dot) - continue - - // these two cases enter the inGlobStar state - var instead = gspref.concat(entries[i], remainWithoutGlobStar) - this._process(instead, index, true, cb) - - var below = gspref.concat(entries[i], remain) - this._process(below, index, true, cb) - } - - cb() -} - -Glob.prototype._processSimple = function (prefix, index, cb) { - // XXX review this. Shouldn't it be doing the mounting etc - // before doing stat? kinda weird? - var self = this - this._stat(prefix, function (er, exists) { - self._processSimple2(prefix, index, er, exists, cb) - }) -} -Glob.prototype._processSimple2 = function (prefix, index, er, exists, cb) { - - //console.error('ps2', prefix, exists) - - if (!this.matches[index]) - this.matches[index] = Object.create(null) - - // If it doesn't exist, then just mark the lack of results - if (!exists) - return cb() - - if (prefix && isAbsolute(prefix) && !this.nomount) { - var trail = /[\/\\]$/.test(prefix) - if (prefix.charAt(0) === '/') { - prefix = path.join(this.root, prefix) - } else { - prefix = path.resolve(this.root, prefix) - if (trail) - prefix += '/' - } - } - - if (process.platform === 'win32') - prefix = prefix.replace(/\\/g, '/') - - // Mark this as a match - this._emitMatch(index, prefix) - cb() -} - -// Returns either 'DIR', 'FILE', or false -Glob.prototype._stat = function (f, cb) { - var abs = this._makeAbs(f) - var needDir = f.slice(-1) === '/' - - if (f.length > this.maxLength) - return cb() - - if (!this.stat && ownProp(this.cache, abs)) { - var c = this.cache[abs] - - if (Array.isArray(c)) - c = 'DIR' - - // It exists, but maybe not how we need it - if (!needDir || c === 'DIR') - return cb(null, c) - - if (needDir && c === 'FILE') - return cb() - - // otherwise we have to stat, because maybe c=true - // if we know it exists, but not what it is. - } - - var exists - var stat = this.statCache[abs] - if (stat !== undefined) { - if (stat === false) - return cb(null, stat) - else { - var type = stat.isDirectory() ? 'DIR' : 'FILE' - if (needDir && type === 'FILE') - return cb() - else - return cb(null, type, stat) - } - } - - var self = this - var statcb = inflight('stat\0' + abs, lstatcb_) - if (statcb) - self.fs.lstat(abs, statcb) - - function lstatcb_ (er, lstat) { - if (lstat && lstat.isSymbolicLink()) { - // If it's a symlink, then treat it as the target, unless - // the target does not exist, then treat it as a file. - return self.fs.stat(abs, function (er, stat) { - if (er) - self._stat2(f, abs, null, lstat, cb) - else - self._stat2(f, abs, er, stat, cb) - }) - } else { - self._stat2(f, abs, er, lstat, cb) - } - } -} - -Glob.prototype._stat2 = function (f, abs, er, stat, cb) { - if (er && (er.code === 'ENOENT' || er.code === 'ENOTDIR')) { - this.statCache[abs] = false - return cb() - } - - var needDir = f.slice(-1) === '/' - this.statCache[abs] = stat - - if (abs.slice(-1) === '/' && stat && !stat.isDirectory()) - return cb(null, false, stat) - - var c = true - if (stat) - c = stat.isDirectory() ? 'DIR' : 'FILE' - this.cache[abs] = this.cache[abs] || c - - if (needDir && c === 'FILE') - return cb() - - return cb(null, c, stat) -} diff --git a/node_modules/node-gyp/node_modules/cacache/node_modules/glob/package.json b/node_modules/node-gyp/node_modules/cacache/node_modules/glob/package.json deleted file mode 100644 index ca0fd916211b5..0000000000000 --- a/node_modules/node-gyp/node_modules/cacache/node_modules/glob/package.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "author": "Isaac Z. Schlueter (http://blog.izs.me/)", - "name": "glob", - "description": "a little globber", - "version": "8.1.0", - "repository": { - "type": "git", - "url": "git://github.com/isaacs/node-glob.git" - }, - "main": "glob.js", - "files": [ - "glob.js", - "sync.js", - "common.js" - ], - "engines": { - "node": ">=12" - }, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "devDependencies": { - "memfs": "^3.2.0", - "mkdirp": "0", - "rimraf": "^2.2.8", - "tap": "^16.0.1", - "tick": "0.0.6" - }, - "tap": { - "before": "test/00-setup.js", - "after": "test/zz-cleanup.js", - "statements": 90, - "branches": 90, - "functions": 90, - "lines": 90, - "jobs": 1 - }, - "scripts": { - "prepublish": "npm run benchclean", - "profclean": "rm -f v8.log profile.txt", - "test": "tap", - "test-regen": "npm run profclean && TEST_REGEN=1 node test/00-setup.js", - "bench": "bash benchmark.sh", - "prof": "bash prof.sh && cat profile.txt", - "benchclean": "node benchclean.js" - }, - "license": "ISC", - "funding": { - "url": "https://github.com/sponsors/isaacs" - } -} diff --git a/node_modules/node-gyp/node_modules/cacache/node_modules/glob/sync.js b/node_modules/node-gyp/node_modules/cacache/node_modules/glob/sync.js deleted file mode 100644 index af4600dd59508..0000000000000 --- a/node_modules/node-gyp/node_modules/cacache/node_modules/glob/sync.js +++ /dev/null @@ -1,486 +0,0 @@ -module.exports = globSync -globSync.GlobSync = GlobSync - -var rp = require('fs.realpath') -var minimatch = require('minimatch') -var Minimatch = minimatch.Minimatch -var Glob = require('./glob.js').Glob -var util = require('util') -var path = require('path') -var assert = require('assert') -var isAbsolute = require('path').isAbsolute -var common = require('./common.js') -var setopts = common.setopts -var ownProp = common.ownProp -var childrenIgnored = common.childrenIgnored -var isIgnored = common.isIgnored - -function globSync (pattern, options) { - if (typeof options === 'function' || arguments.length === 3) - throw new TypeError('callback provided to sync glob\n'+ - 'See: https://github.com/isaacs/node-glob/issues/167') - - return new GlobSync(pattern, options).found -} - -function GlobSync (pattern, options) { - if (!pattern) - throw new Error('must provide pattern') - - if (typeof options === 'function' || arguments.length === 3) - throw new TypeError('callback provided to sync glob\n'+ - 'See: https://github.com/isaacs/node-glob/issues/167') - - if (!(this instanceof GlobSync)) - return new GlobSync(pattern, options) - - setopts(this, pattern, options) - - if (this.noprocess) - return this - - var n = this.minimatch.set.length - this.matches = new Array(n) - for (var i = 0; i < n; i ++) { - this._process(this.minimatch.set[i], i, false) - } - this._finish() -} - -GlobSync.prototype._finish = function () { - assert.ok(this instanceof GlobSync) - if (this.realpath) { - var self = this - this.matches.forEach(function (matchset, index) { - var set = self.matches[index] = Object.create(null) - for (var p in matchset) { - try { - p = self._makeAbs(p) - var real = rp.realpathSync(p, self.realpathCache) - set[real] = true - } catch (er) { - if (er.syscall === 'stat') - set[self._makeAbs(p)] = true - else - throw er - } - } - }) - } - common.finish(this) -} - - -GlobSync.prototype._process = function (pattern, index, inGlobStar) { - assert.ok(this instanceof GlobSync) - - // Get the first [n] parts of pattern that are all strings. - var n = 0 - while (typeof pattern[n] === 'string') { - n ++ - } - // now n is the index of the first one that is *not* a string. - - // See if there's anything else - var prefix - switch (n) { - // if not, then this is rather simple - case pattern.length: - this._processSimple(pattern.join('/'), index) - return - - case 0: - // pattern *starts* with some non-trivial item. - // going to readdir(cwd), but not include the prefix in matches. - prefix = null - break - - default: - // pattern has some string bits in the front. - // whatever it starts with, whether that's 'absolute' like /foo/bar, - // or 'relative' like '../baz' - prefix = pattern.slice(0, n).join('/') - break - } - - var remain = pattern.slice(n) - - // get the list of entries. - var read - if (prefix === null) - read = '.' - else if (isAbsolute(prefix) || - isAbsolute(pattern.map(function (p) { - return typeof p === 'string' ? p : '[*]' - }).join('/'))) { - if (!prefix || !isAbsolute(prefix)) - prefix = '/' + prefix - read = prefix - } else - read = prefix - - var abs = this._makeAbs(read) - - //if ignored, skip processing - if (childrenIgnored(this, read)) - return - - var isGlobStar = remain[0] === minimatch.GLOBSTAR - if (isGlobStar) - this._processGlobStar(prefix, read, abs, remain, index, inGlobStar) - else - this._processReaddir(prefix, read, abs, remain, index, inGlobStar) -} - - -GlobSync.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar) { - var entries = this._readdir(abs, inGlobStar) - - // if the abs isn't a dir, then nothing can match! - if (!entries) - return - - // It will only match dot entries if it starts with a dot, or if - // dot is set. Stuff like @(.foo|.bar) isn't allowed. - var pn = remain[0] - var negate = !!this.minimatch.negate - var rawGlob = pn._glob - var dotOk = this.dot || rawGlob.charAt(0) === '.' - - var matchedEntries = [] - for (var i = 0; i < entries.length; i++) { - var e = entries[i] - if (e.charAt(0) !== '.' || dotOk) { - var m - if (negate && !prefix) { - m = !e.match(pn) - } else { - m = e.match(pn) - } - if (m) - matchedEntries.push(e) - } - } - - var len = matchedEntries.length - // If there are no matched entries, then nothing matches. - if (len === 0) - return - - // if this is the last remaining pattern bit, then no need for - // an additional stat *unless* the user has specified mark or - // stat explicitly. We know they exist, since readdir returned - // them. - - if (remain.length === 1 && !this.mark && !this.stat) { - if (!this.matches[index]) - this.matches[index] = Object.create(null) - - for (var i = 0; i < len; i ++) { - var e = matchedEntries[i] - if (prefix) { - if (prefix.slice(-1) !== '/') - e = prefix + '/' + e - else - e = prefix + e - } - - if (e.charAt(0) === '/' && !this.nomount) { - e = path.join(this.root, e) - } - this._emitMatch(index, e) - } - // This was the last one, and no stats were needed - return - } - - // now test all matched entries as stand-ins for that part - // of the pattern. - remain.shift() - for (var i = 0; i < len; i ++) { - var e = matchedEntries[i] - var newPattern - if (prefix) - newPattern = [prefix, e] - else - newPattern = [e] - this._process(newPattern.concat(remain), index, inGlobStar) - } -} - - -GlobSync.prototype._emitMatch = function (index, e) { - if (isIgnored(this, e)) - return - - var abs = this._makeAbs(e) - - if (this.mark) - e = this._mark(e) - - if (this.absolute) { - e = abs - } - - if (this.matches[index][e]) - return - - if (this.nodir) { - var c = this.cache[abs] - if (c === 'DIR' || Array.isArray(c)) - return - } - - this.matches[index][e] = true - - if (this.stat) - this._stat(e) -} - - -GlobSync.prototype._readdirInGlobStar = function (abs) { - // follow all symlinked directories forever - // just proceed as if this is a non-globstar situation - if (this.follow) - return this._readdir(abs, false) - - var entries - var lstat - var stat - try { - lstat = this.fs.lstatSync(abs) - } catch (er) { - if (er.code === 'ENOENT') { - // lstat failed, doesn't exist - return null - } - } - - var isSym = lstat && lstat.isSymbolicLink() - this.symlinks[abs] = isSym - - // If it's not a symlink or a dir, then it's definitely a regular file. - // don't bother doing a readdir in that case. - if (!isSym && lstat && !lstat.isDirectory()) - this.cache[abs] = 'FILE' - else - entries = this._readdir(abs, false) - - return entries -} - -GlobSync.prototype._readdir = function (abs, inGlobStar) { - var entries - - if (inGlobStar && !ownProp(this.symlinks, abs)) - return this._readdirInGlobStar(abs) - - if (ownProp(this.cache, abs)) { - var c = this.cache[abs] - if (!c || c === 'FILE') - return null - - if (Array.isArray(c)) - return c - } - - try { - return this._readdirEntries(abs, this.fs.readdirSync(abs)) - } catch (er) { - this._readdirError(abs, er) - return null - } -} - -GlobSync.prototype._readdirEntries = function (abs, entries) { - // if we haven't asked to stat everything, then just - // assume that everything in there exists, so we can avoid - // having to stat it a second time. - if (!this.mark && !this.stat) { - for (var i = 0; i < entries.length; i ++) { - var e = entries[i] - if (abs === '/') - e = abs + e - else - e = abs + '/' + e - this.cache[e] = true - } - } - - this.cache[abs] = entries - - // mark and cache dir-ness - return entries -} - -GlobSync.prototype._readdirError = function (f, er) { - // handle errors, and cache the information - switch (er.code) { - case 'ENOTSUP': // https://github.com/isaacs/node-glob/issues/205 - case 'ENOTDIR': // totally normal. means it *does* exist. - var abs = this._makeAbs(f) - this.cache[abs] = 'FILE' - if (abs === this.cwdAbs) { - var error = new Error(er.code + ' invalid cwd ' + this.cwd) - error.path = this.cwd - error.code = er.code - throw error - } - break - - case 'ENOENT': // not terribly unusual - case 'ELOOP': - case 'ENAMETOOLONG': - case 'UNKNOWN': - this.cache[this._makeAbs(f)] = false - break - - default: // some unusual error. Treat as failure. - this.cache[this._makeAbs(f)] = false - if (this.strict) - throw er - if (!this.silent) - console.error('glob error', er) - break - } -} - -GlobSync.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar) { - - var entries = this._readdir(abs, inGlobStar) - - // no entries means not a dir, so it can never have matches - // foo.txt/** doesn't match foo.txt - if (!entries) - return - - // test without the globstar, and with every child both below - // and replacing the globstar. - var remainWithoutGlobStar = remain.slice(1) - var gspref = prefix ? [ prefix ] : [] - var noGlobStar = gspref.concat(remainWithoutGlobStar) - - // the noGlobStar pattern exits the inGlobStar state - this._process(noGlobStar, index, false) - - var len = entries.length - var isSym = this.symlinks[abs] - - // If it's a symlink, and we're in a globstar, then stop - if (isSym && inGlobStar) - return - - for (var i = 0; i < len; i++) { - var e = entries[i] - if (e.charAt(0) === '.' && !this.dot) - continue - - // these two cases enter the inGlobStar state - var instead = gspref.concat(entries[i], remainWithoutGlobStar) - this._process(instead, index, true) - - var below = gspref.concat(entries[i], remain) - this._process(below, index, true) - } -} - -GlobSync.prototype._processSimple = function (prefix, index) { - // XXX review this. Shouldn't it be doing the mounting etc - // before doing stat? kinda weird? - var exists = this._stat(prefix) - - if (!this.matches[index]) - this.matches[index] = Object.create(null) - - // If it doesn't exist, then just mark the lack of results - if (!exists) - return - - if (prefix && isAbsolute(prefix) && !this.nomount) { - var trail = /[\/\\]$/.test(prefix) - if (prefix.charAt(0) === '/') { - prefix = path.join(this.root, prefix) - } else { - prefix = path.resolve(this.root, prefix) - if (trail) - prefix += '/' - } - } - - if (process.platform === 'win32') - prefix = prefix.replace(/\\/g, '/') - - // Mark this as a match - this._emitMatch(index, prefix) -} - -// Returns either 'DIR', 'FILE', or false -GlobSync.prototype._stat = function (f) { - var abs = this._makeAbs(f) - var needDir = f.slice(-1) === '/' - - if (f.length > this.maxLength) - return false - - if (!this.stat && ownProp(this.cache, abs)) { - var c = this.cache[abs] - - if (Array.isArray(c)) - c = 'DIR' - - // It exists, but maybe not how we need it - if (!needDir || c === 'DIR') - return c - - if (needDir && c === 'FILE') - return false - - // otherwise we have to stat, because maybe c=true - // if we know it exists, but not what it is. - } - - var exists - var stat = this.statCache[abs] - if (!stat) { - var lstat - try { - lstat = this.fs.lstatSync(abs) - } catch (er) { - if (er && (er.code === 'ENOENT' || er.code === 'ENOTDIR')) { - this.statCache[abs] = false - return false - } - } - - if (lstat && lstat.isSymbolicLink()) { - try { - stat = this.fs.statSync(abs) - } catch (er) { - stat = lstat - } - } else { - stat = lstat - } - } - - this.statCache[abs] = stat - - var c = true - if (stat) - c = stat.isDirectory() ? 'DIR' : 'FILE' - - this.cache[abs] = this.cache[abs] || c - - if (needDir && c === 'FILE') - return false - - return c -} - -GlobSync.prototype._mark = function (p) { - return common.mark(this, p) -} - -GlobSync.prototype._makeAbs = function (f) { - return common.makeAbs(this, f) -} diff --git a/node_modules/node-gyp/node_modules/cacache/node_modules/minimatch/LICENSE b/node_modules/node-gyp/node_modules/cacache/node_modules/minimatch/LICENSE deleted file mode 100644 index 1493534e60dce..0000000000000 --- a/node_modules/node-gyp/node_modules/cacache/node_modules/minimatch/LICENSE +++ /dev/null @@ -1,15 +0,0 @@ -The ISC License - -Copyright (c) 2011-2023 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/node-gyp/node_modules/cacache/node_modules/minimatch/lib/path.js b/node_modules/node-gyp/node_modules/cacache/node_modules/minimatch/lib/path.js deleted file mode 100644 index ffe453d9e0557..0000000000000 --- a/node_modules/node-gyp/node_modules/cacache/node_modules/minimatch/lib/path.js +++ /dev/null @@ -1,4 +0,0 @@ -const isWindows = typeof process === 'object' && - process && - process.platform === 'win32' -module.exports = isWindows ? { sep: '\\' } : { sep: '/' } diff --git a/node_modules/node-gyp/node_modules/cacache/node_modules/minimatch/minimatch.js b/node_modules/node-gyp/node_modules/cacache/node_modules/minimatch/minimatch.js deleted file mode 100644 index 6c8bfc35181c6..0000000000000 --- a/node_modules/node-gyp/node_modules/cacache/node_modules/minimatch/minimatch.js +++ /dev/null @@ -1,944 +0,0 @@ -const minimatch = module.exports = (p, pattern, options = {}) => { - assertValidPattern(pattern) - - // shortcut: comments match nothing. - if (!options.nocomment && pattern.charAt(0) === '#') { - return false - } - - return new Minimatch(pattern, options).match(p) -} - -module.exports = minimatch - -const path = require('./lib/path.js') -minimatch.sep = path.sep - -const GLOBSTAR = Symbol('globstar **') -minimatch.GLOBSTAR = GLOBSTAR -const expand = require('brace-expansion') - -const plTypes = { - '!': { open: '(?:(?!(?:', close: '))[^/]*?)'}, - '?': { open: '(?:', close: ')?' }, - '+': { open: '(?:', close: ')+' }, - '*': { open: '(?:', close: ')*' }, - '@': { open: '(?:', close: ')' } -} - -// any single thing other than / -// don't need to escape / when using new RegExp() -const qmark = '[^/]' - -// * => any number of characters -const star = qmark + '*?' - -// ** when dots are allowed. Anything goes, except .. and . -// not (^ or / followed by one or two dots followed by $ or /), -// followed by anything, any number of times. -const twoStarDot = '(?:(?!(?:\\\/|^)(?:\\.{1,2})($|\\\/)).)*?' - -// not a ^ or / followed by a dot, -// followed by anything, any number of times. -const twoStarNoDot = '(?:(?!(?:\\\/|^)\\.).)*?' - -// "abc" -> { a:true, b:true, c:true } -const charSet = s => s.split('').reduce((set, c) => { - set[c] = true - return set -}, {}) - -// characters that need to be escaped in RegExp. -const reSpecials = charSet('().*{}+?[]^$\\!') - -// characters that indicate we have to add the pattern start -const addPatternStartSet = charSet('[.(') - -// normalizes slashes. -const slashSplit = /\/+/ - -minimatch.filter = (pattern, options = {}) => - (p, i, list) => minimatch(p, pattern, options) - -const ext = (a, b = {}) => { - const t = {} - Object.keys(a).forEach(k => t[k] = a[k]) - Object.keys(b).forEach(k => t[k] = b[k]) - return t -} - -minimatch.defaults = def => { - if (!def || typeof def !== 'object' || !Object.keys(def).length) { - return minimatch - } - - const orig = minimatch - - const m = (p, pattern, options) => orig(p, pattern, ext(def, options)) - m.Minimatch = class Minimatch extends orig.Minimatch { - constructor (pattern, options) { - super(pattern, ext(def, options)) - } - } - m.Minimatch.defaults = options => orig.defaults(ext(def, options)).Minimatch - m.filter = (pattern, options) => orig.filter(pattern, ext(def, options)) - m.defaults = options => orig.defaults(ext(def, options)) - m.makeRe = (pattern, options) => orig.makeRe(pattern, ext(def, options)) - m.braceExpand = (pattern, options) => orig.braceExpand(pattern, ext(def, options)) - m.match = (list, pattern, options) => orig.match(list, pattern, ext(def, options)) - - return m -} - - - - - -// Brace expansion: -// a{b,c}d -> abd acd -// a{b,}c -> abc ac -// a{0..3}d -> a0d a1d a2d a3d -// a{b,c{d,e}f}g -> abg acdfg acefg -// a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg -// -// Invalid sets are not expanded. -// a{2..}b -> a{2..}b -// a{b}c -> a{b}c -minimatch.braceExpand = (pattern, options) => braceExpand(pattern, options) - -const braceExpand = (pattern, options = {}) => { - assertValidPattern(pattern) - - // Thanks to Yeting Li for - // improving this regexp to avoid a ReDOS vulnerability. - if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) { - // shortcut. no need to expand. - return [pattern] - } - - return expand(pattern) -} - -const MAX_PATTERN_LENGTH = 1024 * 64 -const assertValidPattern = pattern => { - if (typeof pattern !== 'string') { - throw new TypeError('invalid pattern') - } - - if (pattern.length > MAX_PATTERN_LENGTH) { - throw new TypeError('pattern is too long') - } -} - -// parse a component of the expanded set. -// At this point, no pattern may contain "/" in it -// so we're going to return a 2d array, where each entry is the full -// pattern, split on '/', and then turned into a regular expression. -// A regexp is made at the end which joins each array with an -// escaped /, and another full one which joins each regexp with |. -// -// Following the lead of Bash 4.1, note that "**" only has special meaning -// when it is the *only* thing in a path portion. Otherwise, any series -// of * is equivalent to a single *. Globstar behavior is enabled by -// default, and can be disabled by setting options.noglobstar. -const SUBPARSE = Symbol('subparse') - -minimatch.makeRe = (pattern, options) => - new Minimatch(pattern, options || {}).makeRe() - -minimatch.match = (list, pattern, options = {}) => { - const mm = new Minimatch(pattern, options) - list = list.filter(f => mm.match(f)) - if (mm.options.nonull && !list.length) { - list.push(pattern) - } - return list -} - -// replace stuff like \* with * -const globUnescape = s => s.replace(/\\(.)/g, '$1') -const charUnescape = s => s.replace(/\\([^-\]])/g, '$1') -const regExpEscape = s => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&') -const braExpEscape = s => s.replace(/[[\]\\]/g, '\\$&') - -class Minimatch { - constructor (pattern, options) { - assertValidPattern(pattern) - - if (!options) options = {} - - this.options = options - this.set = [] - this.pattern = pattern - this.windowsPathsNoEscape = !!options.windowsPathsNoEscape || - options.allowWindowsEscape === false - if (this.windowsPathsNoEscape) { - this.pattern = this.pattern.replace(/\\/g, '/') - } - this.regexp = null - this.negate = false - this.comment = false - this.empty = false - this.partial = !!options.partial - - // make the set of regexps etc. - this.make() - } - - debug () {} - - make () { - const pattern = this.pattern - const options = this.options - - // empty patterns and comments match nothing. - if (!options.nocomment && pattern.charAt(0) === '#') { - this.comment = true - return - } - if (!pattern) { - this.empty = true - return - } - - // step 1: figure out negation, etc. - this.parseNegate() - - // step 2: expand braces - let set = this.globSet = this.braceExpand() - - if (options.debug) this.debug = (...args) => console.error(...args) - - this.debug(this.pattern, set) - - // step 3: now we have a set, so turn each one into a series of path-portion - // matching patterns. - // These will be regexps, except in the case of "**", which is - // set to the GLOBSTAR object for globstar behavior, - // and will not contain any / characters - set = this.globParts = set.map(s => s.split(slashSplit)) - - this.debug(this.pattern, set) - - // glob --> regexps - set = set.map((s, si, set) => s.map(this.parse, this)) - - this.debug(this.pattern, set) - - // filter out everything that didn't compile properly. - set = set.filter(s => s.indexOf(false) === -1) - - this.debug(this.pattern, set) - - this.set = set - } - - parseNegate () { - if (this.options.nonegate) return - - const pattern = this.pattern - let negate = false - let negateOffset = 0 - - for (let i = 0; i < pattern.length && pattern.charAt(i) === '!'; i++) { - negate = !negate - negateOffset++ - } - - if (negateOffset) this.pattern = pattern.slice(negateOffset) - this.negate = negate - } - - // set partial to true to test if, for example, - // "/a/b" matches the start of "/*/b/*/d" - // Partial means, if you run out of file before you run - // out of pattern, then that's fine, as long as all - // the parts match. - matchOne (file, pattern, partial) { - var options = this.options - - this.debug('matchOne', - { 'this': this, file: file, pattern: pattern }) - - this.debug('matchOne', file.length, pattern.length) - - for (var fi = 0, - pi = 0, - fl = file.length, - pl = pattern.length - ; (fi < fl) && (pi < pl) - ; fi++, pi++) { - this.debug('matchOne loop') - var p = pattern[pi] - var f = file[fi] - - this.debug(pattern, p, f) - - // should be impossible. - // some invalid regexp stuff in the set. - /* istanbul ignore if */ - if (p === false) return false - - if (p === GLOBSTAR) { - this.debug('GLOBSTAR', [pattern, p, f]) - - // "**" - // a/**/b/**/c would match the following: - // a/b/x/y/z/c - // a/x/y/z/b/c - // a/b/x/b/x/c - // a/b/c - // To do this, take the rest of the pattern after - // the **, and see if it would match the file remainder. - // If so, return success. - // If not, the ** "swallows" a segment, and try again. - // This is recursively awful. - // - // a/**/b/**/c matching a/b/x/y/z/c - // - a matches a - // - doublestar - // - matchOne(b/x/y/z/c, b/**/c) - // - b matches b - // - doublestar - // - matchOne(x/y/z/c, c) -> no - // - matchOne(y/z/c, c) -> no - // - matchOne(z/c, c) -> no - // - matchOne(c, c) yes, hit - var fr = fi - var pr = pi + 1 - if (pr === pl) { - this.debug('** at the end') - // a ** at the end will just swallow the rest. - // We have found a match. - // however, it will not swallow /.x, unless - // options.dot is set. - // . and .. are *never* matched by **, for explosively - // exponential reasons. - for (; fi < fl; fi++) { - if (file[fi] === '.' || file[fi] === '..' || - (!options.dot && file[fi].charAt(0) === '.')) return false - } - return true - } - - // ok, let's see if we can swallow whatever we can. - while (fr < fl) { - var swallowee = file[fr] - - this.debug('\nglobstar while', file, fr, pattern, pr, swallowee) - - // XXX remove this slice. Just pass the start index. - if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) { - this.debug('globstar found match!', fr, fl, swallowee) - // found a match. - return true - } else { - // can't swallow "." or ".." ever. - // can only swallow ".foo" when explicitly asked. - if (swallowee === '.' || swallowee === '..' || - (!options.dot && swallowee.charAt(0) === '.')) { - this.debug('dot detected!', file, fr, pattern, pr) - break - } - - // ** swallows a segment, and continue. - this.debug('globstar swallow a segment, and continue') - fr++ - } - } - - // no match was found. - // However, in partial mode, we can't say this is necessarily over. - // If there's more *pattern* left, then - /* istanbul ignore if */ - if (partial) { - // ran out of file - this.debug('\n>>> no match, partial?', file, fr, pattern, pr) - if (fr === fl) return true - } - return false - } - - // something other than ** - // non-magic patterns just have to match exactly - // patterns with magic have been turned into regexps. - var hit - if (typeof p === 'string') { - hit = f === p - this.debug('string match', p, f, hit) - } else { - hit = f.match(p) - this.debug('pattern match', p, f, hit) - } - - if (!hit) return false - } - - // Note: ending in / means that we'll get a final "" - // at the end of the pattern. This can only match a - // corresponding "" at the end of the file. - // If the file ends in /, then it can only match a - // a pattern that ends in /, unless the pattern just - // doesn't have any more for it. But, a/b/ should *not* - // match "a/b/*", even though "" matches against the - // [^/]*? pattern, except in partial mode, where it might - // simply not be reached yet. - // However, a/b/ should still satisfy a/* - - // now either we fell off the end of the pattern, or we're done. - if (fi === fl && pi === pl) { - // ran out of pattern and filename at the same time. - // an exact hit! - return true - } else if (fi === fl) { - // ran out of file, but still had pattern left. - // this is ok if we're doing the match as part of - // a glob fs traversal. - return partial - } else /* istanbul ignore else */ if (pi === pl) { - // ran out of pattern, still have file left. - // this is only acceptable if we're on the very last - // empty segment of a file with a trailing slash. - // a/* should match a/b/ - return (fi === fl - 1) && (file[fi] === '') - } - - // should be unreachable. - /* istanbul ignore next */ - throw new Error('wtf?') - } - - braceExpand () { - return braceExpand(this.pattern, this.options) - } - - parse (pattern, isSub) { - assertValidPattern(pattern) - - const options = this.options - - // shortcuts - if (pattern === '**') { - if (!options.noglobstar) - return GLOBSTAR - else - pattern = '*' - } - if (pattern === '') return '' - - let re = '' - let hasMagic = false - let escaping = false - // ? => one single character - const patternListStack = [] - const negativeLists = [] - let stateChar - let inClass = false - let reClassStart = -1 - let classStart = -1 - let cs - let pl - let sp - // . and .. never match anything that doesn't start with ., - // even when options.dot is set. However, if the pattern - // starts with ., then traversal patterns can match. - let dotTravAllowed = pattern.charAt(0) === '.' - let dotFileAllowed = options.dot || dotTravAllowed - const patternStart = () => - dotTravAllowed - ? '' - : dotFileAllowed - ? '(?!(?:^|\\/)\\.{1,2}(?:$|\\/))' - : '(?!\\.)' - const subPatternStart = (p) => - p.charAt(0) === '.' - ? '' - : options.dot - ? '(?!(?:^|\\/)\\.{1,2}(?:$|\\/))' - : '(?!\\.)' - - - const clearStateChar = () => { - if (stateChar) { - // we had some state-tracking character - // that wasn't consumed by this pass. - switch (stateChar) { - case '*': - re += star - hasMagic = true - break - case '?': - re += qmark - hasMagic = true - break - default: - re += '\\' + stateChar - break - } - this.debug('clearStateChar %j %j', stateChar, re) - stateChar = false - } - } - - for (let i = 0, c; (i < pattern.length) && (c = pattern.charAt(i)); i++) { - this.debug('%s\t%s %s %j', pattern, i, re, c) - - // skip over any that are escaped. - if (escaping) { - /* istanbul ignore next - completely not allowed, even escaped. */ - if (c === '/') { - return false - } - - if (reSpecials[c]) { - re += '\\' - } - re += c - escaping = false - continue - } - - switch (c) { - /* istanbul ignore next */ - case '/': { - // Should already be path-split by now. - return false - } - - case '\\': - if (inClass && pattern.charAt(i + 1) === '-') { - re += c - continue - } - - clearStateChar() - escaping = true - continue - - // the various stateChar values - // for the "extglob" stuff. - case '?': - case '*': - case '+': - case '@': - case '!': - this.debug('%s\t%s %s %j <-- stateChar', pattern, i, re, c) - - // all of those are literals inside a class, except that - // the glob [!a] means [^a] in regexp - if (inClass) { - this.debug(' in class') - if (c === '!' && i === classStart + 1) c = '^' - re += c - continue - } - - // if we already have a stateChar, then it means - // that there was something like ** or +? in there. - // Handle the stateChar, then proceed with this one. - this.debug('call clearStateChar %j', stateChar) - clearStateChar() - stateChar = c - // if extglob is disabled, then +(asdf|foo) isn't a thing. - // just clear the statechar *now*, rather than even diving into - // the patternList stuff. - if (options.noext) clearStateChar() - continue - - case '(': { - if (inClass) { - re += '(' - continue - } - - if (!stateChar) { - re += '\\(' - continue - } - - const plEntry = { - type: stateChar, - start: i - 1, - reStart: re.length, - open: plTypes[stateChar].open, - close: plTypes[stateChar].close, - } - this.debug(this.pattern, '\t', plEntry) - patternListStack.push(plEntry) - // negation is (?:(?!(?:js)(?:))[^/]*) - re += plEntry.open - // next entry starts with a dot maybe? - if (plEntry.start === 0 && plEntry.type !== '!') { - dotTravAllowed = true - re += subPatternStart(pattern.slice(i + 1)) - } - this.debug('plType %j %j', stateChar, re) - stateChar = false - continue - } - - case ')': { - const plEntry = patternListStack[patternListStack.length - 1] - if (inClass || !plEntry) { - re += '\\)' - continue - } - patternListStack.pop() - - // closing an extglob - clearStateChar() - hasMagic = true - pl = plEntry - // negation is (?:(?!js)[^/]*) - // The others are (?:) - re += pl.close - if (pl.type === '!') { - negativeLists.push(Object.assign(pl, { reEnd: re.length })) - } - continue - } - - case '|': { - const plEntry = patternListStack[patternListStack.length - 1] - if (inClass || !plEntry) { - re += '\\|' - continue - } - - clearStateChar() - re += '|' - // next subpattern can start with a dot? - if (plEntry.start === 0 && plEntry.type !== '!') { - dotTravAllowed = true - re += subPatternStart(pattern.slice(i + 1)) - } - continue - } - - // these are mostly the same in regexp and glob - case '[': - // swallow any state-tracking char before the [ - clearStateChar() - - if (inClass) { - re += '\\' + c - continue - } - - inClass = true - classStart = i - reClassStart = re.length - re += c - continue - - case ']': - // a right bracket shall lose its special - // meaning and represent itself in - // a bracket expression if it occurs - // first in the list. -- POSIX.2 2.8.3.2 - if (i === classStart + 1 || !inClass) { - re += '\\' + c - continue - } - - // split where the last [ was, make sure we don't have - // an invalid re. if so, re-walk the contents of the - // would-be class to re-translate any characters that - // were passed through as-is - // TODO: It would probably be faster to determine this - // without a try/catch and a new RegExp, but it's tricky - // to do safely. For now, this is safe and works. - cs = pattern.substring(classStart + 1, i) - try { - RegExp('[' + braExpEscape(charUnescape(cs)) + ']') - // looks good, finish up the class. - re += c - } catch (er) { - // out of order ranges in JS are errors, but in glob syntax, - // they're just a range that matches nothing. - re = re.substring(0, reClassStart) + '(?:$.)' // match nothing ever - } - hasMagic = true - inClass = false - continue - - default: - // swallow any state char that wasn't consumed - clearStateChar() - - if (reSpecials[c] && !(c === '^' && inClass)) { - re += '\\' - } - - re += c - break - - } // switch - } // for - - // handle the case where we left a class open. - // "[abc" is valid, equivalent to "\[abc" - if (inClass) { - // split where the last [ was, and escape it - // this is a huge pita. We now have to re-walk - // the contents of the would-be class to re-translate - // any characters that were passed through as-is - cs = pattern.slice(classStart + 1) - sp = this.parse(cs, SUBPARSE) - re = re.substring(0, reClassStart) + '\\[' + sp[0] - hasMagic = hasMagic || sp[1] - } - - // handle the case where we had a +( thing at the *end* - // of the pattern. - // each pattern list stack adds 3 chars, and we need to go through - // and escape any | chars that were passed through as-is for the regexp. - // Go through and escape them, taking care not to double-escape any - // | chars that were already escaped. - for (pl = patternListStack.pop(); pl; pl = patternListStack.pop()) { - let tail - tail = re.slice(pl.reStart + pl.open.length) - this.debug('setting tail', re, pl) - // maybe some even number of \, then maybe 1 \, followed by a | - tail = tail.replace(/((?:\\{2}){0,64})(\\?)\|/g, (_, $1, $2) => { - /* istanbul ignore else - should already be done */ - if (!$2) { - // the | isn't already escaped, so escape it. - $2 = '\\' - } - - // need to escape all those slashes *again*, without escaping the - // one that we need for escaping the | character. As it works out, - // escaping an even number of slashes can be done by simply repeating - // it exactly after itself. That's why this trick works. - // - // I am sorry that you have to see this. - return $1 + $1 + $2 + '|' - }) - - this.debug('tail=%j\n %s', tail, tail, pl, re) - const t = pl.type === '*' ? star - : pl.type === '?' ? qmark - : '\\' + pl.type - - hasMagic = true - re = re.slice(0, pl.reStart) + t + '\\(' + tail - } - - // handle trailing things that only matter at the very end. - clearStateChar() - if (escaping) { - // trailing \\ - re += '\\\\' - } - - // only need to apply the nodot start if the re starts with - // something that could conceivably capture a dot - const addPatternStart = addPatternStartSet[re.charAt(0)] - - // Hack to work around lack of negative lookbehind in JS - // A pattern like: *.!(x).!(y|z) needs to ensure that a name - // like 'a.xyz.yz' doesn't match. So, the first negative - // lookahead, has to look ALL the way ahead, to the end of - // the pattern. - for (let n = negativeLists.length - 1; n > -1; n--) { - const nl = negativeLists[n] - - const nlBefore = re.slice(0, nl.reStart) - const nlFirst = re.slice(nl.reStart, nl.reEnd - 8) - let nlAfter = re.slice(nl.reEnd) - const nlLast = re.slice(nl.reEnd - 8, nl.reEnd) + nlAfter - - // Handle nested stuff like *(*.js|!(*.json)), where open parens - // mean that we should *not* include the ) in the bit that is considered - // "after" the negated section. - const closeParensBefore = nlBefore.split(')').length - const openParensBefore = nlBefore.split('(').length - closeParensBefore - let cleanAfter = nlAfter - for (let i = 0; i < openParensBefore; i++) { - cleanAfter = cleanAfter.replace(/\)[+*?]?/, '') - } - nlAfter = cleanAfter - - const dollar = nlAfter === '' && isSub !== SUBPARSE ? '(?:$|\\/)' : '' - - re = nlBefore + nlFirst + nlAfter + dollar + nlLast - } - - // if the re is not "" at this point, then we need to make sure - // it doesn't match against an empty path part. - // Otherwise a/* will match a/, which it should not. - if (re !== '' && hasMagic) { - re = '(?=.)' + re - } - - if (addPatternStart) { - re = patternStart() + re - } - - // parsing just a piece of a larger pattern. - if (isSub === SUBPARSE) { - return [re, hasMagic] - } - - // if it's nocase, and the lcase/uppercase don't match, it's magic - if (options.nocase && !hasMagic) { - hasMagic = pattern.toUpperCase() !== pattern.toLowerCase() - } - - // skip the regexp for non-magical patterns - // unescape anything in it, though, so that it'll be - // an exact match against a file etc. - if (!hasMagic) { - return globUnescape(pattern) - } - - const flags = options.nocase ? 'i' : '' - try { - return Object.assign(new RegExp('^' + re + '$', flags), { - _glob: pattern, - _src: re, - }) - } catch (er) /* istanbul ignore next - should be impossible */ { - // If it was an invalid regular expression, then it can't match - // anything. This trick looks for a character after the end of - // the string, which is of course impossible, except in multi-line - // mode, but it's not a /m regex. - return new RegExp('$.') - } - } - - makeRe () { - if (this.regexp || this.regexp === false) return this.regexp - - // at this point, this.set is a 2d array of partial - // pattern strings, or "**". - // - // It's better to use .match(). This function shouldn't - // be used, really, but it's pretty convenient sometimes, - // when you just want to work with a regex. - const set = this.set - - if (!set.length) { - this.regexp = false - return this.regexp - } - const options = this.options - - const twoStar = options.noglobstar ? star - : options.dot ? twoStarDot - : twoStarNoDot - const flags = options.nocase ? 'i' : '' - - // coalesce globstars and regexpify non-globstar patterns - // if it's the only item, then we just do one twoStar - // if it's the first, and there are more, prepend (\/|twoStar\/)? to next - // if it's the last, append (\/twoStar|) to previous - // if it's in the middle, append (\/|\/twoStar\/) to previous - // then filter out GLOBSTAR symbols - let re = set.map(pattern => { - pattern = pattern.map(p => - typeof p === 'string' ? regExpEscape(p) - : p === GLOBSTAR ? GLOBSTAR - : p._src - ).reduce((set, p) => { - if (!(set[set.length - 1] === GLOBSTAR && p === GLOBSTAR)) { - set.push(p) - } - return set - }, []) - pattern.forEach((p, i) => { - if (p !== GLOBSTAR || pattern[i-1] === GLOBSTAR) { - return - } - if (i === 0) { - if (pattern.length > 1) { - pattern[i+1] = '(?:\\\/|' + twoStar + '\\\/)?' + pattern[i+1] - } else { - pattern[i] = twoStar - } - } else if (i === pattern.length - 1) { - pattern[i-1] += '(?:\\\/|' + twoStar + ')?' - } else { - pattern[i-1] += '(?:\\\/|\\\/' + twoStar + '\\\/)' + pattern[i+1] - pattern[i+1] = GLOBSTAR - } - }) - return pattern.filter(p => p !== GLOBSTAR).join('/') - }).join('|') - - // must match entire pattern - // ending in a * or ** will make it less strict. - re = '^(?:' + re + ')$' - - // can match anything, as long as it's not this. - if (this.negate) re = '^(?!' + re + ').*$' - - try { - this.regexp = new RegExp(re, flags) - } catch (ex) /* istanbul ignore next - should be impossible */ { - this.regexp = false - } - return this.regexp - } - - match (f, partial = this.partial) { - this.debug('match', f, this.pattern) - // short-circuit in the case of busted things. - // comments, etc. - if (this.comment) return false - if (this.empty) return f === '' - - if (f === '/' && partial) return true - - const options = this.options - - // windows: need to use /, not \ - if (path.sep !== '/') { - f = f.split(path.sep).join('/') - } - - // treat the test path as a set of pathparts. - f = f.split(slashSplit) - this.debug(this.pattern, 'split', f) - - // just ONE of the pattern sets in this.set needs to match - // in order for it to be valid. If negating, then just one - // match means that we have failed. - // Either way, return on the first hit. - - const set = this.set - this.debug(this.pattern, 'set', set) - - // Find the basename of the path by looking for the last non-empty segment - let filename - for (let i = f.length - 1; i >= 0; i--) { - filename = f[i] - if (filename) break - } - - for (let i = 0; i < set.length; i++) { - const pattern = set[i] - let file = f - if (options.matchBase && pattern.length === 1) { - file = [filename] - } - const hit = this.matchOne(file, pattern, partial) - if (hit) { - if (options.flipNegate) return true - return !this.negate - } - } - - // didn't get any hits. this is success if it's a negative - // pattern, failure otherwise. - if (options.flipNegate) return false - return this.negate - } - - static defaults (def) { - return minimatch.defaults(def).Minimatch - } -} - -minimatch.Minimatch = Minimatch diff --git a/node_modules/node-gyp/node_modules/cacache/node_modules/minimatch/package.json b/node_modules/node-gyp/node_modules/cacache/node_modules/minimatch/package.json deleted file mode 100644 index c8809dbb3119d..0000000000000 --- a/node_modules/node-gyp/node_modules/cacache/node_modules/minimatch/package.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "author": "Isaac Z. Schlueter (http://blog.izs.me)", - "name": "minimatch", - "description": "a glob matcher in javascript", - "publishConfig": { - "tag": "legacy-v5" - }, - "version": "5.1.6", - "repository": { - "type": "git", - "url": "git://github.com/isaacs/minimatch.git" - }, - "main": "minimatch.js", - "scripts": { - "test": "tap", - "snap": "tap", - "preversion": "npm test", - "postversion": "npm publish", - "prepublishOnly": "git push origin --follow-tags" - }, - "engines": { - "node": ">=10" - }, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "devDependencies": { - "tap": "^16.3.2" - }, - "license": "ISC", - "files": [ - "minimatch.js", - "lib" - ] -} diff --git a/node_modules/node-gyp/node_modules/cacache/package.json b/node_modules/node-gyp/node_modules/cacache/package.json deleted file mode 100644 index 7dbd407d8fccf..0000000000000 --- a/node_modules/node-gyp/node_modules/cacache/package.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "name": "cacache", - "version": "16.1.3", - "cache-version": { - "content": "2", - "index": "5" - }, - "description": "Fast, fault-tolerant, cross-platform, disk-based, data-agnostic, content-addressable cache.", - "main": "lib/index.js", - "files": [ - "bin/", - "lib/" - ], - "scripts": { - "preversion": "npm test", - "postversion": "npm publish", - "prepublishOnly": "git push origin --follow-tags", - "test": "tap", - "snap": "tap", - "coverage": "tap", - "test-docker": "docker run -it --rm --name pacotest -v \"$PWD\":/tmp -w /tmp node:latest npm test", - "lint": "eslint \"**/*.js\"", - "npmclilint": "npmcli-lint", - "lintfix": "npm run lint -- --fix", - "postsnap": "npm run lintfix --", - "postlint": "template-oss-check", - "posttest": "npm run lint", - "template-oss-apply": "template-oss-apply --force" - }, - "repository": { - "type": "git", - "url": "https://github.com/npm/cacache.git" - }, - "keywords": [ - "cache", - "caching", - "content-addressable", - "sri", - "sri hash", - "subresource integrity", - "cache", - "storage", - "store", - "file store", - "filesystem", - "disk cache", - "disk storage" - ], - "license": "ISC", - "dependencies": { - "@npmcli/fs": "^2.1.0", - "@npmcli/move-file": "^2.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "glob": "^8.0.1", - "infer-owner": "^1.0.4", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "mkdirp": "^1.0.4", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", - "tar": "^6.1.11", - "unique-filename": "^2.0.0" - }, - "devDependencies": { - "@npmcli/eslint-config": "^3.0.1", - "@npmcli/template-oss": "3.5.0", - "tap": "^16.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - }, - "templateOSS": { - "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "windowsCI": false, - "version": "3.5.0" - }, - "author": "GitHub Inc." -} diff --git a/node_modules/node-gyp/node_modules/fs-minipass/LICENSE b/node_modules/node-gyp/node_modules/fs-minipass/LICENSE deleted file mode 100644 index 19129e315fe59..0000000000000 --- a/node_modules/node-gyp/node_modules/fs-minipass/LICENSE +++ /dev/null @@ -1,15 +0,0 @@ -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/node-gyp/node_modules/fs-minipass/index.js b/node_modules/node-gyp/node_modules/fs-minipass/index.js deleted file mode 100644 index 9b0779c80c55e..0000000000000 --- a/node_modules/node-gyp/node_modules/fs-minipass/index.js +++ /dev/null @@ -1,422 +0,0 @@ -'use strict' -const MiniPass = require('minipass') -const EE = require('events').EventEmitter -const fs = require('fs') - -let writev = fs.writev -/* istanbul ignore next */ -if (!writev) { - // This entire block can be removed if support for earlier than Node.js - // 12.9.0 is not needed. - const binding = process.binding('fs') - const FSReqWrap = binding.FSReqWrap || binding.FSReqCallback - - writev = (fd, iovec, pos, cb) => { - const done = (er, bw) => cb(er, bw, iovec) - const req = new FSReqWrap() - req.oncomplete = done - binding.writeBuffers(fd, iovec, pos, req) - } -} - -const _autoClose = Symbol('_autoClose') -const _close = Symbol('_close') -const _ended = Symbol('_ended') -const _fd = Symbol('_fd') -const _finished = Symbol('_finished') -const _flags = Symbol('_flags') -const _flush = Symbol('_flush') -const _handleChunk = Symbol('_handleChunk') -const _makeBuf = Symbol('_makeBuf') -const _mode = Symbol('_mode') -const _needDrain = Symbol('_needDrain') -const _onerror = Symbol('_onerror') -const _onopen = Symbol('_onopen') -const _onread = Symbol('_onread') -const _onwrite = Symbol('_onwrite') -const _open = Symbol('_open') -const _path = Symbol('_path') -const _pos = Symbol('_pos') -const _queue = Symbol('_queue') -const _read = Symbol('_read') -const _readSize = Symbol('_readSize') -const _reading = Symbol('_reading') -const _remain = Symbol('_remain') -const _size = Symbol('_size') -const _write = Symbol('_write') -const _writing = Symbol('_writing') -const _defaultFlag = Symbol('_defaultFlag') -const _errored = Symbol('_errored') - -class ReadStream extends MiniPass { - constructor (path, opt) { - opt = opt || {} - super(opt) - - this.readable = true - this.writable = false - - if (typeof path !== 'string') - throw new TypeError('path must be a string') - - this[_errored] = false - this[_fd] = typeof opt.fd === 'number' ? opt.fd : null - this[_path] = path - this[_readSize] = opt.readSize || 16*1024*1024 - this[_reading] = false - this[_size] = typeof opt.size === 'number' ? opt.size : Infinity - this[_remain] = this[_size] - this[_autoClose] = typeof opt.autoClose === 'boolean' ? - opt.autoClose : true - - if (typeof this[_fd] === 'number') - this[_read]() - else - this[_open]() - } - - get fd () { return this[_fd] } - get path () { return this[_path] } - - write () { - throw new TypeError('this is a readable stream') - } - - end () { - throw new TypeError('this is a readable stream') - } - - [_open] () { - fs.open(this[_path], 'r', (er, fd) => this[_onopen](er, fd)) - } - - [_onopen] (er, fd) { - if (er) - this[_onerror](er) - else { - this[_fd] = fd - this.emit('open', fd) - this[_read]() - } - } - - [_makeBuf] () { - return Buffer.allocUnsafe(Math.min(this[_readSize], this[_remain])) - } - - [_read] () { - if (!this[_reading]) { - this[_reading] = true - const buf = this[_makeBuf]() - /* istanbul ignore if */ - if (buf.length === 0) - return process.nextTick(() => this[_onread](null, 0, buf)) - fs.read(this[_fd], buf, 0, buf.length, null, (er, br, buf) => - this[_onread](er, br, buf)) - } - } - - [_onread] (er, br, buf) { - this[_reading] = false - if (er) - this[_onerror](er) - else if (this[_handleChunk](br, buf)) - this[_read]() - } - - [_close] () { - if (this[_autoClose] && typeof this[_fd] === 'number') { - const fd = this[_fd] - this[_fd] = null - fs.close(fd, er => er ? this.emit('error', er) : this.emit('close')) - } - } - - [_onerror] (er) { - this[_reading] = true - this[_close]() - this.emit('error', er) - } - - [_handleChunk] (br, buf) { - let ret = false - // no effect if infinite - this[_remain] -= br - if (br > 0) - ret = super.write(br < buf.length ? buf.slice(0, br) : buf) - - if (br === 0 || this[_remain] <= 0) { - ret = false - this[_close]() - super.end() - } - - return ret - } - - emit (ev, data) { - switch (ev) { - case 'prefinish': - case 'finish': - break - - case 'drain': - if (typeof this[_fd] === 'number') - this[_read]() - break - - case 'error': - if (this[_errored]) - return - this[_errored] = true - return super.emit(ev, data) - - default: - return super.emit(ev, data) - } - } -} - -class ReadStreamSync extends ReadStream { - [_open] () { - let threw = true - try { - this[_onopen](null, fs.openSync(this[_path], 'r')) - threw = false - } finally { - if (threw) - this[_close]() - } - } - - [_read] () { - let threw = true - try { - if (!this[_reading]) { - this[_reading] = true - do { - const buf = this[_makeBuf]() - /* istanbul ignore next */ - const br = buf.length === 0 ? 0 - : fs.readSync(this[_fd], buf, 0, buf.length, null) - if (!this[_handleChunk](br, buf)) - break - } while (true) - this[_reading] = false - } - threw = false - } finally { - if (threw) - this[_close]() - } - } - - [_close] () { - if (this[_autoClose] && typeof this[_fd] === 'number') { - const fd = this[_fd] - this[_fd] = null - fs.closeSync(fd) - this.emit('close') - } - } -} - -class WriteStream extends EE { - constructor (path, opt) { - opt = opt || {} - super(opt) - this.readable = false - this.writable = true - this[_errored] = false - this[_writing] = false - this[_ended] = false - this[_needDrain] = false - this[_queue] = [] - this[_path] = path - this[_fd] = typeof opt.fd === 'number' ? opt.fd : null - this[_mode] = opt.mode === undefined ? 0o666 : opt.mode - this[_pos] = typeof opt.start === 'number' ? opt.start : null - this[_autoClose] = typeof opt.autoClose === 'boolean' ? - opt.autoClose : true - - // truncating makes no sense when writing into the middle - const defaultFlag = this[_pos] !== null ? 'r+' : 'w' - this[_defaultFlag] = opt.flags === undefined - this[_flags] = this[_defaultFlag] ? defaultFlag : opt.flags - - if (this[_fd] === null) - this[_open]() - } - - emit (ev, data) { - if (ev === 'error') { - if (this[_errored]) - return - this[_errored] = true - } - return super.emit(ev, data) - } - - - get fd () { return this[_fd] } - get path () { return this[_path] } - - [_onerror] (er) { - this[_close]() - this[_writing] = true - this.emit('error', er) - } - - [_open] () { - fs.open(this[_path], this[_flags], this[_mode], - (er, fd) => this[_onopen](er, fd)) - } - - [_onopen] (er, fd) { - if (this[_defaultFlag] && - this[_flags] === 'r+' && - er && er.code === 'ENOENT') { - this[_flags] = 'w' - this[_open]() - } else if (er) - this[_onerror](er) - else { - this[_fd] = fd - this.emit('open', fd) - this[_flush]() - } - } - - end (buf, enc) { - if (buf) - this.write(buf, enc) - - this[_ended] = true - - // synthetic after-write logic, where drain/finish live - if (!this[_writing] && !this[_queue].length && - typeof this[_fd] === 'number') - this[_onwrite](null, 0) - return this - } - - write (buf, enc) { - if (typeof buf === 'string') - buf = Buffer.from(buf, enc) - - if (this[_ended]) { - this.emit('error', new Error('write() after end()')) - return false - } - - if (this[_fd] === null || this[_writing] || this[_queue].length) { - this[_queue].push(buf) - this[_needDrain] = true - return false - } - - this[_writing] = true - this[_write](buf) - return true - } - - [_write] (buf) { - fs.write(this[_fd], buf, 0, buf.length, this[_pos], (er, bw) => - this[_onwrite](er, bw)) - } - - [_onwrite] (er, bw) { - if (er) - this[_onerror](er) - else { - if (this[_pos] !== null) - this[_pos] += bw - if (this[_queue].length) - this[_flush]() - else { - this[_writing] = false - - if (this[_ended] && !this[_finished]) { - this[_finished] = true - this[_close]() - this.emit('finish') - } else if (this[_needDrain]) { - this[_needDrain] = false - this.emit('drain') - } - } - } - } - - [_flush] () { - if (this[_queue].length === 0) { - if (this[_ended]) - this[_onwrite](null, 0) - } else if (this[_queue].length === 1) - this[_write](this[_queue].pop()) - else { - const iovec = this[_queue] - this[_queue] = [] - writev(this[_fd], iovec, this[_pos], - (er, bw) => this[_onwrite](er, bw)) - } - } - - [_close] () { - if (this[_autoClose] && typeof this[_fd] === 'number') { - const fd = this[_fd] - this[_fd] = null - fs.close(fd, er => er ? this.emit('error', er) : this.emit('close')) - } - } -} - -class WriteStreamSync extends WriteStream { - [_open] () { - let fd - // only wrap in a try{} block if we know we'll retry, to avoid - // the rethrow obscuring the error's source frame in most cases. - if (this[_defaultFlag] && this[_flags] === 'r+') { - try { - fd = fs.openSync(this[_path], this[_flags], this[_mode]) - } catch (er) { - if (er.code === 'ENOENT') { - this[_flags] = 'w' - return this[_open]() - } else - throw er - } - } else - fd = fs.openSync(this[_path], this[_flags], this[_mode]) - - this[_onopen](null, fd) - } - - [_close] () { - if (this[_autoClose] && typeof this[_fd] === 'number') { - const fd = this[_fd] - this[_fd] = null - fs.closeSync(fd) - this.emit('close') - } - } - - [_write] (buf) { - // throw the original, but try to close if it fails - let threw = true - try { - this[_onwrite](null, - fs.writeSync(this[_fd], buf, 0, buf.length, this[_pos])) - threw = false - } finally { - if (threw) - try { this[_close]() } catch (_) {} - } - } -} - -exports.ReadStream = ReadStream -exports.ReadStreamSync = ReadStreamSync - -exports.WriteStream = WriteStream -exports.WriteStreamSync = WriteStreamSync diff --git a/node_modules/node-gyp/node_modules/fs-minipass/package.json b/node_modules/node-gyp/node_modules/fs-minipass/package.json deleted file mode 100644 index 2f2436cb5c3b1..0000000000000 --- a/node_modules/node-gyp/node_modules/fs-minipass/package.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "fs-minipass", - "version": "2.1.0", - "main": "index.js", - "scripts": { - "test": "tap", - "preversion": "npm test", - "postversion": "npm publish", - "postpublish": "git push origin --follow-tags" - }, - "keywords": [], - "author": "Isaac Z. Schlueter (http://blog.izs.me/)", - "license": "ISC", - "repository": { - "type": "git", - "url": "git+https://github.com/npm/fs-minipass.git" - }, - "bugs": { - "url": "https://github.com/npm/fs-minipass/issues" - }, - "homepage": "https://github.com/npm/fs-minipass#readme", - "description": "fs read and write streams based on minipass", - "dependencies": { - "minipass": "^3.0.0" - }, - "devDependencies": { - "mutate-fs": "^2.0.1", - "tap": "^14.6.4" - }, - "files": [ - "index.js" - ], - "tap": { - "check-coverage": true - }, - "engines": { - "node": ">= 8" - } -} diff --git a/node_modules/node-gyp/node_modules/make-fetch-happen/LICENSE b/node_modules/node-gyp/node_modules/make-fetch-happen/LICENSE deleted file mode 100644 index 1808eb2844231..0000000000000 --- a/node_modules/node-gyp/node_modules/make-fetch-happen/LICENSE +++ /dev/null @@ -1,16 +0,0 @@ -ISC License - -Copyright 2017-2022 (c) npm, Inc. - -Permission to use, copy, modify, and/or distribute this software for -any purpose with or without fee is hereby granted, provided that the -above copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE COPYRIGHT HOLDER DISCLAIMS -ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE -COPYRIGHT HOLDER 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/node-gyp/node_modules/make-fetch-happen/lib/agent.js b/node_modules/node-gyp/node_modules/make-fetch-happen/lib/agent.js deleted file mode 100644 index dd68492ed7ea7..0000000000000 --- a/node_modules/node-gyp/node_modules/make-fetch-happen/lib/agent.js +++ /dev/null @@ -1,214 +0,0 @@ -'use strict' -const LRU = require('lru-cache') -const url = require('url') -const isLambda = require('is-lambda') -const dns = require('./dns.js') - -const AGENT_CACHE = new LRU({ max: 50 }) -const HttpAgent = require('agentkeepalive') -const HttpsAgent = HttpAgent.HttpsAgent - -module.exports = getAgent - -const getAgentTimeout = timeout => - typeof timeout !== 'number' || !timeout ? 0 : timeout + 1 - -const getMaxSockets = maxSockets => maxSockets || 15 - -function getAgent (uri, opts) { - const parsedUri = new url.URL(typeof uri === 'string' ? uri : uri.url) - const isHttps = parsedUri.protocol === 'https:' - const pxuri = getProxyUri(parsedUri.href, opts) - - // If opts.timeout is zero, set the agentTimeout to zero as well. A timeout - // of zero disables the timeout behavior (OS limits still apply). Else, if - // opts.timeout is a non-zero value, set it to timeout + 1, to ensure that - // the node-fetch-npm timeout will always fire first, giving us more - // consistent errors. - const agentTimeout = getAgentTimeout(opts.timeout) - const agentMaxSockets = getMaxSockets(opts.maxSockets) - - const key = [ - `https:${isHttps}`, - pxuri - ? `proxy:${pxuri.protocol}//${pxuri.host}:${pxuri.port}` - : '>no-proxy<', - `local-address:${opts.localAddress || '>no-local-address<'}`, - `strict-ssl:${isHttps ? opts.rejectUnauthorized : '>no-strict-ssl<'}`, - `ca:${(isHttps && opts.ca) || '>no-ca<'}`, - `cert:${(isHttps && opts.cert) || '>no-cert<'}`, - `key:${(isHttps && opts.key) || '>no-key<'}`, - `timeout:${agentTimeout}`, - `maxSockets:${agentMaxSockets}`, - ].join(':') - - if (opts.agent != null) { // `agent: false` has special behavior! - return opts.agent - } - - // keep alive in AWS lambda makes no sense - const lambdaAgent = !isLambda ? null - : isHttps ? require('https').globalAgent - : require('http').globalAgent - - if (isLambda && !pxuri) { - return lambdaAgent - } - - if (AGENT_CACHE.peek(key)) { - return AGENT_CACHE.get(key) - } - - if (pxuri) { - const pxopts = isLambda ? { - ...opts, - agent: lambdaAgent, - } : opts - const proxy = getProxy(pxuri, pxopts, isHttps) - AGENT_CACHE.set(key, proxy) - return proxy - } - - const agent = isHttps ? new HttpsAgent({ - maxSockets: agentMaxSockets, - ca: opts.ca, - cert: opts.cert, - key: opts.key, - localAddress: opts.localAddress, - rejectUnauthorized: opts.rejectUnauthorized, - timeout: agentTimeout, - freeSocketTimeout: 15000, - lookup: dns.getLookup(opts.dns), - }) : new HttpAgent({ - maxSockets: agentMaxSockets, - localAddress: opts.localAddress, - timeout: agentTimeout, - freeSocketTimeout: 15000, - lookup: dns.getLookup(opts.dns), - }) - AGENT_CACHE.set(key, agent) - return agent -} - -function checkNoProxy (uri, opts) { - const host = new url.URL(uri).hostname.split('.').reverse() - let noproxy = (opts.noProxy || getProcessEnv('no_proxy')) - if (typeof noproxy === 'string') { - noproxy = noproxy.split(',').map(n => n.trim()) - } - - return noproxy && noproxy.some(no => { - const noParts = no.split('.').filter(x => x).reverse() - if (!noParts.length) { - return false - } - for (let i = 0; i < noParts.length; i++) { - if (host[i] !== noParts[i]) { - return false - } - } - return true - }) -} - -module.exports.getProcessEnv = getProcessEnv - -function getProcessEnv (env) { - if (!env) { - return - } - - let value - - if (Array.isArray(env)) { - for (const e of env) { - value = process.env[e] || - process.env[e.toUpperCase()] || - process.env[e.toLowerCase()] - if (typeof value !== 'undefined') { - break - } - } - } - - if (typeof env === 'string') { - value = process.env[env] || - process.env[env.toUpperCase()] || - process.env[env.toLowerCase()] - } - - return value -} - -module.exports.getProxyUri = getProxyUri -function getProxyUri (uri, opts) { - const protocol = new url.URL(uri).protocol - - const proxy = opts.proxy || - ( - protocol === 'https:' && - getProcessEnv('https_proxy') - ) || - ( - protocol === 'http:' && - getProcessEnv(['https_proxy', 'http_proxy', 'proxy']) - ) - if (!proxy) { - return null - } - - const parsedProxy = (typeof proxy === 'string') ? new url.URL(proxy) : proxy - - return !checkNoProxy(uri, opts) && parsedProxy -} - -const getAuth = u => - u.username && u.password ? decodeURIComponent(`${u.username}:${u.password}`) - : u.username ? decodeURIComponent(u.username) - : null - -const getPath = u => u.pathname + u.search + u.hash - -const HttpProxyAgent = require('http-proxy-agent') -const HttpsProxyAgent = require('https-proxy-agent') -const { SocksProxyAgent } = require('socks-proxy-agent') -module.exports.getProxy = getProxy -function getProxy (proxyUrl, opts, isHttps) { - // our current proxy agents do not support an overridden dns lookup method, so will not - // benefit from the dns cache - const popts = { - host: proxyUrl.hostname, - port: proxyUrl.port, - protocol: proxyUrl.protocol, - path: getPath(proxyUrl), - auth: getAuth(proxyUrl), - ca: opts.ca, - cert: opts.cert, - key: opts.key, - timeout: getAgentTimeout(opts.timeout), - localAddress: opts.localAddress, - maxSockets: getMaxSockets(opts.maxSockets), - rejectUnauthorized: opts.rejectUnauthorized, - } - - if (proxyUrl.protocol === 'http:' || proxyUrl.protocol === 'https:') { - if (!isHttps) { - return new HttpProxyAgent(popts) - } else { - return new HttpsProxyAgent(popts) - } - } else if (proxyUrl.protocol.startsWith('socks')) { - // socks-proxy-agent uses hostname not host - popts.hostname = popts.host - delete popts.host - return new SocksProxyAgent(popts) - } else { - throw Object.assign( - new Error(`unsupported proxy protocol: '${proxyUrl.protocol}'`), - { - code: 'EUNSUPPORTEDPROXY', - url: proxyUrl.href, - } - ) - } -} diff --git a/node_modules/node-gyp/node_modules/make-fetch-happen/lib/cache/entry.js b/node_modules/node-gyp/node_modules/make-fetch-happen/lib/cache/entry.js deleted file mode 100644 index dba89d715d8a5..0000000000000 --- a/node_modules/node-gyp/node_modules/make-fetch-happen/lib/cache/entry.js +++ /dev/null @@ -1,444 +0,0 @@ -const { Request, Response } = require('minipass-fetch') -const Minipass = require('minipass') -const MinipassFlush = require('minipass-flush') -const cacache = require('cacache') -const url = require('url') - -const CachingMinipassPipeline = require('../pipeline.js') -const CachePolicy = require('./policy.js') -const cacheKey = require('./key.js') -const remote = require('../remote.js') - -const hasOwnProperty = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop) - -// allow list for request headers that will be written to the cache index -// note: we will also store any request headers -// that are named in a response's vary header -const KEEP_REQUEST_HEADERS = [ - 'accept-charset', - 'accept-encoding', - 'accept-language', - 'accept', - 'cache-control', -] - -// allow list for response headers that will be written to the cache index -// note: we must not store the real response's age header, or when we load -// a cache policy based on the metadata it will think the cached response -// is always stale -const KEEP_RESPONSE_HEADERS = [ - 'cache-control', - 'content-encoding', - 'content-language', - 'content-type', - 'date', - 'etag', - 'expires', - 'last-modified', - 'link', - 'location', - 'pragma', - 'vary', -] - -// return an object containing all metadata to be written to the index -const getMetadata = (request, response, options) => { - const metadata = { - time: Date.now(), - url: request.url, - reqHeaders: {}, - resHeaders: {}, - - // options on which we must match the request and vary the response - options: { - compress: options.compress != null ? options.compress : request.compress, - }, - } - - // only save the status if it's not a 200 or 304 - if (response.status !== 200 && response.status !== 304) { - metadata.status = response.status - } - - for (const name of KEEP_REQUEST_HEADERS) { - if (request.headers.has(name)) { - metadata.reqHeaders[name] = request.headers.get(name) - } - } - - // if the request's host header differs from the host in the url - // we need to keep it, otherwise it's just noise and we ignore it - const host = request.headers.get('host') - const parsedUrl = new url.URL(request.url) - if (host && parsedUrl.host !== host) { - metadata.reqHeaders.host = host - } - - // if the response has a vary header, make sure - // we store the relevant request headers too - if (response.headers.has('vary')) { - const vary = response.headers.get('vary') - // a vary of "*" means every header causes a different response. - // in that scenario, we do not include any additional headers - // as the freshness check will always fail anyway and we don't - // want to bloat the cache indexes - if (vary !== '*') { - // copy any other request headers that will vary the response - const varyHeaders = vary.trim().toLowerCase().split(/\s*,\s*/) - for (const name of varyHeaders) { - if (request.headers.has(name)) { - metadata.reqHeaders[name] = request.headers.get(name) - } - } - } - } - - for (const name of KEEP_RESPONSE_HEADERS) { - if (response.headers.has(name)) { - metadata.resHeaders[name] = response.headers.get(name) - } - } - - return metadata -} - -// symbols used to hide objects that may be lazily evaluated in a getter -const _request = Symbol('request') -const _response = Symbol('response') -const _policy = Symbol('policy') - -class CacheEntry { - constructor ({ entry, request, response, options }) { - if (entry) { - this.key = entry.key - this.entry = entry - // previous versions of this module didn't write an explicit timestamp in - // the metadata, so fall back to the entry's timestamp. we can't use the - // entry timestamp to determine staleness because cacache will update it - // when it verifies its data - this.entry.metadata.time = this.entry.metadata.time || this.entry.time - } else { - this.key = cacheKey(request) - } - - this.options = options - - // these properties are behind getters that lazily evaluate - this[_request] = request - this[_response] = response - this[_policy] = null - } - - // returns a CacheEntry instance that satisfies the given request - // or undefined if no existing entry satisfies - static async find (request, options) { - try { - // compacts the index and returns an array of unique entries - var matches = await cacache.index.compact(options.cachePath, cacheKey(request), (A, B) => { - const entryA = new CacheEntry({ entry: A, options }) - const entryB = new CacheEntry({ entry: B, options }) - return entryA.policy.satisfies(entryB.request) - }, { - validateEntry: (entry) => { - // clean out entries with a buggy content-encoding value - if (entry.metadata && - entry.metadata.resHeaders && - entry.metadata.resHeaders['content-encoding'] === null) { - return false - } - - // if an integrity is null, it needs to have a status specified - if (entry.integrity === null) { - return !!(entry.metadata && entry.metadata.status) - } - - return true - }, - }) - } catch (err) { - // if the compact request fails, ignore the error and return - return - } - - // a cache mode of 'reload' means to behave as though we have no cache - // on the way to the network. return undefined to allow cacheFetch to - // create a brand new request no matter what. - if (options.cache === 'reload') { - return - } - - // find the specific entry that satisfies the request - let match - for (const entry of matches) { - const _entry = new CacheEntry({ - entry, - options, - }) - - if (_entry.policy.satisfies(request)) { - match = _entry - break - } - } - - return match - } - - // if the user made a PUT/POST/PATCH then we invalidate our - // cache for the same url by deleting the index entirely - static async invalidate (request, options) { - const key = cacheKey(request) - try { - await cacache.rm.entry(options.cachePath, key, { removeFully: true }) - } catch (err) { - // ignore errors - } - } - - get request () { - if (!this[_request]) { - this[_request] = new Request(this.entry.metadata.url, { - method: 'GET', - headers: this.entry.metadata.reqHeaders, - ...this.entry.metadata.options, - }) - } - - return this[_request] - } - - get response () { - if (!this[_response]) { - this[_response] = new Response(null, { - url: this.entry.metadata.url, - counter: this.options.counter, - status: this.entry.metadata.status || 200, - headers: { - ...this.entry.metadata.resHeaders, - 'content-length': this.entry.size, - }, - }) - } - - return this[_response] - } - - get policy () { - if (!this[_policy]) { - this[_policy] = new CachePolicy({ - entry: this.entry, - request: this.request, - response: this.response, - options: this.options, - }) - } - - return this[_policy] - } - - // wraps the response in a pipeline that stores the data - // in the cache while the user consumes it - async store (status) { - // if we got a status other than 200, 301, or 308, - // or the CachePolicy forbid storage, append the - // cache status header and return it untouched - if ( - this.request.method !== 'GET' || - ![200, 301, 308].includes(this.response.status) || - !this.policy.storable() - ) { - this.response.headers.set('x-local-cache-status', 'skip') - return this.response - } - - const size = this.response.headers.get('content-length') - const cacheOpts = { - algorithms: this.options.algorithms, - metadata: getMetadata(this.request, this.response, this.options), - size, - integrity: this.options.integrity, - integrityEmitter: this.response.body.hasIntegrityEmitter && this.response.body, - } - - let body = null - // we only set a body if the status is a 200, redirects are - // stored as metadata only - if (this.response.status === 200) { - let cacheWriteResolve, cacheWriteReject - const cacheWritePromise = new Promise((resolve, reject) => { - cacheWriteResolve = resolve - cacheWriteReject = reject - }) - - body = new CachingMinipassPipeline({ events: ['integrity', 'size'] }, new MinipassFlush({ - flush () { - return cacheWritePromise - }, - })) - // this is always true since if we aren't reusing the one from the remote fetch, we - // are using the one from cacache - body.hasIntegrityEmitter = true - - const onResume = () => { - const tee = new Minipass() - const cacheStream = cacache.put.stream(this.options.cachePath, this.key, cacheOpts) - // re-emit the integrity and size events on our new response body so they can be reused - cacheStream.on('integrity', i => body.emit('integrity', i)) - cacheStream.on('size', s => body.emit('size', s)) - // stick a flag on here so downstream users will know if they can expect integrity events - tee.pipe(cacheStream) - // TODO if the cache write fails, log a warning but return the response anyway - // eslint-disable-next-line promise/catch-or-return - cacheStream.promise().then(cacheWriteResolve, cacheWriteReject) - body.unshift(tee) - body.unshift(this.response.body) - } - - body.once('resume', onResume) - body.once('end', () => body.removeListener('resume', onResume)) - } else { - await cacache.index.insert(this.options.cachePath, this.key, null, cacheOpts) - } - - // note: we do not set the x-local-cache-hash header because we do not know - // the hash value until after the write to the cache completes, which doesn't - // happen until after the response has been sent and it's too late to write - // the header anyway - this.response.headers.set('x-local-cache', encodeURIComponent(this.options.cachePath)) - this.response.headers.set('x-local-cache-key', encodeURIComponent(this.key)) - this.response.headers.set('x-local-cache-mode', 'stream') - this.response.headers.set('x-local-cache-status', status) - this.response.headers.set('x-local-cache-time', new Date().toISOString()) - const newResponse = new Response(body, { - url: this.response.url, - status: this.response.status, - headers: this.response.headers, - counter: this.options.counter, - }) - return newResponse - } - - // use the cached data to create a response and return it - async respond (method, options, status) { - let response - if (method === 'HEAD' || [301, 308].includes(this.response.status)) { - // if the request is a HEAD, or the response is a redirect, - // then the metadata in the entry already includes everything - // we need to build a response - response = this.response - } else { - // we're responding with a full cached response, so create a body - // that reads from cacache and attach it to a new Response - const body = new Minipass() - const headers = { ...this.policy.responseHeaders() } - const onResume = () => { - const cacheStream = cacache.get.stream.byDigest( - this.options.cachePath, this.entry.integrity, { memoize: this.options.memoize } - ) - cacheStream.on('error', async (err) => { - cacheStream.pause() - if (err.code === 'EINTEGRITY') { - await cacache.rm.content( - this.options.cachePath, this.entry.integrity, { memoize: this.options.memoize } - ) - } - if (err.code === 'ENOENT' || err.code === 'EINTEGRITY') { - await CacheEntry.invalidate(this.request, this.options) - } - body.emit('error', err) - cacheStream.resume() - }) - // emit the integrity and size events based on our metadata so we're consistent - body.emit('integrity', this.entry.integrity) - body.emit('size', Number(headers['content-length'])) - cacheStream.pipe(body) - } - - body.once('resume', onResume) - body.once('end', () => body.removeListener('resume', onResume)) - response = new Response(body, { - url: this.entry.metadata.url, - counter: options.counter, - status: 200, - headers, - }) - } - - response.headers.set('x-local-cache', encodeURIComponent(this.options.cachePath)) - response.headers.set('x-local-cache-hash', encodeURIComponent(this.entry.integrity)) - response.headers.set('x-local-cache-key', encodeURIComponent(this.key)) - response.headers.set('x-local-cache-mode', 'stream') - response.headers.set('x-local-cache-status', status) - response.headers.set('x-local-cache-time', new Date(this.entry.metadata.time).toUTCString()) - return response - } - - // use the provided request along with this cache entry to - // revalidate the stored response. returns a response, either - // from the cache or from the update - async revalidate (request, options) { - const revalidateRequest = new Request(request, { - headers: this.policy.revalidationHeaders(request), - }) - - try { - // NOTE: be sure to remove the headers property from the - // user supplied options, since we have already defined - // them on the new request object. if they're still in the - // options then those will overwrite the ones from the policy - var response = await remote(revalidateRequest, { - ...options, - headers: undefined, - }) - } catch (err) { - // if the network fetch fails, return the stale - // cached response unless it has a cache-control - // of 'must-revalidate' - if (!this.policy.mustRevalidate) { - return this.respond(request.method, options, 'stale') - } - - throw err - } - - if (this.policy.revalidated(revalidateRequest, response)) { - // we got a 304, write a new index to the cache and respond from cache - const metadata = getMetadata(request, response, options) - // 304 responses do not include headers that are specific to the response data - // since they do not include a body, so we copy values for headers that were - // in the old cache entry to the new one, if the new metadata does not already - // include that header - for (const name of KEEP_RESPONSE_HEADERS) { - if ( - !hasOwnProperty(metadata.resHeaders, name) && - hasOwnProperty(this.entry.metadata.resHeaders, name) - ) { - metadata.resHeaders[name] = this.entry.metadata.resHeaders[name] - } - } - - try { - await cacache.index.insert(options.cachePath, this.key, this.entry.integrity, { - size: this.entry.size, - metadata, - }) - } catch (err) { - // if updating the cache index fails, we ignore it and - // respond anyway - } - return this.respond(request.method, options, 'revalidated') - } - - // if we got a modified response, create a new entry based on it - const newEntry = new CacheEntry({ - request, - response, - options, - }) - - // respond with the new entry while writing it to the cache - return newEntry.store('updated') - } -} - -module.exports = CacheEntry diff --git a/node_modules/node-gyp/node_modules/make-fetch-happen/lib/cache/errors.js b/node_modules/node-gyp/node_modules/make-fetch-happen/lib/cache/errors.js deleted file mode 100644 index 67a66573bebe6..0000000000000 --- a/node_modules/node-gyp/node_modules/make-fetch-happen/lib/cache/errors.js +++ /dev/null @@ -1,11 +0,0 @@ -class NotCachedError extends Error { - constructor (url) { - /* eslint-disable-next-line max-len */ - super(`request to ${url} failed: cache mode is 'only-if-cached' but no cached response is available.`) - this.code = 'ENOTCACHED' - } -} - -module.exports = { - NotCachedError, -} diff --git a/node_modules/node-gyp/node_modules/make-fetch-happen/lib/cache/index.js b/node_modules/node-gyp/node_modules/make-fetch-happen/lib/cache/index.js deleted file mode 100644 index 0de49d23fb933..0000000000000 --- a/node_modules/node-gyp/node_modules/make-fetch-happen/lib/cache/index.js +++ /dev/null @@ -1,49 +0,0 @@ -const { NotCachedError } = require('./errors.js') -const CacheEntry = require('./entry.js') -const remote = require('../remote.js') - -// do whatever is necessary to get a Response and return it -const cacheFetch = async (request, options) => { - // try to find a cached entry that satisfies this request - const entry = await CacheEntry.find(request, options) - if (!entry) { - // no cached result, if the cache mode is 'only-if-cached' that's a failure - if (options.cache === 'only-if-cached') { - throw new NotCachedError(request.url) - } - - // otherwise, we make a request, store it and return it - const response = await remote(request, options) - const newEntry = new CacheEntry({ request, response, options }) - return newEntry.store('miss') - } - - // we have a cached response that satisfies this request, however if the cache - // mode is 'no-cache' then we send the revalidation request no matter what - if (options.cache === 'no-cache') { - return entry.revalidate(request, options) - } - - // if the cached entry is not stale, or if the cache mode is 'force-cache' or - // 'only-if-cached' we can respond with the cached entry. set the status - // based on the result of needsRevalidation and respond - const _needsRevalidation = entry.policy.needsRevalidation(request) - if (options.cache === 'force-cache' || - options.cache === 'only-if-cached' || - !_needsRevalidation) { - return entry.respond(request.method, options, _needsRevalidation ? 'stale' : 'hit') - } - - // if we got here, the cache entry is stale so revalidate it - return entry.revalidate(request, options) -} - -cacheFetch.invalidate = async (request, options) => { - if (!options.cachePath) { - return - } - - return CacheEntry.invalidate(request, options) -} - -module.exports = cacheFetch diff --git a/node_modules/node-gyp/node_modules/make-fetch-happen/lib/cache/key.js b/node_modules/node-gyp/node_modules/make-fetch-happen/lib/cache/key.js deleted file mode 100644 index f7684d562b7fa..0000000000000 --- a/node_modules/node-gyp/node_modules/make-fetch-happen/lib/cache/key.js +++ /dev/null @@ -1,17 +0,0 @@ -const { URL, format } = require('url') - -// options passed to url.format() when generating a key -const formatOptions = { - auth: false, - fragment: false, - search: true, - unicode: false, -} - -// returns a string to be used as the cache key for the Request -const cacheKey = (request) => { - const parsed = new URL(request.url) - return `make-fetch-happen:request-cache:${format(parsed, formatOptions)}` -} - -module.exports = cacheKey diff --git a/node_modules/node-gyp/node_modules/make-fetch-happen/lib/cache/policy.js b/node_modules/node-gyp/node_modules/make-fetch-happen/lib/cache/policy.js deleted file mode 100644 index ada3c8600dae9..0000000000000 --- a/node_modules/node-gyp/node_modules/make-fetch-happen/lib/cache/policy.js +++ /dev/null @@ -1,161 +0,0 @@ -const CacheSemantics = require('http-cache-semantics') -const Negotiator = require('negotiator') -const ssri = require('ssri') - -// options passed to http-cache-semantics constructor -const policyOptions = { - shared: false, - ignoreCargoCult: true, -} - -// a fake empty response, used when only testing the -// request for storability -const emptyResponse = { status: 200, headers: {} } - -// returns a plain object representation of the Request -const requestObject = (request) => { - const _obj = { - method: request.method, - url: request.url, - headers: {}, - compress: request.compress, - } - - request.headers.forEach((value, key) => { - _obj.headers[key] = value - }) - - return _obj -} - -// returns a plain object representation of the Response -const responseObject = (response) => { - const _obj = { - status: response.status, - headers: {}, - } - - response.headers.forEach((value, key) => { - _obj.headers[key] = value - }) - - return _obj -} - -class CachePolicy { - constructor ({ entry, request, response, options }) { - this.entry = entry - this.request = requestObject(request) - this.response = responseObject(response) - this.options = options - this.policy = new CacheSemantics(this.request, this.response, policyOptions) - - if (this.entry) { - // if we have an entry, copy the timestamp to the _responseTime - // this is necessary because the CacheSemantics constructor forces - // the value to Date.now() which means a policy created from a - // cache entry is likely to always identify itself as stale - this.policy._responseTime = this.entry.metadata.time - } - } - - // static method to quickly determine if a request alone is storable - static storable (request, options) { - // no cachePath means no caching - if (!options.cachePath) { - return false - } - - // user explicitly asked not to cache - if (options.cache === 'no-store') { - return false - } - - // we only cache GET and HEAD requests - if (!['GET', 'HEAD'].includes(request.method)) { - return false - } - - // otherwise, let http-cache-semantics make the decision - // based on the request's headers - const policy = new CacheSemantics(requestObject(request), emptyResponse, policyOptions) - return policy.storable() - } - - // returns true if the policy satisfies the request - satisfies (request) { - const _req = requestObject(request) - if (this.request.headers.host !== _req.headers.host) { - return false - } - - if (this.request.compress !== _req.compress) { - return false - } - - const negotiatorA = new Negotiator(this.request) - const negotiatorB = new Negotiator(_req) - - if (JSON.stringify(negotiatorA.mediaTypes()) !== JSON.stringify(negotiatorB.mediaTypes())) { - return false - } - - if (JSON.stringify(negotiatorA.languages()) !== JSON.stringify(negotiatorB.languages())) { - return false - } - - if (JSON.stringify(negotiatorA.encodings()) !== JSON.stringify(negotiatorB.encodings())) { - return false - } - - if (this.options.integrity) { - return ssri.parse(this.options.integrity).match(this.entry.integrity) - } - - return true - } - - // returns true if the request and response allow caching - storable () { - return this.policy.storable() - } - - // NOTE: this is a hack to avoid parsing the cache-control - // header ourselves, it returns true if the response's - // cache-control contains must-revalidate - get mustRevalidate () { - return !!this.policy._rescc['must-revalidate'] - } - - // returns true if the cached response requires revalidation - // for the given request - needsRevalidation (request) { - const _req = requestObject(request) - // force method to GET because we only cache GETs - // but can serve a HEAD from a cached GET - _req.method = 'GET' - return !this.policy.satisfiesWithoutRevalidation(_req) - } - - responseHeaders () { - return this.policy.responseHeaders() - } - - // returns a new object containing the appropriate headers - // to send a revalidation request - revalidationHeaders (request) { - const _req = requestObject(request) - return this.policy.revalidationHeaders(_req) - } - - // returns true if the request/response was revalidated - // successfully. returns false if a new response was received - revalidated (request, response) { - const _req = requestObject(request) - const _res = responseObject(response) - const policy = this.policy.revalidatedPolicy(_req, _res) - return !policy.modified - } -} - -module.exports = CachePolicy diff --git a/node_modules/node-gyp/node_modules/make-fetch-happen/lib/dns.js b/node_modules/node-gyp/node_modules/make-fetch-happen/lib/dns.js deleted file mode 100644 index 13102b57c4aa0..0000000000000 --- a/node_modules/node-gyp/node_modules/make-fetch-happen/lib/dns.js +++ /dev/null @@ -1,49 +0,0 @@ -const LRUCache = require('lru-cache') -const dns = require('dns') - -const defaultOptions = exports.defaultOptions = { - family: undefined, - hints: dns.ADDRCONFIG, - all: false, - verbatim: undefined, -} - -const lookupCache = exports.lookupCache = new LRUCache({ max: 50 }) - -// this is a factory so that each request can have its own opts (i.e. ttl) -// while still sharing the cache across all requests -exports.getLookup = (dnsOptions) => { - return (hostname, options, callback) => { - if (typeof options === 'function') { - callback = options - options = null - } else if (typeof options === 'number') { - options = { family: options } - } - - options = { ...defaultOptions, ...options } - - const key = JSON.stringify({ - hostname, - family: options.family, - hints: options.hints, - all: options.all, - verbatim: options.verbatim, - }) - - if (lookupCache.has(key)) { - const [address, family] = lookupCache.get(key) - process.nextTick(callback, null, address, family) - return - } - - dnsOptions.lookup(hostname, options, (err, address, family) => { - if (err) { - return callback(err) - } - - lookupCache.set(key, [address, family], { ttl: dnsOptions.ttl }) - return callback(null, address, family) - }) - } -} diff --git a/node_modules/node-gyp/node_modules/make-fetch-happen/lib/fetch.js b/node_modules/node-gyp/node_modules/make-fetch-happen/lib/fetch.js deleted file mode 100644 index 233ba67e16550..0000000000000 --- a/node_modules/node-gyp/node_modules/make-fetch-happen/lib/fetch.js +++ /dev/null @@ -1,118 +0,0 @@ -'use strict' - -const { FetchError, Request, isRedirect } = require('minipass-fetch') -const url = require('url') - -const CachePolicy = require('./cache/policy.js') -const cache = require('./cache/index.js') -const remote = require('./remote.js') - -// given a Request, a Response and user options -// return true if the response is a redirect that -// can be followed. we throw errors that will result -// in the fetch being rejected if the redirect is -// possible but invalid for some reason -const canFollowRedirect = (request, response, options) => { - if (!isRedirect(response.status)) { - return false - } - - if (options.redirect === 'manual') { - return false - } - - if (options.redirect === 'error') { - throw new FetchError(`redirect mode is set to error: ${request.url}`, - 'no-redirect', { code: 'ENOREDIRECT' }) - } - - if (!response.headers.has('location')) { - throw new FetchError(`redirect location header missing for: ${request.url}`, - 'no-location', { code: 'EINVALIDREDIRECT' }) - } - - if (request.counter >= request.follow) { - throw new FetchError(`maximum redirect reached at: ${request.url}`, - 'max-redirect', { code: 'EMAXREDIRECT' }) - } - - return true -} - -// given a Request, a Response, and the user's options return an object -// with a new Request and a new options object that will be used for -// following the redirect -const getRedirect = (request, response, options) => { - const _opts = { ...options } - const location = response.headers.get('location') - const redirectUrl = new url.URL(location, /^https?:/.test(location) ? undefined : request.url) - // Comment below is used under the following license: - /** - * @license - * Copyright (c) 2010-2012 Mikeal Rogers - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - - // Remove authorization if changing hostnames (but not if just - // changing ports or protocols). This matches the behavior of request: - // https://github.com/request/request/blob/b12a6245/lib/redirect.js#L134-L138 - if (new url.URL(request.url).hostname !== redirectUrl.hostname) { - request.headers.delete('authorization') - request.headers.delete('cookie') - } - - // for POST request with 301/302 response, or any request with 303 response, - // use GET when following redirect - if ( - response.status === 303 || - (request.method === 'POST' && [301, 302].includes(response.status)) - ) { - _opts.method = 'GET' - _opts.body = null - request.headers.delete('content-length') - } - - _opts.headers = {} - request.headers.forEach((value, key) => { - _opts.headers[key] = value - }) - - _opts.counter = ++request.counter - const redirectReq = new Request(url.format(redirectUrl), _opts) - return { - request: redirectReq, - options: _opts, - } -} - -const fetch = async (request, options) => { - const response = CachePolicy.storable(request, options) - ? await cache(request, options) - : await remote(request, options) - - // if the request wasn't a GET or HEAD, and the response - // status is between 200 and 399 inclusive, invalidate the - // request url - if (!['GET', 'HEAD'].includes(request.method) && - response.status >= 200 && - response.status <= 399) { - await cache.invalidate(request, options) - } - - if (!canFollowRedirect(request, response, options)) { - return response - } - - const redirect = getRedirect(request, response, options) - return fetch(redirect.request, redirect.options) -} - -module.exports = fetch diff --git a/node_modules/node-gyp/node_modules/make-fetch-happen/lib/index.js b/node_modules/node-gyp/node_modules/make-fetch-happen/lib/index.js deleted file mode 100644 index 2f12e8e1b6113..0000000000000 --- a/node_modules/node-gyp/node_modules/make-fetch-happen/lib/index.js +++ /dev/null @@ -1,41 +0,0 @@ -const { FetchError, Headers, Request, Response } = require('minipass-fetch') - -const configureOptions = require('./options.js') -const fetch = require('./fetch.js') - -const makeFetchHappen = (url, opts) => { - const options = configureOptions(opts) - - const request = new Request(url, options) - return fetch(request, options) -} - -makeFetchHappen.defaults = (defaultUrl, defaultOptions = {}, wrappedFetch = makeFetchHappen) => { - if (typeof defaultUrl === 'object') { - defaultOptions = defaultUrl - defaultUrl = null - } - - const defaultedFetch = (url, options = {}) => { - const finalUrl = url || defaultUrl - const finalOptions = { - ...defaultOptions, - ...options, - headers: { - ...defaultOptions.headers, - ...options.headers, - }, - } - return wrappedFetch(finalUrl, finalOptions) - } - - defaultedFetch.defaults = (defaultUrl1, defaultOptions1 = {}) => - makeFetchHappen.defaults(defaultUrl1, defaultOptions1, defaultedFetch) - return defaultedFetch -} - -module.exports = makeFetchHappen -module.exports.FetchError = FetchError -module.exports.Headers = Headers -module.exports.Request = Request -module.exports.Response = Response diff --git a/node_modules/node-gyp/node_modules/make-fetch-happen/lib/options.js b/node_modules/node-gyp/node_modules/make-fetch-happen/lib/options.js deleted file mode 100644 index daa9ecd9d5d5f..0000000000000 --- a/node_modules/node-gyp/node_modules/make-fetch-happen/lib/options.js +++ /dev/null @@ -1,52 +0,0 @@ -const dns = require('dns') - -const conditionalHeaders = [ - 'if-modified-since', - 'if-none-match', - 'if-unmodified-since', - 'if-match', - 'if-range', -] - -const configureOptions = (opts) => { - const { strictSSL, ...options } = { ...opts } - options.method = options.method ? options.method.toUpperCase() : 'GET' - options.rejectUnauthorized = strictSSL !== false - - if (!options.retry) { - options.retry = { retries: 0 } - } else if (typeof options.retry === 'string') { - const retries = parseInt(options.retry, 10) - if (isFinite(retries)) { - options.retry = { retries } - } else { - options.retry = { retries: 0 } - } - } else if (typeof options.retry === 'number') { - options.retry = { retries: options.retry } - } else { - options.retry = { retries: 0, ...options.retry } - } - - options.dns = { ttl: 5 * 60 * 1000, lookup: dns.lookup, ...options.dns } - - options.cache = options.cache || 'default' - if (options.cache === 'default') { - const hasConditionalHeader = Object.keys(options.headers || {}).some((name) => { - return conditionalHeaders.includes(name.toLowerCase()) - }) - if (hasConditionalHeader) { - options.cache = 'no-store' - } - } - - // cacheManager is deprecated, but if it's set and - // cachePath is not we should copy it to the new field - if (options.cacheManager && !options.cachePath) { - options.cachePath = options.cacheManager - } - - return options -} - -module.exports = configureOptions diff --git a/node_modules/node-gyp/node_modules/make-fetch-happen/lib/pipeline.js b/node_modules/node-gyp/node_modules/make-fetch-happen/lib/pipeline.js deleted file mode 100644 index b1d221b2d0ce3..0000000000000 --- a/node_modules/node-gyp/node_modules/make-fetch-happen/lib/pipeline.js +++ /dev/null @@ -1,41 +0,0 @@ -'use strict' - -const MinipassPipeline = require('minipass-pipeline') - -class CachingMinipassPipeline extends MinipassPipeline { - #events = [] - #data = new Map() - - constructor (opts, ...streams) { - // CRITICAL: do NOT pass the streams to the call to super(), this will start - // the flow of data and potentially cause the events we need to catch to emit - // before we've finished our own setup. instead we call super() with no args, - // finish our setup, and then push the streams into ourselves to start the - // data flow - super() - this.#events = opts.events - - /* istanbul ignore next - coverage disabled because this is pointless to test here */ - if (streams.length) { - this.push(...streams) - } - } - - on (event, handler) { - if (this.#events.includes(event) && this.#data.has(event)) { - return handler(...this.#data.get(event)) - } - - return super.on(event, handler) - } - - emit (event, ...data) { - if (this.#events.includes(event)) { - this.#data.set(event, data) - } - - return super.emit(event, ...data) - } -} - -module.exports = CachingMinipassPipeline diff --git a/node_modules/node-gyp/node_modules/make-fetch-happen/lib/remote.js b/node_modules/node-gyp/node_modules/make-fetch-happen/lib/remote.js deleted file mode 100644 index 068c73a8a7a7e..0000000000000 --- a/node_modules/node-gyp/node_modules/make-fetch-happen/lib/remote.js +++ /dev/null @@ -1,121 +0,0 @@ -const Minipass = require('minipass') -const fetch = require('minipass-fetch') -const promiseRetry = require('promise-retry') -const ssri = require('ssri') - -const CachingMinipassPipeline = require('./pipeline.js') -const getAgent = require('./agent.js') -const pkg = require('../package.json') - -const USER_AGENT = `${pkg.name}/${pkg.version} (+https://npm.im/${pkg.name})` - -const RETRY_ERRORS = [ - 'ECONNRESET', // remote socket closed on us - 'ECONNREFUSED', // remote host refused to open connection - 'EADDRINUSE', // failed to bind to a local port (proxy?) - 'ETIMEDOUT', // someone in the transaction is WAY TOO SLOW - 'ERR_SOCKET_TIMEOUT', // same as above, but this one comes from agentkeepalive - // Known codes we do NOT retry on: - // ENOTFOUND (getaddrinfo failure. Either bad hostname, or offline) -] - -const RETRY_TYPES = [ - 'request-timeout', -] - -// make a request directly to the remote source, -// retrying certain classes of errors as well as -// following redirects (through the cache if necessary) -// and verifying response integrity -const remoteFetch = (request, options) => { - const agent = getAgent(request.url, options) - if (!request.headers.has('connection')) { - request.headers.set('connection', agent ? 'keep-alive' : 'close') - } - - if (!request.headers.has('user-agent')) { - request.headers.set('user-agent', USER_AGENT) - } - - // keep our own options since we're overriding the agent - // and the redirect mode - const _opts = { - ...options, - agent, - redirect: 'manual', - } - - return promiseRetry(async (retryHandler, attemptNum) => { - const req = new fetch.Request(request, _opts) - try { - let res = await fetch(req, _opts) - if (_opts.integrity && res.status === 200) { - // we got a 200 response and the user has specified an expected - // integrity value, so wrap the response in an ssri stream to verify it - const integrityStream = ssri.integrityStream({ - algorithms: _opts.algorithms, - integrity: _opts.integrity, - size: _opts.size, - }) - const pipeline = new CachingMinipassPipeline({ - events: ['integrity', 'size'], - }, res.body, integrityStream) - // we also propagate the integrity and size events out to the pipeline so we can use - // this new response body as an integrityEmitter for cacache - integrityStream.on('integrity', i => pipeline.emit('integrity', i)) - integrityStream.on('size', s => pipeline.emit('size', s)) - res = new fetch.Response(pipeline, res) - // set an explicit flag so we know if our response body will emit integrity and size - res.body.hasIntegrityEmitter = true - } - - res.headers.set('x-fetch-attempts', attemptNum) - - // do not retry POST requests, or requests with a streaming body - // do retry requests with a 408, 420, 429 or 500+ status in the response - const isStream = Minipass.isStream(req.body) - const isRetriable = req.method !== 'POST' && - !isStream && - ([408, 420, 429].includes(res.status) || res.status >= 500) - - if (isRetriable) { - if (typeof options.onRetry === 'function') { - options.onRetry(res) - } - - return retryHandler(res) - } - - return res - } catch (err) { - const code = (err.code === 'EPROMISERETRY') - ? err.retried.code - : err.code - - // err.retried will be the thing that was thrown from above - // if it's a response, we just got a bad status code and we - // can re-throw to allow the retry - const isRetryError = err.retried instanceof fetch.Response || - (RETRY_ERRORS.includes(code) && RETRY_TYPES.includes(err.type)) - - if (req.method === 'POST' || isRetryError) { - throw err - } - - if (typeof options.onRetry === 'function') { - options.onRetry(err) - } - - return retryHandler(err) - } - }, options.retry).catch((err) => { - // don't reject for http errors, just return them - if (err.status >= 400 && err.type !== 'system') { - return err - } - - throw err - }) -} - -module.exports = remoteFetch diff --git a/node_modules/node-gyp/node_modules/make-fetch-happen/package.json b/node_modules/node-gyp/node_modules/make-fetch-happen/package.json deleted file mode 100644 index fc491d1152e15..0000000000000 --- a/node_modules/node-gyp/node_modules/make-fetch-happen/package.json +++ /dev/null @@ -1,79 +0,0 @@ -{ - "name": "make-fetch-happen", - "version": "10.2.1", - "description": "Opinionated, caching, retrying fetch client", - "main": "lib/index.js", - "files": [ - "bin/", - "lib/" - ], - "scripts": { - "preversion": "npm test", - "postversion": "npm publish", - "prepublishOnly": "git push origin --follow-tags", - "test": "tap", - "posttest": "npm run lint", - "eslint": "eslint", - "lint": "eslint \"**/*.js\"", - "lintfix": "npm run lint -- --fix", - "postlint": "template-oss-check", - "snap": "tap", - "template-oss-apply": "template-oss-apply --force" - }, - "repository": { - "type": "git", - "url": "https://github.com/npm/make-fetch-happen.git" - }, - "keywords": [ - "http", - "request", - "fetch", - "mean girls", - "caching", - "cache", - "subresource integrity" - ], - "author": "GitHub Inc.", - "license": "ISC", - "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^16.1.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^2.0.3", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^9.0.0" - }, - "devDependencies": { - "@npmcli/eslint-config": "^3.0.1", - "@npmcli/template-oss": "3.5.0", - "mkdirp": "^1.0.4", - "nock": "^13.2.4", - "rimraf": "^3.0.2", - "safe-buffer": "^5.2.1", - "standard-version": "^9.3.2", - "tap": "^16.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - }, - "tap": { - "color": 1, - "files": "test/*.js", - "check-coverage": true, - "timeout": 60 - }, - "templateOSS": { - "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "3.5.0" - } -} diff --git a/node_modules/node-gyp/node_modules/minipass-fetch/LICENSE b/node_modules/node-gyp/node_modules/minipass-fetch/LICENSE deleted file mode 100644 index 3c3410cdc12ee..0000000000000 --- a/node_modules/node-gyp/node_modules/minipass-fetch/LICENSE +++ /dev/null @@ -1,28 +0,0 @@ -The MIT License (MIT) - -Copyright (c) Isaac Z. Schlueter and Contributors -Copyright (c) 2016 David Frank - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ---- - -Note: This is a derivative work based on "node-fetch" by David Frank, -modified and distributed under the terms of the MIT license above. -https://github.com/bitinn/node-fetch diff --git a/node_modules/node-gyp/node_modules/minipass-fetch/lib/abort-error.js b/node_modules/node-gyp/node_modules/minipass-fetch/lib/abort-error.js deleted file mode 100644 index b18f643269e37..0000000000000 --- a/node_modules/node-gyp/node_modules/minipass-fetch/lib/abort-error.js +++ /dev/null @@ -1,17 +0,0 @@ -'use strict' -class AbortError extends Error { - constructor (message) { - super(message) - this.code = 'FETCH_ABORTED' - this.type = 'aborted' - Error.captureStackTrace(this, this.constructor) - } - - get name () { - return 'AbortError' - } - - // don't allow name to be overridden, but don't throw either - set name (s) {} -} -module.exports = AbortError diff --git a/node_modules/node-gyp/node_modules/minipass-fetch/lib/blob.js b/node_modules/node-gyp/node_modules/minipass-fetch/lib/blob.js deleted file mode 100644 index efe69a34458af..0000000000000 --- a/node_modules/node-gyp/node_modules/minipass-fetch/lib/blob.js +++ /dev/null @@ -1,97 +0,0 @@ -'use strict' -const Minipass = require('minipass') -const TYPE = Symbol('type') -const BUFFER = Symbol('buffer') - -class Blob { - constructor (blobParts, options) { - this[TYPE] = '' - - const buffers = [] - let size = 0 - - if (blobParts) { - const a = blobParts - const length = Number(a.length) - for (let i = 0; i < length; i++) { - const element = a[i] - const buffer = element instanceof Buffer ? element - : ArrayBuffer.isView(element) - ? Buffer.from(element.buffer, element.byteOffset, element.byteLength) - : element instanceof ArrayBuffer ? Buffer.from(element) - : element instanceof Blob ? element[BUFFER] - : typeof element === 'string' ? Buffer.from(element) - : Buffer.from(String(element)) - size += buffer.length - buffers.push(buffer) - } - } - - this[BUFFER] = Buffer.concat(buffers, size) - - const type = options && options.type !== undefined - && String(options.type).toLowerCase() - if (type && !/[^\u0020-\u007E]/.test(type)) { - this[TYPE] = type - } - } - - get size () { - return this[BUFFER].length - } - - get type () { - return this[TYPE] - } - - text () { - return Promise.resolve(this[BUFFER].toString()) - } - - arrayBuffer () { - const buf = this[BUFFER] - const off = buf.byteOffset - const len = buf.byteLength - const ab = buf.buffer.slice(off, off + len) - return Promise.resolve(ab) - } - - stream () { - return new Minipass().end(this[BUFFER]) - } - - slice (start, end, type) { - const size = this.size - const relativeStart = start === undefined ? 0 - : start < 0 ? Math.max(size + start, 0) - : Math.min(start, size) - const relativeEnd = end === undefined ? size - : end < 0 ? Math.max(size + end, 0) - : Math.min(end, size) - const span = Math.max(relativeEnd - relativeStart, 0) - - const buffer = this[BUFFER] - const slicedBuffer = buffer.slice( - relativeStart, - relativeStart + span - ) - const blob = new Blob([], { type }) - blob[BUFFER] = slicedBuffer - return blob - } - - get [Symbol.toStringTag] () { - return 'Blob' - } - - static get BUFFER () { - return BUFFER - } -} - -Object.defineProperties(Blob.prototype, { - size: { enumerable: true }, - type: { enumerable: true }, -}) - -module.exports = Blob diff --git a/node_modules/node-gyp/node_modules/minipass-fetch/lib/body.js b/node_modules/node-gyp/node_modules/minipass-fetch/lib/body.js deleted file mode 100644 index 9d1b45de30ce9..0000000000000 --- a/node_modules/node-gyp/node_modules/minipass-fetch/lib/body.js +++ /dev/null @@ -1,350 +0,0 @@ -'use strict' -const Minipass = require('minipass') -const MinipassSized = require('minipass-sized') - -const Blob = require('./blob.js') -const { BUFFER } = Blob -const FetchError = require('./fetch-error.js') - -// optional dependency on 'encoding' -let convert -try { - convert = require('encoding').convert -} catch (e) { - // defer error until textConverted is called -} - -const INTERNALS = Symbol('Body internals') -const CONSUME_BODY = Symbol('consumeBody') - -class Body { - constructor (bodyArg, options = {}) { - const { size = 0, timeout = 0 } = options - const body = bodyArg === undefined || bodyArg === null ? null - : isURLSearchParams(bodyArg) ? Buffer.from(bodyArg.toString()) - : isBlob(bodyArg) ? bodyArg - : Buffer.isBuffer(bodyArg) ? bodyArg - : Object.prototype.toString.call(bodyArg) === '[object ArrayBuffer]' - ? Buffer.from(bodyArg) - : ArrayBuffer.isView(bodyArg) - ? Buffer.from(bodyArg.buffer, bodyArg.byteOffset, bodyArg.byteLength) - : Minipass.isStream(bodyArg) ? bodyArg - : Buffer.from(String(bodyArg)) - - this[INTERNALS] = { - body, - disturbed: false, - error: null, - } - - this.size = size - this.timeout = timeout - - if (Minipass.isStream(body)) { - body.on('error', er => { - const error = er.name === 'AbortError' ? er - : new FetchError(`Invalid response while trying to fetch ${ - this.url}: ${er.message}`, 'system', er) - this[INTERNALS].error = error - }) - } - } - - get body () { - return this[INTERNALS].body - } - - get bodyUsed () { - return this[INTERNALS].disturbed - } - - arrayBuffer () { - return this[CONSUME_BODY]().then(buf => - buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength)) - } - - blob () { - const ct = this.headers && this.headers.get('content-type') || '' - return this[CONSUME_BODY]().then(buf => Object.assign( - new Blob([], { type: ct.toLowerCase() }), - { [BUFFER]: buf } - )) - } - - async json () { - const buf = await this[CONSUME_BODY]() - try { - return JSON.parse(buf.toString()) - } catch (er) { - throw new FetchError( - `invalid json response body at ${this.url} reason: ${er.message}`, - 'invalid-json' - ) - } - } - - text () { - return this[CONSUME_BODY]().then(buf => buf.toString()) - } - - buffer () { - return this[CONSUME_BODY]() - } - - textConverted () { - return this[CONSUME_BODY]().then(buf => convertBody(buf, this.headers)) - } - - [CONSUME_BODY] () { - if (this[INTERNALS].disturbed) { - return Promise.reject(new TypeError(`body used already for: ${ - this.url}`)) - } - - this[INTERNALS].disturbed = true - - if (this[INTERNALS].error) { - return Promise.reject(this[INTERNALS].error) - } - - // body is null - if (this.body === null) { - return Promise.resolve(Buffer.alloc(0)) - } - - if (Buffer.isBuffer(this.body)) { - return Promise.resolve(this.body) - } - - const upstream = isBlob(this.body) ? this.body.stream() : this.body - - /* istanbul ignore if: should never happen */ - if (!Minipass.isStream(upstream)) { - return Promise.resolve(Buffer.alloc(0)) - } - - const stream = this.size && upstream instanceof MinipassSized ? upstream - : !this.size && upstream instanceof Minipass && - !(upstream instanceof MinipassSized) ? upstream - : this.size ? new MinipassSized({ size: this.size }) - : new Minipass() - - // allow timeout on slow response body, but only if the stream is still writable. this - // makes the timeout center on the socket stream from lib/index.js rather than the - // intermediary minipass stream we create to receive the data - const resTimeout = this.timeout && stream.writable ? setTimeout(() => { - stream.emit('error', new FetchError( - `Response timeout while trying to fetch ${ - this.url} (over ${this.timeout}ms)`, 'body-timeout')) - }, this.timeout) : null - - // do not keep the process open just for this timeout, even - // though we expect it'll get cleared eventually. - if (resTimeout && resTimeout.unref) { - resTimeout.unref() - } - - // do the pipe in the promise, because the pipe() can send too much - // data through right away and upset the MP Sized object - return new Promise((resolve, reject) => { - // if the stream is some other kind of stream, then pipe through a MP - // so we can collect it more easily. - if (stream !== upstream) { - upstream.on('error', er => stream.emit('error', er)) - upstream.pipe(stream) - } - resolve() - }).then(() => stream.concat()).then(buf => { - clearTimeout(resTimeout) - return buf - }).catch(er => { - clearTimeout(resTimeout) - // request was aborted, reject with this Error - if (er.name === 'AbortError' || er.name === 'FetchError') { - throw er - } else if (er.name === 'RangeError') { - throw new FetchError(`Could not create Buffer from response body for ${ - this.url}: ${er.message}`, 'system', er) - } else { - // other errors, such as incorrect content-encoding or content-length - throw new FetchError(`Invalid response body while trying to fetch ${ - this.url}: ${er.message}`, 'system', er) - } - }) - } - - static clone (instance) { - if (instance.bodyUsed) { - throw new Error('cannot clone body after it is used') - } - - const body = instance.body - - // check that body is a stream and not form-data object - // NB: can't clone the form-data object without having it as a dependency - if (Minipass.isStream(body) && typeof body.getBoundary !== 'function') { - // create a dedicated tee stream so that we don't lose data - // potentially sitting in the body stream's buffer by writing it - // immediately to p1 and not having it for p2. - const tee = new Minipass() - const p1 = new Minipass() - const p2 = new Minipass() - tee.on('error', er => { - p1.emit('error', er) - p2.emit('error', er) - }) - body.on('error', er => tee.emit('error', er)) - tee.pipe(p1) - tee.pipe(p2) - body.pipe(tee) - // set instance body to one fork, return the other - instance[INTERNALS].body = p1 - return p2 - } else { - return instance.body - } - } - - static extractContentType (body) { - return body === null || body === undefined ? null - : typeof body === 'string' ? 'text/plain;charset=UTF-8' - : isURLSearchParams(body) - ? 'application/x-www-form-urlencoded;charset=UTF-8' - : isBlob(body) ? body.type || null - : Buffer.isBuffer(body) ? null - : Object.prototype.toString.call(body) === '[object ArrayBuffer]' ? null - : ArrayBuffer.isView(body) ? null - : typeof body.getBoundary === 'function' - ? `multipart/form-data;boundary=${body.getBoundary()}` - : Minipass.isStream(body) ? null - : 'text/plain;charset=UTF-8' - } - - static getTotalBytes (instance) { - const { body } = instance - return (body === null || body === undefined) ? 0 - : isBlob(body) ? body.size - : Buffer.isBuffer(body) ? body.length - : body && typeof body.getLengthSync === 'function' && ( - // detect form data input from form-data module - body._lengthRetrievers && - /* istanbul ignore next */ body._lengthRetrievers.length === 0 || // 1.x - body.hasKnownLength && body.hasKnownLength()) // 2.x - ? body.getLengthSync() - : null - } - - static writeToStream (dest, instance) { - const { body } = instance - - if (body === null || body === undefined) { - dest.end() - } else if (Buffer.isBuffer(body) || typeof body === 'string') { - dest.end(body) - } else { - // body is stream or blob - const stream = isBlob(body) ? body.stream() : body - stream.on('error', er => dest.emit('error', er)).pipe(dest) - } - - return dest - } -} - -Object.defineProperties(Body.prototype, { - body: { enumerable: true }, - bodyUsed: { enumerable: true }, - arrayBuffer: { enumerable: true }, - blob: { enumerable: true }, - json: { enumerable: true }, - text: { enumerable: true }, -}) - -const isURLSearchParams = obj => - // Duck-typing as a necessary condition. - (typeof obj !== 'object' || - typeof obj.append !== 'function' || - typeof obj.delete !== 'function' || - typeof obj.get !== 'function' || - typeof obj.getAll !== 'function' || - typeof obj.has !== 'function' || - typeof obj.set !== 'function') ? false - // Brand-checking and more duck-typing as optional condition. - : obj.constructor.name === 'URLSearchParams' || - Object.prototype.toString.call(obj) === '[object URLSearchParams]' || - typeof obj.sort === 'function' - -const isBlob = obj => - typeof obj === 'object' && - typeof obj.arrayBuffer === 'function' && - typeof obj.type === 'string' && - typeof obj.stream === 'function' && - typeof obj.constructor === 'function' && - typeof obj.constructor.name === 'string' && - /^(Blob|File)$/.test(obj.constructor.name) && - /^(Blob|File)$/.test(obj[Symbol.toStringTag]) - -const convertBody = (buffer, headers) => { - /* istanbul ignore if */ - if (typeof convert !== 'function') { - throw new Error('The package `encoding` must be installed to use the textConverted() function') - } - - const ct = headers && headers.get('content-type') - let charset = 'utf-8' - let res - - // header - if (ct) { - res = /charset=([^;]*)/i.exec(ct) - } - - // no charset in content type, peek at response body for at most 1024 bytes - const str = buffer.slice(0, 1024).toString() - - // html5 - if (!res && str) { - res = / this.expect - ? 'max-size' : type - this.message = message - Error.captureStackTrace(this, this.constructor) - } - - get name () { - return 'FetchError' - } - - // don't allow name to be overwritten - set name (n) {} - - get [Symbol.toStringTag] () { - return 'FetchError' - } -} -module.exports = FetchError diff --git a/node_modules/node-gyp/node_modules/minipass-fetch/lib/headers.js b/node_modules/node-gyp/node_modules/minipass-fetch/lib/headers.js deleted file mode 100644 index dd6e854d5ba39..0000000000000 --- a/node_modules/node-gyp/node_modules/minipass-fetch/lib/headers.js +++ /dev/null @@ -1,267 +0,0 @@ -'use strict' -const invalidTokenRegex = /[^^_`a-zA-Z\-0-9!#$%&'*+.|~]/ -const invalidHeaderCharRegex = /[^\t\x20-\x7e\x80-\xff]/ - -const validateName = name => { - name = `${name}` - if (invalidTokenRegex.test(name) || name === '') { - throw new TypeError(`${name} is not a legal HTTP header name`) - } -} - -const validateValue = value => { - value = `${value}` - if (invalidHeaderCharRegex.test(value)) { - throw new TypeError(`${value} is not a legal HTTP header value`) - } -} - -const find = (map, name) => { - name = name.toLowerCase() - for (const key in map) { - if (key.toLowerCase() === name) { - return key - } - } - return undefined -} - -const MAP = Symbol('map') -class Headers { - constructor (init = undefined) { - this[MAP] = Object.create(null) - if (init instanceof Headers) { - const rawHeaders = init.raw() - const headerNames = Object.keys(rawHeaders) - for (const headerName of headerNames) { - for (const value of rawHeaders[headerName]) { - this.append(headerName, value) - } - } - return - } - - // no-op - if (init === undefined || init === null) { - return - } - - if (typeof init === 'object') { - const method = init[Symbol.iterator] - if (method !== null && method !== undefined) { - if (typeof method !== 'function') { - throw new TypeError('Header pairs must be iterable') - } - - // sequence> - // Note: per spec we have to first exhaust the lists then process them - const pairs = [] - for (const pair of init) { - if (typeof pair !== 'object' || - typeof pair[Symbol.iterator] !== 'function') { - throw new TypeError('Each header pair must be iterable') - } - const arrPair = Array.from(pair) - if (arrPair.length !== 2) { - throw new TypeError('Each header pair must be a name/value tuple') - } - pairs.push(arrPair) - } - - for (const pair of pairs) { - this.append(pair[0], pair[1]) - } - } else { - // record - for (const key of Object.keys(init)) { - this.append(key, init[key]) - } - } - } else { - throw new TypeError('Provided initializer must be an object') - } - } - - get (name) { - name = `${name}` - validateName(name) - const key = find(this[MAP], name) - if (key === undefined) { - return null - } - - return this[MAP][key].join(', ') - } - - forEach (callback, thisArg = undefined) { - let pairs = getHeaders(this) - for (let i = 0; i < pairs.length; i++) { - const [name, value] = pairs[i] - callback.call(thisArg, value, name, this) - // refresh in case the callback added more headers - pairs = getHeaders(this) - } - } - - set (name, value) { - name = `${name}` - value = `${value}` - validateName(name) - validateValue(value) - const key = find(this[MAP], name) - this[MAP][key !== undefined ? key : name] = [value] - } - - append (name, value) { - name = `${name}` - value = `${value}` - validateName(name) - validateValue(value) - const key = find(this[MAP], name) - if (key !== undefined) { - this[MAP][key].push(value) - } else { - this[MAP][name] = [value] - } - } - - has (name) { - name = `${name}` - validateName(name) - return find(this[MAP], name) !== undefined - } - - delete (name) { - name = `${name}` - validateName(name) - const key = find(this[MAP], name) - if (key !== undefined) { - delete this[MAP][key] - } - } - - raw () { - return this[MAP] - } - - keys () { - return new HeadersIterator(this, 'key') - } - - values () { - return new HeadersIterator(this, 'value') - } - - [Symbol.iterator] () { - return new HeadersIterator(this, 'key+value') - } - - entries () { - return new HeadersIterator(this, 'key+value') - } - - get [Symbol.toStringTag] () { - return 'Headers' - } - - static exportNodeCompatibleHeaders (headers) { - const obj = Object.assign(Object.create(null), headers[MAP]) - - // http.request() only supports string as Host header. This hack makes - // specifying custom Host header possible. - const hostHeaderKey = find(headers[MAP], 'Host') - if (hostHeaderKey !== undefined) { - obj[hostHeaderKey] = obj[hostHeaderKey][0] - } - - return obj - } - - static createHeadersLenient (obj) { - const headers = new Headers() - for (const name of Object.keys(obj)) { - if (invalidTokenRegex.test(name)) { - continue - } - - if (Array.isArray(obj[name])) { - for (const val of obj[name]) { - if (invalidHeaderCharRegex.test(val)) { - continue - } - - if (headers[MAP][name] === undefined) { - headers[MAP][name] = [val] - } else { - headers[MAP][name].push(val) - } - } - } else if (!invalidHeaderCharRegex.test(obj[name])) { - headers[MAP][name] = [obj[name]] - } - } - return headers - } -} - -Object.defineProperties(Headers.prototype, { - get: { enumerable: true }, - forEach: { enumerable: true }, - set: { enumerable: true }, - append: { enumerable: true }, - has: { enumerable: true }, - delete: { enumerable: true }, - keys: { enumerable: true }, - values: { enumerable: true }, - entries: { enumerable: true }, -}) - -const getHeaders = (headers, kind = 'key+value') => - Object.keys(headers[MAP]).sort().map( - kind === 'key' ? k => k.toLowerCase() - : kind === 'value' ? k => headers[MAP][k].join(', ') - : k => [k.toLowerCase(), headers[MAP][k].join(', ')] - ) - -const INTERNAL = Symbol('internal') - -class HeadersIterator { - constructor (target, kind) { - this[INTERNAL] = { - target, - kind, - index: 0, - } - } - - get [Symbol.toStringTag] () { - return 'HeadersIterator' - } - - next () { - /* istanbul ignore if: should be impossible */ - if (!this || Object.getPrototypeOf(this) !== HeadersIterator.prototype) { - throw new TypeError('Value of `this` is not a HeadersIterator') - } - - const { target, kind, index } = this[INTERNAL] - const values = getHeaders(target, kind) - const len = values.length - if (index >= len) { - return { - value: undefined, - done: true, - } - } - - this[INTERNAL].index++ - - return { value: values[index], done: false } - } -} - -// manually extend because 'extends' requires a ctor -Object.setPrototypeOf(HeadersIterator.prototype, - Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]()))) - -module.exports = Headers diff --git a/node_modules/node-gyp/node_modules/minipass-fetch/lib/index.js b/node_modules/node-gyp/node_modules/minipass-fetch/lib/index.js deleted file mode 100644 index b1878ac0c06b5..0000000000000 --- a/node_modules/node-gyp/node_modules/minipass-fetch/lib/index.js +++ /dev/null @@ -1,365 +0,0 @@ -'use strict' -const { URL } = require('url') -const http = require('http') -const https = require('https') -const zlib = require('minizlib') -const Minipass = require('minipass') - -const Body = require('./body.js') -const { writeToStream, getTotalBytes } = Body -const Response = require('./response.js') -const Headers = require('./headers.js') -const { createHeadersLenient } = Headers -const Request = require('./request.js') -const { getNodeRequestOptions } = Request -const FetchError = require('./fetch-error.js') -const AbortError = require('./abort-error.js') - -// XXX this should really be split up and unit-ized for easier testing -// and better DRY implementation of data/http request aborting -const fetch = async (url, opts) => { - if (/^data:/.test(url)) { - const request = new Request(url, opts) - // delay 1 promise tick so that the consumer can abort right away - return Promise.resolve().then(() => new Promise((resolve, reject) => { - let type, data - try { - const { pathname, search } = new URL(url) - const split = pathname.split(',') - if (split.length < 2) { - throw new Error('invalid data: URI') - } - const mime = split.shift() - const base64 = /;base64$/.test(mime) - type = base64 ? mime.slice(0, -1 * ';base64'.length) : mime - const rawData = decodeURIComponent(split.join(',') + search) - data = base64 ? Buffer.from(rawData, 'base64') : Buffer.from(rawData) - } catch (er) { - return reject(new FetchError(`[${request.method}] ${ - request.url} invalid URL, ${er.message}`, 'system', er)) - } - - const { signal } = request - if (signal && signal.aborted) { - return reject(new AbortError('The user aborted a request.')) - } - - const headers = { 'Content-Length': data.length } - if (type) { - headers['Content-Type'] = type - } - return resolve(new Response(data, { headers })) - })) - } - - return new Promise((resolve, reject) => { - // build request object - const request = new Request(url, opts) - let options - try { - options = getNodeRequestOptions(request) - } catch (er) { - return reject(er) - } - - const send = (options.protocol === 'https:' ? https : http).request - const { signal } = request - let response = null - const abort = () => { - const error = new AbortError('The user aborted a request.') - reject(error) - if (Minipass.isStream(request.body) && - typeof request.body.destroy === 'function') { - request.body.destroy(error) - } - if (response && response.body) { - response.body.emit('error', error) - } - } - - if (signal && signal.aborted) { - return abort() - } - - const abortAndFinalize = () => { - abort() - finalize() - } - - const finalize = () => { - req.abort() - if (signal) { - signal.removeEventListener('abort', abortAndFinalize) - } - clearTimeout(reqTimeout) - } - - // send request - const req = send(options) - - if (signal) { - signal.addEventListener('abort', abortAndFinalize) - } - - let reqTimeout = null - if (request.timeout) { - req.once('socket', socket => { - reqTimeout = setTimeout(() => { - reject(new FetchError(`network timeout at: ${ - request.url}`, 'request-timeout')) - finalize() - }, request.timeout) - }) - } - - req.on('error', er => { - // if a 'response' event is emitted before the 'error' event, then by the - // time this handler is run it's too late to reject the Promise for the - // response. instead, we forward the error event to the response stream - // so that the error will surface to the user when they try to consume - // the body. this is done as a side effect of aborting the request except - // for in windows, where we must forward the event manually, otherwise - // there is no longer a ref'd socket attached to the request and the - // stream never ends so the event loop runs out of work and the process - // exits without warning. - // coverage skipped here due to the difficulty in testing - // istanbul ignore next - if (req.res) { - req.res.emit('error', er) - } - reject(new FetchError(`request to ${request.url} failed, reason: ${ - er.message}`, 'system', er)) - finalize() - }) - - req.on('response', res => { - clearTimeout(reqTimeout) - - const headers = createHeadersLenient(res.headers) - - // HTTP fetch step 5 - if (fetch.isRedirect(res.statusCode)) { - // HTTP fetch step 5.2 - const location = headers.get('Location') - - // HTTP fetch step 5.3 - const locationURL = location === null ? null - : (new URL(location, request.url)).toString() - - // HTTP fetch step 5.5 - if (request.redirect === 'error') { - reject(new FetchError('uri requested responds with a redirect, ' + - `redirect mode is set to error: ${request.url}`, 'no-redirect')) - finalize() - return - } else if (request.redirect === 'manual') { - // node-fetch-specific step: make manual redirect a bit easier to - // use by setting the Location header value to the resolved URL. - if (locationURL !== null) { - // handle corrupted header - try { - headers.set('Location', locationURL) - } catch (err) { - /* istanbul ignore next: nodejs server prevent invalid - response headers, we can't test this through normal - request */ - reject(err) - } - } - } else if (request.redirect === 'follow' && locationURL !== null) { - // HTTP-redirect fetch step 5 - if (request.counter >= request.follow) { - reject(new FetchError(`maximum redirect reached at: ${ - request.url}`, 'max-redirect')) - finalize() - return - } - - // HTTP-redirect fetch step 9 - if (res.statusCode !== 303 && - request.body && - getTotalBytes(request) === null) { - reject(new FetchError( - 'Cannot follow redirect with body being a readable stream', - 'unsupported-redirect' - )) - finalize() - return - } - - // Update host due to redirection - request.headers.set('host', (new URL(locationURL)).host) - - // HTTP-redirect fetch step 6 (counter increment) - // Create a new Request object. - const requestOpts = { - headers: new Headers(request.headers), - follow: request.follow, - counter: request.counter + 1, - agent: request.agent, - compress: request.compress, - method: request.method, - body: request.body, - signal: request.signal, - timeout: request.timeout, - } - - // if the redirect is to a new hostname, strip the authorization and cookie headers - const parsedOriginal = new URL(request.url) - const parsedRedirect = new URL(locationURL) - if (parsedOriginal.hostname !== parsedRedirect.hostname) { - requestOpts.headers.delete('authorization') - requestOpts.headers.delete('cookie') - } - - // HTTP-redirect fetch step 11 - if (res.statusCode === 303 || ( - (res.statusCode === 301 || res.statusCode === 302) && - request.method === 'POST' - )) { - requestOpts.method = 'GET' - requestOpts.body = undefined - requestOpts.headers.delete('content-length') - } - - // HTTP-redirect fetch step 15 - resolve(fetch(new Request(locationURL, requestOpts))) - finalize() - return - } - } // end if(isRedirect) - - // prepare response - res.once('end', () => - signal && signal.removeEventListener('abort', abortAndFinalize)) - - const body = new Minipass() - // if an error occurs, either on the response stream itself, on one of the - // decoder streams, or a response length timeout from the Body class, we - // forward the error through to our internal body stream. If we see an - // error event on that, we call finalize to abort the request and ensure - // we don't leave a socket believing a request is in flight. - // this is difficult to test, so lacks specific coverage. - body.on('error', finalize) - // exceedingly rare that the stream would have an error, - // but just in case we proxy it to the stream in use. - res.on('error', /* istanbul ignore next */ er => body.emit('error', er)) - res.on('data', (chunk) => body.write(chunk)) - res.on('end', () => body.end()) - - const responseOptions = { - url: request.url, - status: res.statusCode, - statusText: res.statusMessage, - headers: headers, - size: request.size, - timeout: request.timeout, - counter: request.counter, - trailer: new Promise(resolveTrailer => - res.on('end', () => resolveTrailer(createHeadersLenient(res.trailers)))), - } - - // HTTP-network fetch step 12.1.1.3 - const codings = headers.get('Content-Encoding') - - // HTTP-network fetch step 12.1.1.4: handle content codings - - // in following scenarios we ignore compression support - // 1. compression support is disabled - // 2. HEAD request - // 3. no Content-Encoding header - // 4. no content response (204) - // 5. content not modified response (304) - if (!request.compress || - request.method === 'HEAD' || - codings === null || - res.statusCode === 204 || - res.statusCode === 304) { - response = new Response(body, responseOptions) - resolve(response) - return - } - - // Be less strict when decoding compressed responses, since sometimes - // servers send slightly invalid responses that are still accepted - // by common browsers. - // Always using Z_SYNC_FLUSH is what cURL does. - const zlibOptions = { - flush: zlib.constants.Z_SYNC_FLUSH, - finishFlush: zlib.constants.Z_SYNC_FLUSH, - } - - // for gzip - if (codings === 'gzip' || codings === 'x-gzip') { - const unzip = new zlib.Gunzip(zlibOptions) - response = new Response( - // exceedingly rare that the stream would have an error, - // but just in case we proxy it to the stream in use. - body.on('error', /* istanbul ignore next */ er => unzip.emit('error', er)).pipe(unzip), - responseOptions - ) - resolve(response) - return - } - - // for deflate - if (codings === 'deflate' || codings === 'x-deflate') { - // handle the infamous raw deflate response from old servers - // a hack for old IIS and Apache servers - const raw = res.pipe(new Minipass()) - raw.once('data', chunk => { - // see http://stackoverflow.com/questions/37519828 - const decoder = (chunk[0] & 0x0F) === 0x08 - ? new zlib.Inflate() - : new zlib.InflateRaw() - // exceedingly rare that the stream would have an error, - // but just in case we proxy it to the stream in use. - body.on('error', /* istanbul ignore next */ er => decoder.emit('error', er)).pipe(decoder) - response = new Response(decoder, responseOptions) - resolve(response) - }) - return - } - - // for br - if (codings === 'br') { - // ignoring coverage so tests don't have to fake support (or lack of) for brotli - // istanbul ignore next - try { - var decoder = new zlib.BrotliDecompress() - } catch (err) { - reject(err) - finalize() - return - } - // exceedingly rare that the stream would have an error, - // but just in case we proxy it to the stream in use. - body.on('error', /* istanbul ignore next */ er => decoder.emit('error', er)).pipe(decoder) - response = new Response(decoder, responseOptions) - resolve(response) - return - } - - // otherwise, use response as-is - response = new Response(body, responseOptions) - resolve(response) - }) - - writeToStream(req, request) - }) -} - -module.exports = fetch - -fetch.isRedirect = code => - code === 301 || - code === 302 || - code === 303 || - code === 307 || - code === 308 - -fetch.Headers = Headers -fetch.Request = Request -fetch.Response = Response -fetch.FetchError = FetchError -fetch.AbortError = AbortError diff --git a/node_modules/node-gyp/node_modules/minipass-fetch/lib/request.js b/node_modules/node-gyp/node_modules/minipass-fetch/lib/request.js deleted file mode 100644 index e620df6de2c01..0000000000000 --- a/node_modules/node-gyp/node_modules/minipass-fetch/lib/request.js +++ /dev/null @@ -1,281 +0,0 @@ -'use strict' -const { URL } = require('url') -const Minipass = require('minipass') -const Headers = require('./headers.js') -const { exportNodeCompatibleHeaders } = Headers -const Body = require('./body.js') -const { clone, extractContentType, getTotalBytes } = Body - -const version = require('../package.json').version -const defaultUserAgent = - `minipass-fetch/${version} (+https://github.com/isaacs/minipass-fetch)` - -const INTERNALS = Symbol('Request internals') - -const isRequest = input => - typeof input === 'object' && typeof input[INTERNALS] === 'object' - -const isAbortSignal = signal => { - const proto = ( - signal - && typeof signal === 'object' - && Object.getPrototypeOf(signal) - ) - return !!(proto && proto.constructor.name === 'AbortSignal') -} - -class Request extends Body { - constructor (input, init = {}) { - const parsedURL = isRequest(input) ? new URL(input.url) - : input && input.href ? new URL(input.href) - : new URL(`${input}`) - - if (isRequest(input)) { - init = { ...input[INTERNALS], ...init } - } else if (!input || typeof input === 'string') { - input = {} - } - - const method = (init.method || input.method || 'GET').toUpperCase() - const isGETHEAD = method === 'GET' || method === 'HEAD' - - if ((init.body !== null && init.body !== undefined || - isRequest(input) && input.body !== null) && isGETHEAD) { - throw new TypeError('Request with GET/HEAD method cannot have body') - } - - const inputBody = init.body !== null && init.body !== undefined ? init.body - : isRequest(input) && input.body !== null ? clone(input) - : null - - super(inputBody, { - timeout: init.timeout || input.timeout || 0, - size: init.size || input.size || 0, - }) - - const headers = new Headers(init.headers || input.headers || {}) - - if (inputBody !== null && inputBody !== undefined && - !headers.has('Content-Type')) { - const contentType = extractContentType(inputBody) - if (contentType) { - headers.append('Content-Type', contentType) - } - } - - const signal = 'signal' in init ? init.signal - : null - - if (signal !== null && signal !== undefined && !isAbortSignal(signal)) { - throw new TypeError('Expected signal must be an instanceof AbortSignal') - } - - // TLS specific options that are handled by node - const { - ca, - cert, - ciphers, - clientCertEngine, - crl, - dhparam, - ecdhCurve, - family, - honorCipherOrder, - key, - passphrase, - pfx, - rejectUnauthorized = process.env.NODE_TLS_REJECT_UNAUTHORIZED !== '0', - secureOptions, - secureProtocol, - servername, - sessionIdContext, - } = init - - this[INTERNALS] = { - method, - redirect: init.redirect || input.redirect || 'follow', - headers, - parsedURL, - signal, - ca, - cert, - ciphers, - clientCertEngine, - crl, - dhparam, - ecdhCurve, - family, - honorCipherOrder, - key, - passphrase, - pfx, - rejectUnauthorized, - secureOptions, - secureProtocol, - servername, - sessionIdContext, - } - - // node-fetch-only options - this.follow = init.follow !== undefined ? init.follow - : input.follow !== undefined ? input.follow - : 20 - this.compress = init.compress !== undefined ? init.compress - : input.compress !== undefined ? input.compress - : true - this.counter = init.counter || input.counter || 0 - this.agent = init.agent || input.agent - } - - get method () { - return this[INTERNALS].method - } - - get url () { - return this[INTERNALS].parsedURL.toString() - } - - get headers () { - return this[INTERNALS].headers - } - - get redirect () { - return this[INTERNALS].redirect - } - - get signal () { - return this[INTERNALS].signal - } - - clone () { - return new Request(this) - } - - get [Symbol.toStringTag] () { - return 'Request' - } - - static getNodeRequestOptions (request) { - const parsedURL = request[INTERNALS].parsedURL - const headers = new Headers(request[INTERNALS].headers) - - // fetch step 1.3 - if (!headers.has('Accept')) { - headers.set('Accept', '*/*') - } - - // Basic fetch - if (!/^https?:$/.test(parsedURL.protocol)) { - throw new TypeError('Only HTTP(S) protocols are supported') - } - - if (request.signal && - Minipass.isStream(request.body) && - typeof request.body.destroy !== 'function') { - throw new Error( - 'Cancellation of streamed requests with AbortSignal is not supported') - } - - // HTTP-network-or-cache fetch steps 2.4-2.7 - const contentLengthValue = - (request.body === null || request.body === undefined) && - /^(POST|PUT)$/i.test(request.method) ? '0' - : request.body !== null && request.body !== undefined - ? getTotalBytes(request) - : null - - if (contentLengthValue) { - headers.set('Content-Length', contentLengthValue + '') - } - - // HTTP-network-or-cache fetch step 2.11 - if (!headers.has('User-Agent')) { - headers.set('User-Agent', defaultUserAgent) - } - - // HTTP-network-or-cache fetch step 2.15 - if (request.compress && !headers.has('Accept-Encoding')) { - headers.set('Accept-Encoding', 'gzip,deflate') - } - - const agent = typeof request.agent === 'function' - ? request.agent(parsedURL) - : request.agent - - if (!headers.has('Connection') && !agent) { - headers.set('Connection', 'close') - } - - // TLS specific options that are handled by node - const { - ca, - cert, - ciphers, - clientCertEngine, - crl, - dhparam, - ecdhCurve, - family, - honorCipherOrder, - key, - passphrase, - pfx, - rejectUnauthorized, - secureOptions, - secureProtocol, - servername, - sessionIdContext, - } = request[INTERNALS] - - // HTTP-network fetch step 4.2 - // chunked encoding is handled by Node.js - - // we cannot spread parsedURL directly, so we have to read each property one-by-one - // and map them to the equivalent https?.request() method options - const urlProps = { - auth: parsedURL.username || parsedURL.password - ? `${parsedURL.username}:${parsedURL.password}` - : '', - host: parsedURL.host, - hostname: parsedURL.hostname, - path: `${parsedURL.pathname}${parsedURL.search}`, - port: parsedURL.port, - protocol: parsedURL.protocol, - } - - return { - ...urlProps, - method: request.method, - headers: exportNodeCompatibleHeaders(headers), - agent, - ca, - cert, - ciphers, - clientCertEngine, - crl, - dhparam, - ecdhCurve, - family, - honorCipherOrder, - key, - passphrase, - pfx, - rejectUnauthorized, - secureOptions, - secureProtocol, - servername, - sessionIdContext, - } - } -} - -module.exports = Request - -Object.defineProperties(Request.prototype, { - method: { enumerable: true }, - url: { enumerable: true }, - headers: { enumerable: true }, - redirect: { enumerable: true }, - clone: { enumerable: true }, - signal: { enumerable: true }, -}) diff --git a/node_modules/node-gyp/node_modules/minipass-fetch/lib/response.js b/node_modules/node-gyp/node_modules/minipass-fetch/lib/response.js deleted file mode 100644 index 54cb52db3594a..0000000000000 --- a/node_modules/node-gyp/node_modules/minipass-fetch/lib/response.js +++ /dev/null @@ -1,90 +0,0 @@ -'use strict' -const http = require('http') -const { STATUS_CODES } = http - -const Headers = require('./headers.js') -const Body = require('./body.js') -const { clone, extractContentType } = Body - -const INTERNALS = Symbol('Response internals') - -class Response extends Body { - constructor (body = null, opts = {}) { - super(body, opts) - - const status = opts.status || 200 - const headers = new Headers(opts.headers) - - if (body !== null && body !== undefined && !headers.has('Content-Type')) { - const contentType = extractContentType(body) - if (contentType) { - headers.append('Content-Type', contentType) - } - } - - this[INTERNALS] = { - url: opts.url, - status, - statusText: opts.statusText || STATUS_CODES[status], - headers, - counter: opts.counter, - trailer: Promise.resolve(opts.trailer || new Headers()), - } - } - - get trailer () { - return this[INTERNALS].trailer - } - - get url () { - return this[INTERNALS].url || '' - } - - get status () { - return this[INTERNALS].status - } - - get ok () { - return this[INTERNALS].status >= 200 && this[INTERNALS].status < 300 - } - - get redirected () { - return this[INTERNALS].counter > 0 - } - - get statusText () { - return this[INTERNALS].statusText - } - - get headers () { - return this[INTERNALS].headers - } - - clone () { - return new Response(clone(this), { - url: this.url, - status: this.status, - statusText: this.statusText, - headers: this.headers, - ok: this.ok, - redirected: this.redirected, - trailer: this.trailer, - }) - } - - get [Symbol.toStringTag] () { - return 'Response' - } -} - -module.exports = Response - -Object.defineProperties(Response.prototype, { - url: { enumerable: true }, - status: { enumerable: true }, - ok: { enumerable: true }, - redirected: { enumerable: true }, - statusText: { enumerable: true }, - headers: { enumerable: true }, - clone: { enumerable: true }, -}) diff --git a/node_modules/node-gyp/node_modules/minipass-fetch/package.json b/node_modules/node-gyp/node_modules/minipass-fetch/package.json deleted file mode 100644 index ada5aed6d7cf6..0000000000000 --- a/node_modules/node-gyp/node_modules/minipass-fetch/package.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "name": "minipass-fetch", - "version": "2.1.2", - "description": "An implementation of window.fetch in Node.js using Minipass streams", - "license": "MIT", - "main": "lib/index.js", - "scripts": { - "test": "tap", - "snap": "tap", - "preversion": "npm test", - "postversion": "npm publish", - "postpublish": "git push origin --follow-tags", - "lint": "eslint \"**/*.js\"", - "postlint": "template-oss-check", - "lintfix": "npm run lint -- --fix", - "prepublishOnly": "git push origin --follow-tags", - "posttest": "npm run lint", - "template-oss-apply": "template-oss-apply --force" - }, - "tap": { - "coverage-map": "map.js", - "check-coverage": true - }, - "devDependencies": { - "@npmcli/eslint-config": "^3.0.1", - "@npmcli/template-oss": "3.5.0", - "@ungap/url-search-params": "^0.2.2", - "abort-controller": "^3.0.0", - "abortcontroller-polyfill": "~1.7.3", - "encoding": "^0.1.13", - "form-data": "^4.0.0", - "nock": "^13.2.4", - "parted": "^0.1.1", - "string-to-arraybuffer": "^1.0.2", - "tap": "^16.0.0" - }, - "dependencies": { - "minipass": "^3.1.6", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - }, - "repository": { - "type": "git", - "url": "https://github.com/npm/minipass-fetch.git" - }, - "keywords": [ - "fetch", - "minipass", - "node-fetch", - "window.fetch" - ], - "files": [ - "bin/", - "lib/" - ], - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - }, - "author": "GitHub Inc.", - "templateOSS": { - "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "3.5.0" - } -} diff --git a/node_modules/node-gyp/node_modules/minipass/LICENSE b/node_modules/node-gyp/node_modules/minipass/LICENSE deleted file mode 100644 index bf1dece2e1f12..0000000000000 --- a/node_modules/node-gyp/node_modules/minipass/LICENSE +++ /dev/null @@ -1,15 +0,0 @@ -The ISC License - -Copyright (c) 2017-2022 npm, Inc., 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/node-gyp/node_modules/minipass/index.js b/node_modules/node-gyp/node_modules/minipass/index.js deleted file mode 100644 index e8797aab6cc27..0000000000000 --- a/node_modules/node-gyp/node_modules/minipass/index.js +++ /dev/null @@ -1,649 +0,0 @@ -'use strict' -const proc = typeof process === 'object' && process ? process : { - stdout: null, - stderr: null, -} -const EE = require('events') -const Stream = require('stream') -const SD = require('string_decoder').StringDecoder - -const EOF = Symbol('EOF') -const MAYBE_EMIT_END = Symbol('maybeEmitEnd') -const EMITTED_END = Symbol('emittedEnd') -const EMITTING_END = Symbol('emittingEnd') -const EMITTED_ERROR = Symbol('emittedError') -const CLOSED = Symbol('closed') -const READ = Symbol('read') -const FLUSH = Symbol('flush') -const FLUSHCHUNK = Symbol('flushChunk') -const ENCODING = Symbol('encoding') -const DECODER = Symbol('decoder') -const FLOWING = Symbol('flowing') -const PAUSED = Symbol('paused') -const RESUME = Symbol('resume') -const BUFFERLENGTH = Symbol('bufferLength') -const BUFFERPUSH = Symbol('bufferPush') -const BUFFERSHIFT = Symbol('bufferShift') -const OBJECTMODE = Symbol('objectMode') -const DESTROYED = Symbol('destroyed') -const EMITDATA = Symbol('emitData') -const EMITEND = Symbol('emitEnd') -const EMITEND2 = Symbol('emitEnd2') -const ASYNC = Symbol('async') - -const defer = fn => Promise.resolve().then(fn) - -// TODO remove when Node v8 support drops -const doIter = global._MP_NO_ITERATOR_SYMBOLS_ !== '1' -const ASYNCITERATOR = doIter && Symbol.asyncIterator - || Symbol('asyncIterator not implemented') -const ITERATOR = doIter && Symbol.iterator - || Symbol('iterator not implemented') - -// events that mean 'the stream is over' -// these are treated specially, and re-emitted -// if they are listened for after emitting. -const isEndish = ev => - ev === 'end' || - ev === 'finish' || - ev === 'prefinish' - -const isArrayBuffer = b => b instanceof ArrayBuffer || - typeof b === 'object' && - b.constructor && - b.constructor.name === 'ArrayBuffer' && - b.byteLength >= 0 - -const isArrayBufferView = b => !Buffer.isBuffer(b) && ArrayBuffer.isView(b) - -class Pipe { - constructor (src, dest, opts) { - this.src = src - this.dest = dest - this.opts = opts - this.ondrain = () => src[RESUME]() - dest.on('drain', this.ondrain) - } - unpipe () { - this.dest.removeListener('drain', this.ondrain) - } - // istanbul ignore next - only here for the prototype - proxyErrors () {} - end () { - this.unpipe() - if (this.opts.end) - this.dest.end() - } -} - -class PipeProxyErrors extends Pipe { - unpipe () { - this.src.removeListener('error', this.proxyErrors) - super.unpipe() - } - constructor (src, dest, opts) { - super(src, dest, opts) - this.proxyErrors = er => dest.emit('error', er) - src.on('error', this.proxyErrors) - } -} - -module.exports = class Minipass extends Stream { - constructor (options) { - super() - this[FLOWING] = false - // whether we're explicitly paused - this[PAUSED] = false - this.pipes = [] - this.buffer = [] - this[OBJECTMODE] = options && options.objectMode || false - if (this[OBJECTMODE]) - this[ENCODING] = null - else - this[ENCODING] = options && options.encoding || null - if (this[ENCODING] === 'buffer') - this[ENCODING] = null - this[ASYNC] = options && !!options.async || false - this[DECODER] = this[ENCODING] ? new SD(this[ENCODING]) : null - this[EOF] = false - this[EMITTED_END] = false - this[EMITTING_END] = false - this[CLOSED] = false - this[EMITTED_ERROR] = null - this.writable = true - this.readable = true - this[BUFFERLENGTH] = 0 - this[DESTROYED] = false - } - - get bufferLength () { return this[BUFFERLENGTH] } - - get encoding () { return this[ENCODING] } - set encoding (enc) { - if (this[OBJECTMODE]) - throw new Error('cannot set encoding in objectMode') - - if (this[ENCODING] && enc !== this[ENCODING] && - (this[DECODER] && this[DECODER].lastNeed || this[BUFFERLENGTH])) - throw new Error('cannot change encoding') - - if (this[ENCODING] !== enc) { - this[DECODER] = enc ? new SD(enc) : null - if (this.buffer.length) - this.buffer = this.buffer.map(chunk => this[DECODER].write(chunk)) - } - - this[ENCODING] = enc - } - - setEncoding (enc) { - this.encoding = enc - } - - get objectMode () { return this[OBJECTMODE] } - set objectMode (om) { this[OBJECTMODE] = this[OBJECTMODE] || !!om } - - get ['async'] () { return this[ASYNC] } - set ['async'] (a) { this[ASYNC] = this[ASYNC] || !!a } - - write (chunk, encoding, cb) { - if (this[EOF]) - throw new Error('write after end') - - if (this[DESTROYED]) { - this.emit('error', Object.assign( - new Error('Cannot call write after a stream was destroyed'), - { code: 'ERR_STREAM_DESTROYED' } - )) - return true - } - - if (typeof encoding === 'function') - cb = encoding, encoding = 'utf8' - - if (!encoding) - encoding = 'utf8' - - const fn = this[ASYNC] ? defer : f => f() - - // convert array buffers and typed array views into buffers - // at some point in the future, we may want to do the opposite! - // leave strings and buffers as-is - // anything else switches us into object mode - if (!this[OBJECTMODE] && !Buffer.isBuffer(chunk)) { - if (isArrayBufferView(chunk)) - chunk = Buffer.from(chunk.buffer, chunk.byteOffset, chunk.byteLength) - else if (isArrayBuffer(chunk)) - chunk = Buffer.from(chunk) - else if (typeof chunk !== 'string') - // use the setter so we throw if we have encoding set - this.objectMode = true - } - - // handle object mode up front, since it's simpler - // this yields better performance, fewer checks later. - if (this[OBJECTMODE]) { - /* istanbul ignore if - maybe impossible? */ - if (this.flowing && this[BUFFERLENGTH] !== 0) - this[FLUSH](true) - - if (this.flowing) - this.emit('data', chunk) - else - this[BUFFERPUSH](chunk) - - if (this[BUFFERLENGTH] !== 0) - this.emit('readable') - - if (cb) - fn(cb) - - return this.flowing - } - - // at this point the chunk is a buffer or string - // don't buffer it up or send it to the decoder - if (!chunk.length) { - if (this[BUFFERLENGTH] !== 0) - this.emit('readable') - if (cb) - fn(cb) - return this.flowing - } - - // fast-path writing strings of same encoding to a stream with - // an empty buffer, skipping the buffer/decoder dance - if (typeof chunk === 'string' && - // unless it is a string already ready for us to use - !(encoding === this[ENCODING] && !this[DECODER].lastNeed)) { - chunk = Buffer.from(chunk, encoding) - } - - if (Buffer.isBuffer(chunk) && this[ENCODING]) - chunk = this[DECODER].write(chunk) - - // Note: flushing CAN potentially switch us into not-flowing mode - if (this.flowing && this[BUFFERLENGTH] !== 0) - this[FLUSH](true) - - if (this.flowing) - this.emit('data', chunk) - else - this[BUFFERPUSH](chunk) - - if (this[BUFFERLENGTH] !== 0) - this.emit('readable') - - if (cb) - fn(cb) - - return this.flowing - } - - read (n) { - if (this[DESTROYED]) - return null - - if (this[BUFFERLENGTH] === 0 || n === 0 || n > this[BUFFERLENGTH]) { - this[MAYBE_EMIT_END]() - return null - } - - if (this[OBJECTMODE]) - n = null - - if (this.buffer.length > 1 && !this[OBJECTMODE]) { - if (this.encoding) - this.buffer = [this.buffer.join('')] - else - this.buffer = [Buffer.concat(this.buffer, this[BUFFERLENGTH])] - } - - const ret = this[READ](n || null, this.buffer[0]) - this[MAYBE_EMIT_END]() - return ret - } - - [READ] (n, chunk) { - if (n === chunk.length || n === null) - this[BUFFERSHIFT]() - else { - this.buffer[0] = chunk.slice(n) - chunk = chunk.slice(0, n) - this[BUFFERLENGTH] -= n - } - - this.emit('data', chunk) - - if (!this.buffer.length && !this[EOF]) - this.emit('drain') - - return chunk - } - - end (chunk, encoding, cb) { - if (typeof chunk === 'function') - cb = chunk, chunk = null - if (typeof encoding === 'function') - cb = encoding, encoding = 'utf8' - if (chunk) - this.write(chunk, encoding) - if (cb) - this.once('end', cb) - this[EOF] = true - this.writable = false - - // if we haven't written anything, then go ahead and emit, - // even if we're not reading. - // we'll re-emit if a new 'end' listener is added anyway. - // This makes MP more suitable to write-only use cases. - if (this.flowing || !this[PAUSED]) - this[MAYBE_EMIT_END]() - return this - } - - // don't let the internal resume be overwritten - [RESUME] () { - if (this[DESTROYED]) - return - - this[PAUSED] = false - this[FLOWING] = true - this.emit('resume') - if (this.buffer.length) - this[FLUSH]() - else if (this[EOF]) - this[MAYBE_EMIT_END]() - else - this.emit('drain') - } - - resume () { - return this[RESUME]() - } - - pause () { - this[FLOWING] = false - this[PAUSED] = true - } - - get destroyed () { - return this[DESTROYED] - } - - get flowing () { - return this[FLOWING] - } - - get paused () { - return this[PAUSED] - } - - [BUFFERPUSH] (chunk) { - if (this[OBJECTMODE]) - this[BUFFERLENGTH] += 1 - else - this[BUFFERLENGTH] += chunk.length - this.buffer.push(chunk) - } - - [BUFFERSHIFT] () { - if (this.buffer.length) { - if (this[OBJECTMODE]) - this[BUFFERLENGTH] -= 1 - else - this[BUFFERLENGTH] -= this.buffer[0].length - } - return this.buffer.shift() - } - - [FLUSH] (noDrain) { - do {} while (this[FLUSHCHUNK](this[BUFFERSHIFT]())) - - if (!noDrain && !this.buffer.length && !this[EOF]) - this.emit('drain') - } - - [FLUSHCHUNK] (chunk) { - return chunk ? (this.emit('data', chunk), this.flowing) : false - } - - pipe (dest, opts) { - if (this[DESTROYED]) - return - - const ended = this[EMITTED_END] - opts = opts || {} - if (dest === proc.stdout || dest === proc.stderr) - opts.end = false - else - opts.end = opts.end !== false - opts.proxyErrors = !!opts.proxyErrors - - // piping an ended stream ends immediately - if (ended) { - if (opts.end) - dest.end() - } else { - this.pipes.push(!opts.proxyErrors ? new Pipe(this, dest, opts) - : new PipeProxyErrors(this, dest, opts)) - if (this[ASYNC]) - defer(() => this[RESUME]()) - else - this[RESUME]() - } - - return dest - } - - unpipe (dest) { - const p = this.pipes.find(p => p.dest === dest) - if (p) { - this.pipes.splice(this.pipes.indexOf(p), 1) - p.unpipe() - } - } - - addListener (ev, fn) { - return this.on(ev, fn) - } - - on (ev, fn) { - const ret = super.on(ev, fn) - if (ev === 'data' && !this.pipes.length && !this.flowing) - this[RESUME]() - else if (ev === 'readable' && this[BUFFERLENGTH] !== 0) - super.emit('readable') - else if (isEndish(ev) && this[EMITTED_END]) { - super.emit(ev) - this.removeAllListeners(ev) - } else if (ev === 'error' && this[EMITTED_ERROR]) { - if (this[ASYNC]) - defer(() => fn.call(this, this[EMITTED_ERROR])) - else - fn.call(this, this[EMITTED_ERROR]) - } - return ret - } - - get emittedEnd () { - return this[EMITTED_END] - } - - [MAYBE_EMIT_END] () { - if (!this[EMITTING_END] && - !this[EMITTED_END] && - !this[DESTROYED] && - this.buffer.length === 0 && - this[EOF]) { - this[EMITTING_END] = true - this.emit('end') - this.emit('prefinish') - this.emit('finish') - if (this[CLOSED]) - this.emit('close') - this[EMITTING_END] = false - } - } - - emit (ev, data, ...extra) { - // error and close are only events allowed after calling destroy() - if (ev !== 'error' && ev !== 'close' && ev !== DESTROYED && this[DESTROYED]) - return - else if (ev === 'data') { - return !data ? false - : this[ASYNC] ? defer(() => this[EMITDATA](data)) - : this[EMITDATA](data) - } else if (ev === 'end') { - return this[EMITEND]() - } else if (ev === 'close') { - this[CLOSED] = true - // don't emit close before 'end' and 'finish' - if (!this[EMITTED_END] && !this[DESTROYED]) - return - const ret = super.emit('close') - this.removeAllListeners('close') - return ret - } else if (ev === 'error') { - this[EMITTED_ERROR] = data - const ret = super.emit('error', data) - this[MAYBE_EMIT_END]() - return ret - } else if (ev === 'resume') { - const ret = super.emit('resume') - this[MAYBE_EMIT_END]() - return ret - } else if (ev === 'finish' || ev === 'prefinish') { - const ret = super.emit(ev) - this.removeAllListeners(ev) - return ret - } - - // Some other unknown event - const ret = super.emit(ev, data, ...extra) - this[MAYBE_EMIT_END]() - return ret - } - - [EMITDATA] (data) { - for (const p of this.pipes) { - if (p.dest.write(data) === false) - this.pause() - } - const ret = super.emit('data', data) - this[MAYBE_EMIT_END]() - return ret - } - - [EMITEND] () { - if (this[EMITTED_END]) - return - - this[EMITTED_END] = true - this.readable = false - if (this[ASYNC]) - defer(() => this[EMITEND2]()) - else - this[EMITEND2]() - } - - [EMITEND2] () { - if (this[DECODER]) { - const data = this[DECODER].end() - if (data) { - for (const p of this.pipes) { - p.dest.write(data) - } - super.emit('data', data) - } - } - - for (const p of this.pipes) { - p.end() - } - const ret = super.emit('end') - this.removeAllListeners('end') - return ret - } - - // const all = await stream.collect() - collect () { - const buf = [] - if (!this[OBJECTMODE]) - buf.dataLength = 0 - // set the promise first, in case an error is raised - // by triggering the flow here. - const p = this.promise() - this.on('data', c => { - buf.push(c) - if (!this[OBJECTMODE]) - buf.dataLength += c.length - }) - return p.then(() => buf) - } - - // const data = await stream.concat() - concat () { - return this[OBJECTMODE] - ? Promise.reject(new Error('cannot concat in objectMode')) - : this.collect().then(buf => - this[OBJECTMODE] - ? Promise.reject(new Error('cannot concat in objectMode')) - : this[ENCODING] ? buf.join('') : Buffer.concat(buf, buf.dataLength)) - } - - // stream.promise().then(() => done, er => emitted error) - promise () { - return new Promise((resolve, reject) => { - this.on(DESTROYED, () => reject(new Error('stream destroyed'))) - this.on('error', er => reject(er)) - this.on('end', () => resolve()) - }) - } - - // for await (let chunk of stream) - [ASYNCITERATOR] () { - const next = () => { - const res = this.read() - if (res !== null) - return Promise.resolve({ done: false, value: res }) - - if (this[EOF]) - return Promise.resolve({ done: true }) - - let resolve = null - let reject = null - const onerr = er => { - this.removeListener('data', ondata) - this.removeListener('end', onend) - reject(er) - } - const ondata = value => { - this.removeListener('error', onerr) - this.removeListener('end', onend) - this.pause() - resolve({ value: value, done: !!this[EOF] }) - } - const onend = () => { - this.removeListener('error', onerr) - this.removeListener('data', ondata) - resolve({ done: true }) - } - const ondestroy = () => onerr(new Error('stream destroyed')) - return new Promise((res, rej) => { - reject = rej - resolve = res - this.once(DESTROYED, ondestroy) - this.once('error', onerr) - this.once('end', onend) - this.once('data', ondata) - }) - } - - return { next } - } - - // for (let chunk of stream) - [ITERATOR] () { - const next = () => { - const value = this.read() - const done = value === null - return { value, done } - } - return { next } - } - - destroy (er) { - if (this[DESTROYED]) { - if (er) - this.emit('error', er) - else - this.emit(DESTROYED) - return this - } - - this[DESTROYED] = true - - // throw away all buffered data, it's never coming out - this.buffer.length = 0 - this[BUFFERLENGTH] = 0 - - if (typeof this.close === 'function' && !this[CLOSED]) - this.close() - - if (er) - this.emit('error', er) - else // if no error to emit, still reject pending promises - this.emit(DESTROYED) - - return this - } - - static isStream (s) { - return !!s && (s instanceof Minipass || s instanceof Stream || - s instanceof EE && ( - typeof s.pipe === 'function' || // readable - (typeof s.write === 'function' && typeof s.end === 'function') // writable - )) - } -} diff --git a/node_modules/node-gyp/node_modules/minipass/package.json b/node_modules/node-gyp/node_modules/minipass/package.json deleted file mode 100644 index 548d03fa6d5d4..0000000000000 --- a/node_modules/node-gyp/node_modules/minipass/package.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "name": "minipass", - "version": "3.3.6", - "description": "minimal implementation of a PassThrough stream", - "main": "index.js", - "types": "index.d.ts", - "dependencies": { - "yallist": "^4.0.0" - }, - "devDependencies": { - "@types/node": "^17.0.41", - "end-of-stream": "^1.4.0", - "prettier": "^2.6.2", - "tap": "^16.2.0", - "through2": "^2.0.3", - "ts-node": "^10.8.1", - "typescript": "^4.7.3" - }, - "scripts": { - "test": "tap", - "preversion": "npm test", - "postversion": "npm publish", - "postpublish": "git push origin --follow-tags" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/isaacs/minipass.git" - }, - "keywords": [ - "passthrough", - "stream" - ], - "author": "Isaac Z. Schlueter (http://blog.izs.me/)", - "license": "ISC", - "files": [ - "index.d.ts", - "index.js" - ], - "tap": { - "check-coverage": true - }, - "engines": { - "node": ">=8" - }, - "prettier": { - "semi": false, - "printWidth": 80, - "tabWidth": 2, - "useTabs": false, - "singleQuote": true, - "jsxSingleQuote": false, - "bracketSameLine": true, - "arrowParens": "avoid", - "endOfLine": "lf" - } -} diff --git a/node_modules/node-gyp/node_modules/ssri/LICENSE.md b/node_modules/node-gyp/node_modules/ssri/LICENSE.md deleted file mode 100644 index e335388869f50..0000000000000 --- a/node_modules/node-gyp/node_modules/ssri/LICENSE.md +++ /dev/null @@ -1,16 +0,0 @@ -ISC License - -Copyright 2021 (c) npm, Inc. - -Permission to use, copy, modify, and/or distribute this software for -any purpose with or without fee is hereby granted, provided that the -above copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE COPYRIGHT HOLDER DISCLAIMS -ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE -COPYRIGHT HOLDER 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/node-gyp/node_modules/ssri/lib/index.js b/node_modules/node-gyp/node_modules/ssri/lib/index.js deleted file mode 100644 index 1443137cbc708..0000000000000 --- a/node_modules/node-gyp/node_modules/ssri/lib/index.js +++ /dev/null @@ -1,524 +0,0 @@ -'use strict' - -const crypto = require('crypto') -const MiniPass = require('minipass') - -const SPEC_ALGORITHMS = ['sha256', 'sha384', 'sha512'] - -// TODO: this should really be a hardcoded list of algorithms we support, -// rather than [a-z0-9]. -const BASE64_REGEX = /^[a-z0-9+/]+(?:=?=?)$/i -const SRI_REGEX = /^([a-z0-9]+)-([^?]+)([?\S*]*)$/ -const STRICT_SRI_REGEX = /^([a-z0-9]+)-([A-Za-z0-9+/=]{44,88})(\?[\x21-\x7E]*)?$/ -const VCHAR_REGEX = /^[\x21-\x7E]+$/ - -const defaultOpts = { - algorithms: ['sha512'], - error: false, - options: [], - pickAlgorithm: getPrioritizedHash, - sep: ' ', - single: false, - strict: false, -} - -const ssriOpts = (opts = {}) => ({ ...defaultOpts, ...opts }) - -const getOptString = options => !options || !options.length - ? '' - : `?${options.join('?')}` - -const _onEnd = Symbol('_onEnd') -const _getOptions = Symbol('_getOptions') -const _emittedSize = Symbol('_emittedSize') -const _emittedIntegrity = Symbol('_emittedIntegrity') -const _emittedVerified = Symbol('_emittedVerified') - -class IntegrityStream extends MiniPass { - constructor (opts) { - super() - this.size = 0 - this.opts = opts - - // may be overridden later, but set now for class consistency - this[_getOptions]() - - // options used for calculating stream. can't be changed. - const { algorithms = defaultOpts.algorithms } = opts - this.algorithms = Array.from( - new Set(algorithms.concat(this.algorithm ? [this.algorithm] : [])) - ) - this.hashes = this.algorithms.map(crypto.createHash) - } - - [_getOptions] () { - const { - integrity, - size, - options, - } = { ...defaultOpts, ...this.opts } - - // For verification - this.sri = integrity ? parse(integrity, this.opts) : null - this.expectedSize = size - this.goodSri = this.sri ? !!Object.keys(this.sri).length : false - this.algorithm = this.goodSri ? this.sri.pickAlgorithm(this.opts) : null - this.digests = this.goodSri ? this.sri[this.algorithm] : null - this.optString = getOptString(options) - } - - on (ev, handler) { - if (ev === 'size' && this[_emittedSize]) { - return handler(this[_emittedSize]) - } - - if (ev === 'integrity' && this[_emittedIntegrity]) { - return handler(this[_emittedIntegrity]) - } - - if (ev === 'verified' && this[_emittedVerified]) { - return handler(this[_emittedVerified]) - } - - return super.on(ev, handler) - } - - emit (ev, data) { - if (ev === 'end') { - this[_onEnd]() - } - return super.emit(ev, data) - } - - write (data) { - this.size += data.length - this.hashes.forEach(h => h.update(data)) - return super.write(data) - } - - [_onEnd] () { - if (!this.goodSri) { - this[_getOptions]() - } - const newSri = parse(this.hashes.map((h, i) => { - return `${this.algorithms[i]}-${h.digest('base64')}${this.optString}` - }).join(' '), this.opts) - // Integrity verification mode - const match = this.goodSri && newSri.match(this.sri, this.opts) - if (typeof this.expectedSize === 'number' && this.size !== this.expectedSize) { - /* eslint-disable-next-line max-len */ - const err = new Error(`stream size mismatch when checking ${this.sri}.\n Wanted: ${this.expectedSize}\n Found: ${this.size}`) - err.code = 'EBADSIZE' - err.found = this.size - err.expected = this.expectedSize - err.sri = this.sri - this.emit('error', err) - } else if (this.sri && !match) { - /* eslint-disable-next-line max-len */ - const err = new Error(`${this.sri} integrity checksum failed when using ${this.algorithm}: wanted ${this.digests} but got ${newSri}. (${this.size} bytes)`) - err.code = 'EINTEGRITY' - err.found = newSri - err.expected = this.digests - err.algorithm = this.algorithm - err.sri = this.sri - this.emit('error', err) - } else { - this[_emittedSize] = this.size - this.emit('size', this.size) - this[_emittedIntegrity] = newSri - this.emit('integrity', newSri) - if (match) { - this[_emittedVerified] = match - this.emit('verified', match) - } - } - } -} - -class Hash { - get isHash () { - return true - } - - constructor (hash, opts) { - opts = ssriOpts(opts) - const strict = !!opts.strict - this.source = hash.trim() - - // set default values so that we make V8 happy to - // always see a familiar object template. - this.digest = '' - this.algorithm = '' - this.options = [] - - // 3.1. Integrity metadata (called "Hash" by ssri) - // https://w3c.github.io/webappsec-subresource-integrity/#integrity-metadata-description - const match = this.source.match( - strict - ? STRICT_SRI_REGEX - : SRI_REGEX - ) - if (!match) { - return - } - if (strict && !SPEC_ALGORITHMS.some(a => a === match[1])) { - return - } - this.algorithm = match[1] - this.digest = match[2] - - const rawOpts = match[3] - if (rawOpts) { - this.options = rawOpts.slice(1).split('?') - } - } - - hexDigest () { - return this.digest && Buffer.from(this.digest, 'base64').toString('hex') - } - - toJSON () { - return this.toString() - } - - toString (opts) { - opts = ssriOpts(opts) - if (opts.strict) { - // Strict mode enforces the standard as close to the foot of the - // letter as it can. - if (!( - // The spec has very restricted productions for algorithms. - // https://www.w3.org/TR/CSP2/#source-list-syntax - SPEC_ALGORITHMS.some(x => x === this.algorithm) && - // Usually, if someone insists on using a "different" base64, we - // leave it as-is, since there's multiple standards, and the - // specified is not a URL-safe variant. - // https://www.w3.org/TR/CSP2/#base64_value - this.digest.match(BASE64_REGEX) && - // Option syntax is strictly visual chars. - // https://w3c.github.io/webappsec-subresource-integrity/#grammardef-option-expression - // https://tools.ietf.org/html/rfc5234#appendix-B.1 - this.options.every(opt => opt.match(VCHAR_REGEX)) - )) { - return '' - } - } - const options = this.options && this.options.length - ? `?${this.options.join('?')}` - : '' - return `${this.algorithm}-${this.digest}${options}` - } -} - -class Integrity { - get isIntegrity () { - return true - } - - toJSON () { - return this.toString() - } - - isEmpty () { - return Object.keys(this).length === 0 - } - - toString (opts) { - opts = ssriOpts(opts) - let sep = opts.sep || ' ' - if (opts.strict) { - // Entries must be separated by whitespace, according to spec. - sep = sep.replace(/\S+/g, ' ') - } - return Object.keys(this).map(k => { - return this[k].map(hash => { - return Hash.prototype.toString.call(hash, opts) - }).filter(x => x.length).join(sep) - }).filter(x => x.length).join(sep) - } - - concat (integrity, opts) { - opts = ssriOpts(opts) - const other = typeof integrity === 'string' - ? integrity - : stringify(integrity, opts) - return parse(`${this.toString(opts)} ${other}`, opts) - } - - hexDigest () { - return parse(this, { single: true }).hexDigest() - } - - // add additional hashes to an integrity value, but prevent - // *changing* an existing integrity hash. - merge (integrity, opts) { - opts = ssriOpts(opts) - const other = parse(integrity, opts) - for (const algo in other) { - if (this[algo]) { - if (!this[algo].find(hash => - other[algo].find(otherhash => - hash.digest === otherhash.digest))) { - throw new Error('hashes do not match, cannot update integrity') - } - } else { - this[algo] = other[algo] - } - } - } - - match (integrity, opts) { - opts = ssriOpts(opts) - const other = parse(integrity, opts) - const algo = other.pickAlgorithm(opts) - return ( - this[algo] && - other[algo] && - this[algo].find(hash => - other[algo].find(otherhash => - hash.digest === otherhash.digest - ) - ) - ) || false - } - - pickAlgorithm (opts) { - opts = ssriOpts(opts) - const pickAlgorithm = opts.pickAlgorithm - const keys = Object.keys(this) - return keys.reduce((acc, algo) => { - return pickAlgorithm(acc, algo) || acc - }) - } -} - -module.exports.parse = parse -function parse (sri, opts) { - if (!sri) { - return null - } - opts = ssriOpts(opts) - if (typeof sri === 'string') { - return _parse(sri, opts) - } else if (sri.algorithm && sri.digest) { - const fullSri = new Integrity() - fullSri[sri.algorithm] = [sri] - return _parse(stringify(fullSri, opts), opts) - } else { - return _parse(stringify(sri, opts), opts) - } -} - -function _parse (integrity, opts) { - // 3.4.3. Parse metadata - // https://w3c.github.io/webappsec-subresource-integrity/#parse-metadata - if (opts.single) { - return new Hash(integrity, opts) - } - const hashes = integrity.trim().split(/\s+/).reduce((acc, string) => { - const hash = new Hash(string, opts) - if (hash.algorithm && hash.digest) { - const algo = hash.algorithm - if (!acc[algo]) { - acc[algo] = [] - } - acc[algo].push(hash) - } - return acc - }, new Integrity()) - return hashes.isEmpty() ? null : hashes -} - -module.exports.stringify = stringify -function stringify (obj, opts) { - opts = ssriOpts(opts) - if (obj.algorithm && obj.digest) { - return Hash.prototype.toString.call(obj, opts) - } else if (typeof obj === 'string') { - return stringify(parse(obj, opts), opts) - } else { - return Integrity.prototype.toString.call(obj, opts) - } -} - -module.exports.fromHex = fromHex -function fromHex (hexDigest, algorithm, opts) { - opts = ssriOpts(opts) - const optString = getOptString(opts.options) - return parse( - `${algorithm}-${ - Buffer.from(hexDigest, 'hex').toString('base64') - }${optString}`, opts - ) -} - -module.exports.fromData = fromData -function fromData (data, opts) { - opts = ssriOpts(opts) - const algorithms = opts.algorithms - const optString = getOptString(opts.options) - return algorithms.reduce((acc, algo) => { - const digest = crypto.createHash(algo).update(data).digest('base64') - const hash = new Hash( - `${algo}-${digest}${optString}`, - opts - ) - /* istanbul ignore else - it would be VERY strange if the string we - * just calculated with an algo did not have an algo or digest. - */ - if (hash.algorithm && hash.digest) { - const hashAlgo = hash.algorithm - if (!acc[hashAlgo]) { - acc[hashAlgo] = [] - } - acc[hashAlgo].push(hash) - } - return acc - }, new Integrity()) -} - -module.exports.fromStream = fromStream -function fromStream (stream, opts) { - opts = ssriOpts(opts) - const istream = integrityStream(opts) - return new Promise((resolve, reject) => { - stream.pipe(istream) - stream.on('error', reject) - istream.on('error', reject) - let sri - istream.on('integrity', s => { - sri = s - }) - istream.on('end', () => resolve(sri)) - istream.on('data', () => {}) - }) -} - -module.exports.checkData = checkData -function checkData (data, sri, opts) { - opts = ssriOpts(opts) - sri = parse(sri, opts) - if (!sri || !Object.keys(sri).length) { - if (opts.error) { - throw Object.assign( - new Error('No valid integrity hashes to check against'), { - code: 'EINTEGRITY', - } - ) - } else { - return false - } - } - const algorithm = sri.pickAlgorithm(opts) - const digest = crypto.createHash(algorithm).update(data).digest('base64') - const newSri = parse({ algorithm, digest }) - const match = newSri.match(sri, opts) - if (match || !opts.error) { - return match - } else if (typeof opts.size === 'number' && (data.length !== opts.size)) { - /* eslint-disable-next-line max-len */ - const err = new Error(`data size mismatch when checking ${sri}.\n Wanted: ${opts.size}\n Found: ${data.length}`) - err.code = 'EBADSIZE' - err.found = data.length - err.expected = opts.size - err.sri = sri - throw err - } else { - /* eslint-disable-next-line max-len */ - const err = new Error(`Integrity checksum failed when using ${algorithm}: Wanted ${sri}, but got ${newSri}. (${data.length} bytes)`) - err.code = 'EINTEGRITY' - err.found = newSri - err.expected = sri - err.algorithm = algorithm - err.sri = sri - throw err - } -} - -module.exports.checkStream = checkStream -function checkStream (stream, sri, opts) { - opts = ssriOpts(opts) - opts.integrity = sri - sri = parse(sri, opts) - if (!sri || !Object.keys(sri).length) { - return Promise.reject(Object.assign( - new Error('No valid integrity hashes to check against'), { - code: 'EINTEGRITY', - } - )) - } - const checker = integrityStream(opts) - return new Promise((resolve, reject) => { - stream.pipe(checker) - stream.on('error', reject) - checker.on('error', reject) - let verified - checker.on('verified', s => { - verified = s - }) - checker.on('end', () => resolve(verified)) - checker.on('data', () => {}) - }) -} - -module.exports.integrityStream = integrityStream -function integrityStream (opts = {}) { - return new IntegrityStream(opts) -} - -module.exports.create = createIntegrity -function createIntegrity (opts) { - opts = ssriOpts(opts) - const algorithms = opts.algorithms - const optString = getOptString(opts.options) - - const hashes = algorithms.map(crypto.createHash) - - return { - update: function (chunk, enc) { - hashes.forEach(h => h.update(chunk, enc)) - return this - }, - digest: function (enc) { - const integrity = algorithms.reduce((acc, algo) => { - const digest = hashes.shift().digest('base64') - const hash = new Hash( - `${algo}-${digest}${optString}`, - opts - ) - /* istanbul ignore else - it would be VERY strange if the hash we - * just calculated with an algo did not have an algo or digest. - */ - if (hash.algorithm && hash.digest) { - const hashAlgo = hash.algorithm - if (!acc[hashAlgo]) { - acc[hashAlgo] = [] - } - acc[hashAlgo].push(hash) - } - return acc - }, new Integrity()) - - return integrity - }, - } -} - -const NODE_HASHES = new Set(crypto.getHashes()) - -// This is a Best Effort™ at a reasonable priority for hash algos -const DEFAULT_PRIORITY = [ - 'md5', 'whirlpool', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512', - // TODO - it's unclear _which_ of these Node will actually use as its name - // for the algorithm, so we guesswork it based on the OpenSSL names. - 'sha3', - 'sha3-256', 'sha3-384', 'sha3-512', - 'sha3_256', 'sha3_384', 'sha3_512', -].filter(algo => NODE_HASHES.has(algo)) - -function getPrioritizedHash (algo1, algo2) { - /* eslint-disable-next-line max-len */ - return DEFAULT_PRIORITY.indexOf(algo1.toLowerCase()) >= DEFAULT_PRIORITY.indexOf(algo2.toLowerCase()) - ? algo1 - : algo2 -} diff --git a/node_modules/node-gyp/node_modules/ssri/package.json b/node_modules/node-gyp/node_modules/ssri/package.json deleted file mode 100644 index 91c1f919788cd..0000000000000 --- a/node_modules/node-gyp/node_modules/ssri/package.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "name": "ssri", - "version": "9.0.1", - "description": "Standard Subresource Integrity library -- parses, serializes, generates, and verifies integrity metadata according to the SRI spec.", - "main": "lib/index.js", - "files": [ - "bin/", - "lib/" - ], - "scripts": { - "prerelease": "npm t", - "postrelease": "npm publish", - "prepublishOnly": "git push origin --follow-tags", - "posttest": "npm run lint", - "test": "tap", - "coverage": "tap", - "lint": "eslint \"**/*.js\"", - "postlint": "template-oss-check", - "template-oss-apply": "template-oss-apply --force", - "lintfix": "npm run lint -- --fix", - "preversion": "npm test", - "postversion": "npm publish", - "snap": "tap" - }, - "tap": { - "check-coverage": true - }, - "repository": { - "type": "git", - "url": "https://github.com/npm/ssri.git" - }, - "keywords": [ - "w3c", - "web", - "security", - "integrity", - "checksum", - "hashing", - "subresource integrity", - "sri", - "sri hash", - "sri string", - "sri generator", - "html" - ], - "author": "GitHub Inc.", - "license": "ISC", - "dependencies": { - "minipass": "^3.1.1" - }, - "devDependencies": { - "@npmcli/eslint-config": "^3.0.1", - "@npmcli/template-oss": "3.5.0", - "tap": "^16.0.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - }, - "templateOSS": { - "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "3.5.0" - } -} diff --git a/node_modules/node-gyp/node_modules/unique-filename/LICENSE b/node_modules/node-gyp/node_modules/unique-filename/LICENSE deleted file mode 100644 index 69619c125ea7e..0000000000000 --- a/node_modules/node-gyp/node_modules/unique-filename/LICENSE +++ /dev/null @@ -1,5 +0,0 @@ -Copyright npm, Inc - -Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND 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/node-gyp/node_modules/unique-filename/lib/index.js b/node_modules/node-gyp/node_modules/unique-filename/lib/index.js deleted file mode 100644 index d067d2e709809..0000000000000 --- a/node_modules/node-gyp/node_modules/unique-filename/lib/index.js +++ /dev/null @@ -1,7 +0,0 @@ -var path = require('path') - -var uniqueSlug = require('unique-slug') - -module.exports = function (filepath, prefix, uniq) { - return path.join(filepath, (prefix ? prefix + '-' : '') + uniqueSlug(uniq)) -} diff --git a/node_modules/node-gyp/node_modules/unique-filename/package.json b/node_modules/node-gyp/node_modules/unique-filename/package.json deleted file mode 100644 index bfdec2c3722a0..0000000000000 --- a/node_modules/node-gyp/node_modules/unique-filename/package.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "name": "unique-filename", - "version": "2.0.1", - "description": "Generate a unique filename for use in temporary directories or caches.", - "main": "lib/index.js", - "scripts": { - "test": "tap", - "lint": "eslint \"**/*.js\"", - "postlint": "template-oss-check", - "template-oss-apply": "template-oss-apply --force", - "lintfix": "npm run lint -- --fix", - "preversion": "npm test", - "postversion": "npm publish", - "prepublishOnly": "git push origin --follow-tags", - "snap": "tap", - "posttest": "npm run lint" - }, - "repository": { - "type": "git", - "url": "https://github.com/npm/unique-filename.git" - }, - "keywords": [], - "author": "GitHub Inc.", - "license": "ISC", - "bugs": { - "url": "https://github.com/iarna/unique-filename/issues" - }, - "homepage": "https://github.com/iarna/unique-filename", - "devDependencies": { - "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "3.5.0", - "tap": "^16.3.0" - }, - "dependencies": { - "unique-slug": "^3.0.0" - }, - "files": [ - "bin/", - "lib/" - ], - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - }, - "templateOSS": { - "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "3.5.0" - } -} diff --git a/node_modules/node-gyp/node_modules/unique-slug/LICENSE b/node_modules/node-gyp/node_modules/unique-slug/LICENSE deleted file mode 100644 index 7953647e7760b..0000000000000 --- a/node_modules/node-gyp/node_modules/unique-slug/LICENSE +++ /dev/null @@ -1,15 +0,0 @@ -The ISC License - -Copyright npm, Inc - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND 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/node-gyp/node_modules/unique-slug/lib/index.js b/node_modules/node-gyp/node_modules/unique-slug/lib/index.js deleted file mode 100644 index 1bac84d95d730..0000000000000 --- a/node_modules/node-gyp/node_modules/unique-slug/lib/index.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict' -var MurmurHash3 = require('imurmurhash') - -module.exports = function (uniq) { - if (uniq) { - var hash = new MurmurHash3(uniq) - return ('00000000' + hash.result().toString(16)).slice(-8) - } else { - return (Math.random().toString(16) + '0000000').slice(2, 10) - } -} diff --git a/node_modules/node-gyp/node_modules/unique-slug/package.json b/node_modules/node-gyp/node_modules/unique-slug/package.json deleted file mode 100644 index 3194408f27fda..0000000000000 --- a/node_modules/node-gyp/node_modules/unique-slug/package.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "name": "unique-slug", - "version": "3.0.0", - "description": "Generate a unique character string suitible for use in files and URLs.", - "main": "lib/index.js", - "scripts": { - "test": "tap", - "lint": "eslint \"**/*.js\"", - "postlint": "template-oss-check", - "template-oss-apply": "template-oss-apply --force", - "lintfix": "npm run lint -- --fix", - "preversion": "npm test", - "postversion": "npm publish", - "prepublishOnly": "git push origin --follow-tags", - "snap": "tap", - "posttest": "npm run lint" - }, - "keywords": [], - "author": "GitHub Inc.", - "license": "ISC", - "devDependencies": { - "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "3.5.0", - "tap": "^16.3.0" - }, - "repository": { - "type": "git", - "url": "https://github.com/npm/unique-slug.git" - }, - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "files": [ - "bin/", - "lib/" - ], - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - }, - "templateOSS": { - "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "3.5.0" - } -} diff --git a/node_modules/node-gyp/package.json b/node_modules/node-gyp/package.json index f95ebeadecd70..7e9fb648ab082 100644 --- a/node_modules/node-gyp/package.json +++ b/node_modules/node-gyp/package.json @@ -11,8 +11,8 @@ "bindings", "gyp" ], - "version": "9.3.1", - "installVersion": 9, + "version": "9.4.0", + "installVersion": 11, "author": "Nathan Rajlich (http://tootallnate.net)", "repository": { "type": "git", @@ -23,9 +23,10 @@ "main": "./lib/node-gyp.js", "dependencies": { "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", "glob": "^7.1.4", "graceful-fs": "^4.2.6", - "make-fetch-happen": "^10.0.3", + "make-fetch-happen": "^11.0.3", "nopt": "^6.0.0", "npmlog": "^6.0.0", "rimraf": "^3.0.2", @@ -38,13 +39,13 @@ }, "devDependencies": { "bindings": "^1.5.0", + "mocha": "^10.2.0", "nan": "^2.14.2", "require-inject": "^1.4.4", - "standard": "^14.3.4", - "tap": "^12.7.0" + "standard": "^14.3.4" }, "scripts": { "lint": "standard */*.js test/**/*.js", - "test": "npm run lint && tap --timeout=600 test/test-*" + "test": "npm run lint && mocha --reporter=test/reporter.js test/test-download.js test/test-*" } } diff --git a/node_modules/node-gyp/test/fixtures/VS_2022_Community_workload.txt b/node_modules/node-gyp/test/fixtures/VS_2022_Community_workload.txt new file mode 100644 index 0000000000000..7cd20f8598926 --- /dev/null +++ b/node_modules/node-gyp/test/fixtures/VS_2022_Community_workload.txt @@ -0,0 +1,569 @@ +[ + { + "path": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community", + "version": "17.4.33213.308", + "packages": [ + "Microsoft.VisualStudio.Product.Community", + "Microsoft.VisualStudio.PackageGroup.LiveShare.VSCore", + "Microsoft.VisualStudio.LiveShare.VSCore", + "Microsoft.VisualStudio.Workload.NativeDesktop", + "Microsoft.VisualStudio.Component.VC.ASAN", + "Microsoft.VisualCpp.ASAN.X86", + "Microsoft.VC.14.34.17.4.ASAN.X86.base", + "Microsoft.VC.14.34.17.4.ASAN.X64.base", + "Microsoft.VC.14.34.17.4.ASAN.Headers.base", + "Microsoft.VisualStudio.VC.IDE.Project.Factories", + "Microsoft.VisualStudio.Component.VC.TestAdapterForGoogleTest", + "Microsoft.VisualStudio.VC.Ide.TestAdapterForGoogleTest", + "Microsoft.VisualStudio.Component.VC.TestAdapterForBoostTest", + "Microsoft.VisualStudio.VC.Ide.TestAdapterForBoostTest", + "Microsoft.VisualStudio.Component.VC.CMake.Project", + "Microsoft.VisualStudio.ComponentGroup.WebToolsExtensions.CMake", + "Microsoft.VisualStudio.VC.CMake", + "Microsoft.VisualStudio.VC.CMake.Project", + "Microsoft.VisualStudio.VC.CMake.Client", + "Microsoft.VisualStudio.VC.ExternalBuildFramework", + "Microsoft.VisualStudio.Component.VC.DiagnosticTools", + "Microsoft.VisualStudio.ComponentGroup.NativeDesktop.Core", + "Microsoft.VisualStudio.PackageGroup.TestTools.Native", + "Microsoft.VisualStudio.Component.VC.Redist.14.Latest", + "Microsoft.VisualStudio.VC.Templates.UnitTest", + "Microsoft.VisualStudio.VC.UnitTest.Desktop.Build.Core", + "Microsoft.VisualStudio.TestTools.TestPlatform.V1.CPP", + "Microsoft.VisualStudio.VC.Templates.UnitTest.Resources", + "Microsoft.VisualStudio.VC.Templates.Desktop", + "Microsoft.VisualStudio.Component.Graphics", + "Microsoft.VisualStudio.Graphics.Viewers", + "Microsoft.VisualStudio.Graphics.Viewers.Resources", + "Microsoft.VisualStudio.Component.VC.ATL.ARM64", + "Microsoft.VisualCpp.ATL.ARM64", + "Microsoft.VC.14.34.17.4.ATL.ARM64.base", + "Microsoft.VisualStudio.Component.VC.ATL", + "Microsoft.VisualStudio.VC.Ide.ATL", + "Microsoft.VisualStudio.VC.Ide.ATL.Resources", + "Microsoft.VisualCpp.ATL.X86", + "Microsoft.VC.14.34.17.4.ATL.X86.base", + "Microsoft.VisualCpp.ATL.X64", + "Microsoft.VC.14.34.17.4.ATL.X64.base", + "Microsoft.VC.14.34.17.4.Props.ATLMFC", + "Microsoft.VisualCpp.ATL.Source", + "Microsoft.VC.14.34.17.4.ATL.Source.base", + "Microsoft.VisualCpp.ATL.Headers", + "Microsoft.VC.14.34.17.4.ATL.Headers.base", + "Microsoft.VC.14.34.17.4.Servicing.ATL", + "Microsoft.VisualStudio.Component.VC.Tools.ARM64", + "Microsoft.VisualStudio.VC.MSBuild.v170.ARM64.v143", + "Microsoft.VisualStudio.VC.MSBuild.v170.ARM64", + "Microsoft.VS.VC.vcvars.arm64.Shortcuts", + "Microsoft.VisualCpp.CA.Ext.Hostx64.TargetARM64", + "Microsoft.VC.14.34.17.4.CA.Ext.Hostx64.TargetARM64.base", + "Microsoft.VC.14.34.17.4.CA.Ext.Hostx64.TargetARM64.Res.base", + "Microsoft.VisualCpp.CA.Ext.Hostx86.TargetARM64", + "Microsoft.VC.14.34.17.4.CA.Ext.Hostx86.TargetARM64.base", + "Microsoft.VC.14.34.17.4.CA.Ext.Hostx86.TargetARM64.Res.base", + "Microsoft.VisualCpp.CA.Ext.HostARM64.TargetARM64", + "Microsoft.VC.14.34.17.4.CA.Ext.HostARM64.TargetARM64.base", + "Microsoft.VC.14.34.17.4.CA.Ext.HostARM64.TargetARM64.Res.base", + "Microsoft.VisualCpp.Tools.Hostx86.Targetarm64", + "Microsoft.VC.14.34.17.4.Tools.Hostx86.Targetarm64.base", + "Microsoft.VC.14.34.17.4.Tools.HostX86.TargetARM64.Res.base", + "Microsoft.VisualCpp.Tools.HostARM64.TargetARM64", + "Microsoft.VC.14.34.17.4.Tools.HostARM64.TargetARM64.base", + "Microsoft.VC.14.34.17.4.Tools.HostARM64.TargetARM64.Res.base", + "Microsoft.VisualCpp.CRT.Redist.ARM64.OneCore.Desktop", + "Microsoft.VC.14.34.17.4.CRT.Redist.ARM64.OneCore.Desktop.base", + "Microsoft.VisualCpp.CRT.Redist.ARM64", + "Microsoft.VC.14.34.17.4.CRT.Redist.ARM64.base", + "Microsoft.VisualCpp.CRT.ARM64.OneCore.Desktop", + "Microsoft.VC.14.34.17.4.CRT.ARM64.OneCore.Desktop.base", + "Microsoft.VC.14.34.17.4.CRT.ARM64.OneCore.Desktop.debug.base", + "Microsoft.VisualCpp.CRT.ARM64.Store", + "Microsoft.VC.14.34.17.4.CRT.ARM64.Store.base", + "Microsoft.VisualCpp.CRT.ARM64.Desktop", + "Microsoft.VC.14.34.17.4.CRT.ARM64.Desktop.base", + "Microsoft.VC.14.34.17.4.CRT.ARM64.Desktop.debug.base", + "Microsoft.VisualStudio.PackageGroup.VC.Tools.x64.ARM64", + "Microsoft.VisualCpp.Tools.Core", + "Microsoft.VisualCpp.PGO.ARM64", + "Microsoft.VC.14.34.17.4.PGO.ARM64.base", + "Microsoft.VisualCpp.Premium.Tools.Hostx86.Targetarm64", + "Microsoft.VC.14.34.17.4.Premium.Tools.Hostx86.Targetarm64.base", + "Microsoft.VC.14.34.17.4.Prem.HostX86.TargetARM64.Res.base", + "Microsoft.VisualCpp.Premium.Tools.HostX64.TargetARM64", + "Microsoft.VC.14.34.17.4.Premium.Tools.HostX64.TargetARM64.base", + "Microsoft.VC.14.34.17.4.Prem.HostX64.TargetARM64.Res.base", + "Microsoft.VisualCpp.Premium.Tools.ARM64.Base", + "Microsoft.VC.14.34.17.4.Premium.Tools.ARM64.Base.base", + "Microsoft.VisualCpp.Tools.HostX64.TargetARM64", + "Microsoft.VC.14.34.17.4.Tools.HostX64.TargetARM64.base", + "Microsoft.VC.14.34.17.4.Props.ARM64", + "Microsoft.VC.14.34.17.4.Tools.HostX64.TargetARM64.Res.base", + "Microsoft.VisualStudio.Component.VC.Tools.ARM64EC", + "Microsoft.VisualStudio.Component.Windows11SDK.22621", + "Win11SDK_10.0.22621", + "Microsoft.VisualStudio.VC.MSBuild.v170.ARM64EC.v143", + "Microsoft.VisualStudio.VC.MSBuild.v170.ARM64EC", + "Microsoft.VisualCpp.CRT.ARM64EC.Store", + "Microsoft.VC.14.34.17.4.CRT.ARM64EC.Store.base", + "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", + "Microsoft.VisualCpp.CodeAnalysis.Extensions", + "Microsoft.VisualCpp.CA.Ext.HostARM64.Targetx64", + "Microsoft.VC.14.34.17.4.CA.Ext.HostARM64.Targetx64.base", + "Microsoft.VC.14.34.17.4.CA.Ext.HostARM64.Targetx64.Res.base", + "Microsoft.VisualCpp.CA.Ext.HostARM64.Targetx86", + "Microsoft.VC.14.34.17.4.CA.Ext.HostARM64.Targetx86.base", + "Microsoft.VC.14.34.17.4.CA.Ext.HostARM64.Targetx86.Res.base", + "Microsoft.VisualCpp.CA.Ext.Hostx86.Targetx64", + "Microsoft.VC.14.34.17.4.CA.Ext.Hostx86.Targetx64.base", + "Microsoft.VC.14.34.17.4.CA.Ext.Hostx86.Targetx64.Res.base", + "Microsoft.VisualCpp.CA.Ext.Hostx86.Targetx86", + "Microsoft.VC.14.34.17.4.CA.Ext.Hostx86.Targetx86.base", + "Microsoft.VC.14.34.17.4.CA.Ext.Hostx86.Targetx86.Res.base", + "Microsoft.VisualCpp.CA.Ext.Hostx64.Targetx64", + "Microsoft.VC.14.34.17.4.CA.Ext.Hostx64.Targetx64.base", + "Microsoft.VC.14.34.17.4.CA.Ext.Hostx64.Targetx64.Res.base", + "Microsoft.VisualCpp.CA.Ext.Hostx64.Targetx86", + "Microsoft.VC.14.34.17.4.CA.Ext.Hostx64.Targetx86.base", + "Microsoft.VC.14.34.17.4.Servicing.CAExtensions", + "Microsoft.VC.14.34.17.4.CA.Ext.Hostx64.Targetx86.Res.base", + "Microsoft.VisualCpp.Tools.HostX64.TargetX86", + "Microsoft.VC.14.34.17.4.Tools.HostX64.TargetX86.base", + "Microsoft.VC.14.34.17.4.Tools.HostX64.TargetX86.Res.base", + "Microsoft.VisualCpp.Tools.HostX64.TargetX64", + "Microsoft.VC.14.34.17.4.Tools.HostX64.TargetX64.base", + "Microsoft.VC.14.34.17.4.Tools.HostX64.TargetX64.Res.base", + "Microsoft.VisualCpp.Tools.HostARM64.TargetX86", + "Microsoft.VC.14.34.17.4.Tools.HostARM64.TargetX86.base", + "Microsoft.VisualCpp.RuntimeDebug.14", + "Microsoft.VC.14.34.17.4.Tools.HostARM64.TargetX86.Res.base", + "Microsoft.VisualCpp.Tools.HostARM64.TargetX64", + "Microsoft.VC.14.34.17.4.Tools.HostARM64.TargetX64.base", + "Microsoft.VisualCpp.RuntimeDebug.14.ARM64", + "Microsoft.VisualCpp.Redist.14.Latest", + "Microsoft.VisualCpp.Redist.14.Latest", + "Microsoft.VC.14.34.17.4.Tools.HostARM64.Targetx64.Res.base", + "Microsoft.VisualCpp.Premium.Tools.HostX86.TargetX64", + "Microsoft.VC.14.34.17.4.Premium.Tools.HostX86.TargetX64.base", + "Microsoft.VC.14.34.17.4.Prem.Hostx86.Targetx64.Res.base", + "Microsoft.VisualCpp.Premium.Tools.HostX86.TargetX86", + "Microsoft.VC.14.34.17.4.Premium.Tools.HostX86.TargetX86.base", + "Microsoft.VC.14.34.17.4.Prem.HostX86.TargetX86.Res.base", + "Microsoft.VisualCpp.Premium.Tools.HostARM64.TargetX86", + "Microsoft.VC.14.34.17.4.Premium.Tools.HostARM64.TargetX86.base", + "Microsoft.VC.14.34.17.4.Prem.HostARM64.TargetX86.Res.base", + "Microsoft.VisualCpp.Premium.Tools.HostARM64.TargetX64", + "Microsoft.VC.14.34.17.4.Premium.Tools.HostARM64.TargetX64.base", + "Microsoft.VC.14.34.17.4.Prem.HostARM64.Targetx64.Res.base", + "Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX86", + "Microsoft.VC.14.34.17.4.Premium.Tools.HostX64.TargetX86.base", + "Microsoft.VC.14.34.17.4.Prem.HostX64.TargetX86.Res.base", + "Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX64", + "Microsoft.VC.14.34.17.4.Premium.Tools.HostX64.TargetX64.base", + "Microsoft.VC.14.34.17.4.Prem.HostX64.TargetX64.Res.base", + "Microsoft.VisualCpp.PGO.X86", + "Microsoft.VC.14.34.17.4.PGO.X86.base", + "Microsoft.VisualCpp.PGO.X64", + "Microsoft.VC.14.34.17.4.PGO.X64.base", + "Microsoft.VisualCpp.PGO.Headers", + "Microsoft.VC.14.34.17.4.PGO.Headers.base", + "Microsoft.VisualCpp.CRT.x86.Store", + "Microsoft.VC.14.34.17.4.CRT.x86.Store.base", + "Microsoft.VisualCpp.CRT.x86.OneCore.Desktop", + "Microsoft.VC.14.34.17.4.CRT.x86.OneCore.Desktop.base", + "Microsoft.VisualCpp.CRT.x64.Store", + "Microsoft.VC.14.34.17.4.CRT.x64.Store.base", + "Microsoft.VisualCpp.CRT.x64.OneCore.Desktop", + "Microsoft.VC.14.34.17.4.CRT.x64.OneCore.Desktop.base", + "Microsoft.VisualCpp.CRT.Redist.x86.OneCore.Desktop", + "Microsoft.VC.14.34.17.4.CRT.Redist.x86.OneCore.Desktop.base", + "Microsoft.VisualCpp.CRT.Redist.x64.OneCore.Desktop", + "Microsoft.VC.14.34.17.4.CRT.Redist.x64.OneCore.Desktop.base", + "Microsoft.VisualStudio.PackageGroup.VC.Tools.x86", + "Microsoft.VisualCpp.Tools.Hostx86.Targetx64.Res", + "Microsoft.VisualCpp.Tools.HostX86.TargetX64", + "Microsoft.VC.14.34.17.4.Tools.HostX86.TargetX64.base", + "Microsoft.VC.14.34.17.4.Props.x64", + "Microsoft.VC.14.34.17.4.Tools.Hostx86.Targetx64.Res.base", + "Microsoft.VisualCpp.Tools.HostX86.TargetX86.Res", + "Microsoft.VisualCpp.Tools.HostX86.TargetX86", + "Microsoft.VC.14.34.17.4.Tools.HostX86.TargetX86.base", + "Microsoft.VC.14.34.17.4.Servicing.Compilers", + "Microsoft.VC.14.34.17.4.Props.x86", + "Microsoft.VC.14.34.17.4.Props", + "Microsoft.VC.14.34.17.4.Tools.HostX86.TargetX86.Res.base", + "Microsoft.VisualCpp.Tools.Core.Resources", + "Microsoft.VisualCpp.Tools.Core.x86", + "Microsoft.VC.14.34.17.4.Tools.Core.Props", + "Microsoft.VisualCpp.DIA.SDK", + "Microsoft.VisualCpp.Servicing.DIASDK", + "Microsoft.VisualCpp.CRT.x86.Desktop", + "Microsoft.VC.14.34.17.4.CRT.x86.Desktop.base", + "Microsoft.VisualCpp.CRT.x64.Desktop", + "Microsoft.VC.14.34.17.4.CRT.x64.Desktop.base", + "Microsoft.VisualCpp.CRT.Source", + "Microsoft.VC.14.34.17.4.CRT.Source.base", + "Microsoft.VisualCpp.CRT.Redist.X86", + "Microsoft.VC.14.34.17.4.CRT.Redist.X86.base", + "Microsoft.VisualCpp.CRT.Redist.X64", + "Microsoft.VisualCpp.CRT.Redist.Resources", + "Microsoft.VC.14.34.17.4.CRT.Redist.X64.base", + "Microsoft.VisualCpp.CRT.Headers", + "Microsoft.VC.14.34.17.4.CRT.Headers.base", + "Microsoft.VC.14.34.17.4.Servicing.CrtHeaders", + "Microsoft.VC.14.34.17.4.Servicing", + "Microsoft.VisualStudio.Component.VC.CoreIde", + "Microsoft.VisualStudio.VC.Ide.Pro", + "Microsoft.VisualStudio.VC.Ide.Pro.Resources", + "Microsoft.VisualStudio.VC.Templates.General", + "Microsoft.VisualStudio.VC.Templates.General.Resources", + "Microsoft.VisualStudio.VC.Items.Pro", + "Microsoft.VisualStudio.PackageGroup.VC.CoreIDE.Reduced", + "Microsoft.VisualStudio.VC.Ide.x64", + "Microsoft.VisualStudio.PackageGroup.VC.CoreIDE.Express", + "Microsoft.VisualStudio.VC.vcvars", + "Microsoft.VS.VC.vcvars.x86.Shortcuts", + "Microsoft.VS.VC.vcvars.x64.Shortcuts", + "Microsoft.VS.VC.vcvars.arm64_x64.Shortcuts", + "Microsoft.VisualStudio.VC.MSBuild.v170.X64.v143", + "Microsoft.VisualStudio.VC.MSBuild.v170.X64", + "Microsoft.VisualStudio.VC.MSBuild.v170.ARM.v143", + "Microsoft.VisualStudio.VC.MSBuild.v170.ARM", + "Microsoft.VisualStudio.VC.MSBuild.v170.x86.v143", + "Microsoft.VisualStudio.VC.MSBuild.v170.X86", + "Microsoft.VisualStudio.VC.MSBuild.v170.Base", + "Microsoft.VisualStudio.VC.MSBuild.v170.Base.Resources", + "Microsoft.VisualStudio.VC.Ide.WinXPlus", + "Microsoft.VisualStudio.VC.Ide.Dskx", + "Microsoft.VisualStudio.VC.Ide.Dskx.Resources", + "Microsoft.VisualStudio.VC.Ide.Base", + "Microsoft.VisualStudio.VC.Ide.LanguageService", + "Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.Scripts", + "Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.PythonDistro", + "Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.10", + "Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.9", + "Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.8", + "Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.7", + "Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.6", + "Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.5", + "Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.4", + "Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.3", + "Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.2", + "Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.1", + "Microsoft.VisualStudio.VC.Ide.VCPkgDatabase", + "Microsoft.VisualStudio.VC.Ide.Core", + "Microsoft.VisualStudio.VC.Ide.ProjectSystem", + "Microsoft.VisualStudio.VC.Ide.ProjectSystem.Resources", + "Microsoft.VisualStudio.VC.Ide.Core.VCProjectEngine", + "Microsoft.VisualStudio.VC.Ide.Core.VCProjectEngine.Resources", + "Microsoft.VisualStudio.VC.Ide.LanguageService.Resources", + "Microsoft.VisualStudio.VC.Llvm.Base", + "Microsoft.VisualStudio.VC.Ide.Base.Resources", + "Microsoft.Net.PackageGroup.4.8.1.Redist", + "Microsoft.VisualStudio.Component.IntelliCode", + "Microsoft.VisualStudio.IntelliCode.CSharp", + "Microsoft.VisualStudio.IntelliCode", + "Component.Microsoft.VisualStudio.LiveShare.2022", + "Microsoft.VisualStudio.Component.Debugger.JustInTime", + "Microsoft.VisualStudio.Debugger.ImmersiveActivateHelper.Msi", + "Microsoft.VisualStudio.Debugger.JustInTime", + "Microsoft.VisualStudio.Debugger.JustInTime.Msi", + "Microsoft.VisualStudio.LiveShare.2022", + "Microsoft.Icecap.Analysis", + "Microsoft.Icecap.Analysis.Resources", + "Microsoft.Icecap.Analysis.Resources.Targeted", + "Microsoft.Icecap.Collection.Msi", + "Microsoft.Icecap.Collection.Msi.Targeted", + "Microsoft.Icecap.Collection.Msi.Resources", + "Microsoft.Icecap.Collection.Msi.Resources.Targeted", + "Microsoft.DiagnosticsHub.Instrumentation", + "Microsoft.DiagnosticsHub.Instrumentation.Targeted", + "Microsoft.DiagnosticsHub.CpuSampling", + "Microsoft.DiagnosticsHub.CpuSampling.Targeted", + "Microsoft.PackageGroup.DiagnosticsHub.Platform", + "Microsoft.VisualStudio.InstrumentationEngine.ARM64", + "Microsoft.VisualStudio.InstrumentationEngine", + "Microsoft.DiagnosticsHub.Runtime.ExternalDependencies", + "SQLiteCore", + "SQLiteCore.Targeted", + "Microsoft.DiagnosticsHub.Runtime.ExternalDependencies.Targeted", + "Microsoft.DiagnosticsHub.Runtime", + "Microsoft.DiagnosticsHub.Runtime.Targeted", + "Microsoft.DiagnosticsHub.Collection.ExternalDependencies.arm64", + "Microsoft.DiagnosticsHub.Collection", + "Microsoft.DiagnosticsHub.Collection.Service", + "Microsoft.VisualStudio.VC.Ide.MDD", + "Microsoft.VisualStudio.VC.Ide.Linux.ConnectionManager", + "Microsoft.VisualStudio.VisualC.Utilities", + "Microsoft.VisualStudio.VisualC.Utilities.Resources", + "Microsoft.VisualStudio.VC.Ide.Linux.ConnectionManager.Resources", + "Microsoft.VisualStudio.VC.Ide.ResourceEditor", + "Microsoft.VisualStudio.VC.Ide.ResourceEditor.Resources", + "Microsoft.VisualStudio.PackageGroup.TestTools.Core", + "Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.V2.CLI", + "Microsoft.VisualStudio.TestTools.TestPlatform.V2.CLI", + "Microsoft.VisualStudio.TestTools.Pex.Common", + "Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.V1.CLI", + "Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.Legacy", + "Microsoft.VisualStudio.PackageGroup.MinShell.Interop", + "Microsoft.VisualStudio.TestTools.TP.Legacy.Tips.Msi", + "Microsoft.VisualStudio.TestTools.TP.Legacy.Tips.Common", + "Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Tips", + "Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Tips.Resources", + "Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.TestSettings", + "Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Professional", + "Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Common", + "Microsoft.VisualStudio.TestTools.TP.Legacy.Common.Res", + "Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Core", + "Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Core.Resources", + "Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Agent", + "Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.IDE", + "Microsoft.VisualStudio.Cache.Service", + "Microsoft.VisualStudio.TestTools.TestWIExtension", + "Microsoft.VisualStudio.TestTools.TestPlatform.V1.CLI", + "Microsoft.VisualStudio.TestTools.TestPlatform.IDE", + "Microsoft.VisualStudio.PackageGroup.TestTools.CodeCoverage", + "Microsoft.VisualStudio.PackageGroup.TestTools.DataCollectors", + "Microsoft.VisualStudio.Component.NuGet", + "Microsoft.CredentialProvider", + "Microsoft.VisualStudio.NuGet.Licenses", + "Microsoft.VisualStudio.Component.TextTemplating", + "Microsoft.VisualStudio.TextTemplating.MSBuild", + "Microsoft.VisualStudio.TextTemplating.Integration", + "Microsoft.VisualStudio.TextTemplating.Core", + "Microsoft.VisualStudio.TextTemplating.Integration.Resources", + "Microsoft.VisualCpp.CRT.ClickOnce.Msi", + "Microsoft.VisualStudio.Component.Roslyn.LanguageServices", + "Microsoft.VisualStudio.InteractiveWindow", + "Microsoft.DiaSymReader.Native", + "Microsoft.VisualCpp.Redist.14", + "Microsoft.VisualCpp.Redist.14", + "Microsoft.VisualCpp.Servicing.Redist", + "Microsoft.VisualStudio.PackageGroup.StaticAnalysis", + "Microsoft.VisualStudio.StaticAnalysis.IDE", + "Microsoft.VisualStudio.StaticAnalysis.IDE.Resources", + "Microsoft.VisualStudio.StaticAnalysis.FxCop.Resources", + "Microsoft.VisualStudio.StaticAnalysis.auxil", + "Microsoft.VisualStudio.StaticAnalysis.auxil.Resources", + "Roslyn.VisualStudio.Setup.ServiceHub", + "Microsoft.Component.MSBuild", + "Microsoft.NuGet.Build.Tasks.Setup", + "Microsoft.VisualStudio.Component.Roslyn.Compiler", + "Microsoft.CodeAnalysis.Compilers", + "Microsoft.VisualStudio.Component.JavaScript.TypeScript", + "Microsoft.VisualStudio.JavaScript.ProjectSystem", + "Microsoft.VisualStudio.ComponentGroup.WebToolsExtensions", + "Microsoft.VisualStudio.ProTools", + "sqlsysclrtypes", + "SQLCommon", + "Microsoft.VisualStudio.ProTools.Resources", + "Microsoft.VisualStudio.Web.Scaffolding", + "Microsoft.VisualStudio.WebToolsExtensions", + "Microsoft.VisualStudio.ConnectedServices.Core", + "Microsoft.VisualStudio.WebTools", + "Microsoft.VisualStudio.WebToolsExtensions.MSBuild", + "Microsoft.VisualStudio.WebTools.Resources", + "Microsoft.VisualStudio.WebTools.WSP.FSA", + "Microsoft.VisualStudio.WebTools.WSP.FSA.Resources", + "Microsoft.VisualStudio.PackageGroup.Debugger.Script", + "Microsoft.VisualStudio.Component.TypeScript.TSServer", + "Microsoft.VisualStudio.Package.TypeScript.TSServer", + "Microsoft.VisualStudio.PackageGroup.JavaScript.Language", + "Microsoft.VisualStudio.Package.NodeJs", + "TypeScript.Build", + "TypeScript.LanguageService", + "TypeScript.Tools", + "Microsoft.VisualStudio.PackageGroup.Community", + "Microsoft.VisualStudio.Community.VB.x86", + "Microsoft.VisualStudio.Community.VB.x64", + "Microsoft.VisualStudio.PackageGroup.Core", + "Microsoft.VisualStudio.CodeSense.Community", + "Microsoft.VisualStudio.TestTools.TeamFoundationClient", + "Microsoft.VisualStudio.PackageGroup.Debugger.Core", + "Microsoft.VisualStudio.Debugger.BrokeredServices", + "Microsoft.VisualStudio.Debugger.VSCodeDebuggerHost", + "Microsoft.VisualStudio.Debugger.AzureAttach", + "Microsoft.VisualStudio.Web.Azure.Common", + "Microsoft.WebTools.Shared", + "Microsoft.WebTools.DotNet.Core.ItemTemplates", + "Microsoft.VisualStudio.PackageGroup.Debugger.TimeTravel.Replay", + "Microsoft.VisualStudio.VC.Ide.Debugger", + "Microsoft.VisualStudio.VC.Ide.Debugger.Concord", + "Microsoft.VisualStudio.VC.Ide.Debugger.Concord.Resources", + "Microsoft.VisualStudio.VC.Ide.Debugger.Resources", + "Microsoft.VisualStudio.VC.Ide.Common", + "Microsoft.VisualStudio.VC.Ide.Common.Resources", + "Microsoft.VisualStudio.Debugger.CollectionAgents", + "Microsoft.VisualStudio.Debugger.Parallel", + "Microsoft.VisualStudio.Debugger.Parallel.Resources", + "Microsoft.VisualStudio.Debugger.Managed", + "Microsoft.CodeAnalysis.ExpressionEvaluator", + "Microsoft.CodeAnalysis.VisualStudio.Setup", + "Microsoft.VisualStudio.Debugger.Concord.Managed", + "Microsoft.VisualStudio.Debugger.Concord.Managed.Resources", + "Microsoft.VisualStudio.Debugger.Managed.Resources", + "Microsoft.VisualStudio.Debugger.TargetComposition", + "Microsoft.VisualStudio.Debugger.TargetComposition.Remote.arm64", + "Microsoft.VisualStudio.Debugger.TargetComposition.Remote", + "Microsoft.VisualStudio.Debugger.TargetComposition.Remote", + "Microsoft.VisualStudio.Debugger.Remote", + "Microsoft.VisualStudio.Debugger.Concord.Remote", + "Microsoft.VisualStudio.Debugger.Concord.Remote.Resources", + "Microsoft.VisualStudio.Debugger.Remote", + "Microsoft.VisualStudio.Debugger.Remote.ARM64", + "Microsoft.VisualStudio.Debugger.Concord.Remote.ARM64", + "Microsoft.VisualStudio.Debugger.Concord.Remote.Resources.ARM64", + "Microsoft.VisualStudio.Debugger.Remote.ARM", + "Microsoft.VisualStudio.Debugger.Concord.Remote.ARM", + "Microsoft.VisualStudio.Debugger.Concord.Remote.Resources.ARM", + "Microsoft.VisualStudio.Debugger.Remote.Resources.ARM", + "Microsoft.VisualStudio.Debugger.Remote.Resources.ARM64", + "Microsoft.VisualStudio.Debugger.Concord.Remote", + "Microsoft.VisualStudio.Debugger.Concord.Remote.Resources", + "Microsoft.VisualStudio.Debugger.Remote.Resources", + "Microsoft.VisualStudio.Debugger.Remote.Resources", + "Microsoft.VisualStudio.Debugger", + "Microsoft.VisualStudio.VC.MSVCDis", + "Microsoft.IntelliTrace.DiagnosticsHub", + "Microsoft.VisualStudio.Debugger.Concord", + "Microsoft.VisualStudio.Debugger.Concord.Resources", + "Microsoft.VisualStudio.Debugger.Resources", + "Microsoft.VisualStudio.Debugger.Package.DiagHub.Client", + "Microsoft.VisualStudio.Debugger.Remote.DiagnosticsHub.Client", + "Microsoft.VisualStudio.Debugger.Remote.DiagnosticsHub.Client", + "Microsoft.VisualStudio.Debugger.Remote.DiagnosticsHub.Client", + "Microsoft.PackageGroup.ClientDiagnostics", + "Microsoft.VisualStudio.AppResponsiveness", + "Microsoft.VisualStudio.AppResponsiveness.Targeted", + "Microsoft.VisualStudio.AppResponsiveness.Resources", + "Microsoft.VisualStudio.ClientDiagnostics", + "Microsoft.VisualStudio.ClientDiagnostics.Targeted", + "Microsoft.VisualStudio.ClientDiagnostics.Resources", + "Microsoft.VisualStudio.PackageGroup.CommunityCore", + "Microsoft.VisualStudio.ProjectSystem.Full", + "Microsoft.VisualStudio.LiveShareApi", + "Microsoft.VisualStudio.ProjectSystem.Query", + "Microsoft.VisualStudio.ProjectSystem", + "Microsoft.VisualStudio.Community.x86", + "Microsoft.VisualStudio.Community.x64", + "Microsoft.VisualStudio.Community.Msi.Resources", + "Microsoft.VisualStudio.Community.Msi", + "Microsoft.VisualStudio.Community.Shared.Msi", + "Microsoft.VisualStudio.Devenv.Msi", + "Microsoft.VisualStudio.Devenv.Shared.Msi", + "Microsoft.VisualStudio.MinShell.Interop.Msi", + "Microsoft.VisualStudio.MinShell.Interop.Shared.Msi", + "Microsoft.VisualStudio.Editors", + "Microsoft.VisualStudio.Workload.CoreEditor", + "Microsoft.VisualStudio.Component.CoreEditor", + "Microsoft.VisualStudio.PackageGroup.CoreEditor", + "Microsoft.WebView2", + "Microsoft.VisualStudio.ScriptedHost", + "Microsoft.VisualStudio.ScriptedHost.Targeted", + "Microsoft.VisualCpp.Tools.Common.UtilsPrereq", + "Microsoft.VisualCpp.Tools.Common.Utils", + "Microsoft.VisualCpp.Tools.Common.Utils.Resources", + "Microsoft.VisualStudio.PackageGroup.VsDevCmd", + "Microsoft.VisualStudio.VsDevCmd.Ext.NetFxSdk", + "Microsoft.VisualStudio.VsDevCmd.Core.WinSdk", + "Microsoft.VisualStudio.VsDevCmd.Core.DotNet", + "Microsoft.VisualStudio.VC.DevCmd", + "Microsoft.VisualStudio.VC.DevCmd.Resources", + "Microsoft.VisualStudio.VirtualTree", + "Microsoft.DiaSymReader", + "Microsoft.Build.Dependencies", + "Microsoft.Build.FileTracker.Msi", + "Microsoft.Build", + "Microsoft.VisualStudio.PackageGroup.NuGet", + "Microsoft.DataAI.NuGetRecommender", + "Microsoft.VisualStudio.NuGet.Core", + "Microsoft.Build.Arm64", + "Microsoft.Build.UnGAC", + "Microsoft.VisualStudio.TextMateGrammars", + "Microsoft.VisualStudio.Platform.Markdown", + "Microsoft.VisualStudio.Platform.CrossRepositorySearch", + "Microsoft.VisualStudio.PackageGroup.TeamExplorer.Common", + "Microsoft.VisualStudio.TeamExplorer", + "Microsoft.VisualStudio.PackageGroup.ServiceHub", + "Microsoft.ServiceHub.Node", + "Microsoft.ServiceHub.Managed", + "Microsoft.ServiceHub.arm64", + "Microsoft.VisualStudio.ProjectServices", + "Microsoft.VisualStudio.OpenFolder.VSIX", + "Microsoft.VisualStudio.FileHandler.Msi", + "Microsoft.VisualStudio.FileHandler.Msi", + "Microsoft.VisualStudio.PackageGroup.MinShell", + "Microsoft.VisualStudio.MinShell.Msi", + "Microsoft.VisualStudio.MinShell.Shared.Msi", + "Microsoft.VisualStudio.MinShell.Msi.Resources", + "Microsoft.VisualStudio.MinShell.Interop", + "CoreEditorFonts", + "Microsoft.VisualStudio.Log", + "Microsoft.VisualStudio.Log.Targeted", + "Microsoft.VisualStudio.Log.Resources", + "Microsoft.VisualStudio.Finalizer", + "Microsoft.VisualStudio.Devenv", + "Microsoft.VisualStudio.Devenv.Resources", + "Microsoft.VisualStudio.CoreEditor", + "Microsoft.VisualStudio.Navigation.RichCodeNav", + "Microsoft.VisualStudio.Platform.NavigateTo", + "Microsoft.VisualStudio.Connected", + "SQLitePCLRaw", + "SQLitePCLRaw.Targeted", + "Microsoft.VisualStudio.Connected.Auto", + "Microsoft.VisualStudio.Connected.Auto.Resources", + "Microsoft.VisualStudio.AzureSDK", + "Microsoft.VisualStudio.PerfLib", + "Microsoft.VisualStudio.Connected.Resources", + "Microsoft.Net.PackageGroup.4.8.Redist", + "Microsoft.VisualStudio.PackageGroup.Progression", + "Microsoft.VisualStudio.PerformanceProvider", + "Microsoft.VisualStudio.GraphModel", + "Microsoft.VisualStudio.GraphProvider", + "Microsoft.VisualStudio.Community.VB.Targeted", + "Microsoft.VisualStudio.Community.VB.Neutral", + "Microsoft.VisualStudio.Community.CSharp.Targeted", + "Microsoft.VisualStudio.Community.CSharp.Neutral", + "Microsoft.VisualStudio.Community.ProductArch.TargetedExtra", + "Microsoft.VisualStudio.Community.ProductArch.Targeted", + "Microsoft.VisualStudio.Community.ProductArch.NeutralExtra", + "Microsoft.DiaSymReader.PortablePdb", + "Microsoft.IntelliTrace.CollectorCab", + "Microsoft.VisualStudio.Community.VB.Resources.Targeted", + "Microsoft.VisualStudio.Community.VB.Resources.Neutral", + "Microsoft.VisualStudio.Community.CSharp.Resources.Targeted", + "Microsoft.VisualStudio.Community.CSharp.Resources.Neutral", + "Microsoft.VisualStudio.Community.ProductArch.Resources.Targeted", + "Microsoft.VisualStudio.Community.ProductArch.Resources.NeutralExtra", + "Microsoft.VisualStudio.Net.Eula.Resources", + "Microsoft.VisualStudio.Community.ProductArch.Resources.Neutral", + "Microsoft.VisualStudio.WebSiteProject.DTE", + "Microsoft.VisualStudio.Diagnostics.AspNetHelper", + "Microsoft.VisualStudio.Diagnostics.AspNetHelper.Standard", + "Microsoft.MSHtml", + "Microsoft.VisualStudio.Platform.CallHierarchy", + "Microsoft.VisualStudio.Community.ProductArch.Neutral", + "Microsoft.VisualStudio.MinShell", + "Microsoft.VisualStudio.VsWebProtocolSelector.Msi", + "Microsoft.Net.6.WindowsDesktop.Runtime", + "Microsoft.Net.6.Runtime", + "Microsoft.VisualStudio.PackageGroup.Setup.Common", + "Microsoft.VisualStudio.Setup.WMIProvider", + "Microsoft.VisualStudio.Setup.Configuration.Interop", + "Microsoft.VisualStudio.Setup.Configuration", + "Microsoft.VisualStudio.Extensibility.Container", + "Microsoft.VisualStudio.LanguageServer", + "Microsoft.VisualStudio.Platform.Terminal", + "Microsoft.VisualStudio.MefHosting", + "Microsoft.VisualStudio.Initializer", + "Microsoft.VisualStudio.ExtensionManager", + "Microsoft.VisualStudio.Platform.Editor", + "Microsoft.VisualStudio.MinShell.Targeted", + "Microsoft.VisualStudio.NativeImageSupport", + "Microsoft.VisualStudio.Devenv.Config", + "Microsoft.VisualStudio.MinShell.Resources.arm64", + "Microsoft.VisualStudio.MinShell.Auto", + "Microsoft.VisualStudio.MinShell.Auto.Resources", + "Microsoft.VisualStudio.Branding.Community" + ] + } +] diff --git a/node_modules/node-gyp/test/reporter.js b/node_modules/node-gyp/test/reporter.js new file mode 100644 index 0000000000000..9964b1b5d504c --- /dev/null +++ b/node_modules/node-gyp/test/reporter.js @@ -0,0 +1,75 @@ +const Mocha = require('mocha') + +class Reporter { + constructor (runner) { + this.failedTests = [] + + runner.on(Mocha.Runner.constants.EVENT_RUN_BEGIN, () => { + console.log('Starting tests') + }) + + runner.on(Mocha.Runner.constants.EVENT_RUN_END, () => { + console.log('Tests finished') + console.log() + console.log('****************') + console.log('* TESTS REPORT *') + console.log('****************') + console.log() + console.log(`Executed ${runner.stats.suites} suites with ${runner.stats.tests} tests in ${runner.stats.duration} ms`) + console.log(` Passed: ${runner.stats.passes}`) + console.log(` Skipped: ${runner.stats.pending}`) + console.log(` Failed: ${runner.stats.failures}`) + if (this.failedTests.length > 0) { + console.log() + console.log(' Failed test details') + this.failedTests.forEach((failedTest, index) => { + console.log() + console.log(` ${index + 1}.'${failedTest.test.fullTitle()}'`) + console.log(` Name: ${failedTest.error.name}`) + console.log(` Message: ${failedTest.error.message}`) + console.log(` Code: ${failedTest.error.code}`) + console.log(` Stack: ${failedTest.error.stack}`) + }) + } + console.log() + }) + + runner.on(Mocha.Runner.constants.EVENT_SUITE_BEGIN, (suite) => { + if (suite.root) { + return + } + console.log(`Starting suite '${suite.title}'`) + }) + + runner.on(Mocha.Runner.constants.EVENT_SUITE_END, (suite) => { + if (suite.root) { + return + } + console.log(`Suite '${suite.title}' finished`) + console.log() + }) + + runner.on(Mocha.Runner.constants.EVENT_TEST_BEGIN, (test) => { + console.log(`Starting test '${test.title}'`) + }) + + runner.on(Mocha.Runner.constants.EVENT_TEST_PASS, (test) => { + console.log(`Test '${test.title}' passed in ${test.duration} ms`) + }) + + runner.on(Mocha.Runner.constants.EVENT_TEST_PENDING, (test) => { + console.log(`Test '${test.title}' skipped in ${test.duration} ms`) + }) + + runner.on(Mocha.Runner.constants.EVENT_TEST_FAIL, (test, error) => { + this.failedTests.push({ test, error }) + console.log(`Test '${test.title}' failed in ${test.duration} ms with ${error}`) + }) + + runner.on(Mocha.Runner.constants.EVENT_TEST_END, (test) => { + console.log() + }) + } +} + +module.exports = Reporter diff --git a/node_modules/node-gyp/test/test-addon.js b/node_modules/node-gyp/test/test-addon.js index f79eff73c169e..43556620a85ab 100644 --- a/node_modules/node-gyp/test/test-addon.js +++ b/node_modules/node-gyp/test/test-addon.js @@ -1,6 +1,7 @@ 'use strict' -const test = require('tap').test +const { describe, it } = require('mocha') +const assert = require('assert') const path = require('path') const fs = require('graceful-fs') const childProcess = require('child_process') @@ -35,116 +36,117 @@ function checkCharmapValid () { return lines.pop() === 'True' } -test('build simple addon', function (t) { - t.plan(3) - - // Set the loglevel otherwise the output disappears when run via 'npm test' - var cmd = [nodeGyp, 'rebuild', '-C', addonPath, '--loglevel=verbose'] - var proc = execFile(process.execPath, cmd, function (err, stdout, stderr) { - var logLines = stderr.toString().trim().split(/\r?\n/) - var lastLine = logLines[logLines.length - 1] - t.strictEqual(err, null) - t.strictEqual(lastLine, 'gyp info ok', 'should end in ok') - t.strictEqual(runHello().trim(), 'world') +describe('addon', function () { + this.timeout(300000) + + it('build simple addon', function (done) { + // Set the loglevel otherwise the output disappears when run via 'npm test' + var cmd = [nodeGyp, 'rebuild', '-C', addonPath, '--loglevel=verbose'] + var proc = execFile(process.execPath, cmd, function (err, stdout, stderr) { + var logLines = stderr.toString().trim().split(/\r?\n/) + var lastLine = logLines[logLines.length - 1] + assert.strictEqual(err, null) + assert.strictEqual(lastLine, 'gyp info ok', 'should end in ok') + assert.strictEqual(runHello().trim(), 'world') + done() + }) + proc.stdout.setEncoding('utf-8') + proc.stderr.setEncoding('utf-8') }) - proc.stdout.setEncoding('utf-8') - proc.stderr.setEncoding('utf-8') -}) - -test('build simple addon in path with non-ascii characters', function (t) { - t.plan(1) - if (!checkCharmapValid()) { - return t.skip('python console app can\'t encode non-ascii character.') - } + it('build simple addon in path with non-ascii characters', function (done) { + if (!checkCharmapValid()) { + return this.skip('python console app can\'t encode non-ascii character.') + } - var testDirNames = { - cp936: '文件夹', - cp1252: 'Latīna', - cp932: 'フォルダ' - } - // Select non-ascii characters by current encoding - var testDirName = testDirNames[getEncoding()] - // If encoding is UTF-8 or other then no need to test - if (!testDirName) { - return t.skip('no need to test') - } + var testDirNames = { + cp936: '文件夹', + cp1252: 'Latīna', + cp932: 'フォルダ' + } + // Select non-ascii characters by current encoding + var testDirName = testDirNames[getEncoding()] + // If encoding is UTF-8 or other then no need to test + if (!testDirName) { + return this.skip('no need to test') + } - t.plan(3) + this.timeout(300000) - var data - var configPath = path.join(addonPath, 'build', 'config.gypi') - try { - data = fs.readFileSync(configPath, 'utf8') - } catch (err) { - t.error(err) - return - } - var config = JSON.parse(data.replace(/#.+\n/, '')) - var nodeDir = config.variables.nodedir - var testNodeDir = path.join(addonPath, testDirName) - // Create symbol link to path with non-ascii characters - try { - fs.symlinkSync(nodeDir, testNodeDir, 'dir') - } catch (err) { - switch (err.code) { - case 'EEXIST': break - case 'EPERM': - t.error(err, 'Please try to running console as an administrator') - return - default: - t.error(err) - return + var data + var configPath = path.join(addonPath, 'build', 'config.gypi') + try { + data = fs.readFileSync(configPath, 'utf8') + } catch (err) { + assert.fail(err) + return } - } - - var cmd = [ - nodeGyp, - 'rebuild', - '-C', - addonPath, - '--loglevel=verbose', - '-nodedir=' + testNodeDir - ] - var proc = execFile(process.execPath, cmd, function (err, stdout, stderr) { + var config = JSON.parse(data.replace(/#.+\n/, '')) + var nodeDir = config.variables.nodedir + var testNodeDir = path.join(addonPath, testDirName) + // Create symbol link to path with non-ascii characters try { - fs.unlink(testNodeDir) + fs.symlinkSync(nodeDir, testNodeDir, 'dir') } catch (err) { - t.error(err) + switch (err.code) { + case 'EEXIST': break + case 'EPERM': + assert.fail(err, null, 'Please try to running console as an administrator') + return + default: + assert.fail(err) + return + } } - var logLines = stderr.toString().trim().split(/\r?\n/) - var lastLine = logLines[logLines.length - 1] - t.strictEqual(err, null) - t.strictEqual(lastLine, 'gyp info ok', 'should end in ok') - t.strictEqual(runHello().trim(), 'world') + var cmd = [ + nodeGyp, + 'rebuild', + '-C', + addonPath, + '--loglevel=verbose', + '-nodedir=' + testNodeDir + ] + var proc = execFile(process.execPath, cmd, function (err, stdout, stderr) { + try { + fs.unlink(testNodeDir) + } catch (err) { + assert.fail(err) + } + + var logLines = stderr.toString().trim().split(/\r?\n/) + var lastLine = logLines[logLines.length - 1] + assert.strictEqual(err, null) + assert.strictEqual(lastLine, 'gyp info ok', 'should end in ok') + assert.strictEqual(runHello().trim(), 'world') + done() + }) + proc.stdout.setEncoding('utf-8') + proc.stderr.setEncoding('utf-8') }) - proc.stdout.setEncoding('utf-8') - proc.stderr.setEncoding('utf-8') -}) - -test('addon works with renamed host executable', function (t) { - // No `fs.copyFileSync` before node8. - if (process.version.substr(1).split('.')[0] < 8) { - t.skip('skipping test for old node version') - t.end() - return - } - t.plan(3) - - var notNodePath = path.join(os.tmpdir(), 'notnode' + path.extname(process.execPath)) - fs.copyFileSync(process.execPath, notNodePath) + it('addon works with renamed host executable', function (done) { + // No `fs.copyFileSync` before node8. + if (process.version.substr(1).split('.')[0] < 8) { + return this.skip('skipping test for old node version') + } - var cmd = [nodeGyp, 'rebuild', '-C', addonPath, '--loglevel=verbose'] - var proc = execFile(process.execPath, cmd, function (err, stdout, stderr) { - var logLines = stderr.toString().trim().split(/\r?\n/) - var lastLine = logLines[logLines.length - 1] - t.strictEqual(err, null) - t.strictEqual(lastLine, 'gyp info ok', 'should end in ok') - t.strictEqual(runHello(notNodePath).trim(), 'world') - fs.unlinkSync(notNodePath) + this.timeout(300000) + + var notNodePath = path.join(os.tmpdir(), 'notnode' + path.extname(process.execPath)) + fs.copyFileSync(process.execPath, notNodePath) + + var cmd = [nodeGyp, 'rebuild', '-C', addonPath, '--loglevel=verbose'] + var proc = execFile(process.execPath, cmd, function (err, stdout, stderr) { + var logLines = stderr.toString().trim().split(/\r?\n/) + var lastLine = logLines[logLines.length - 1] + assert.strictEqual(err, null) + assert.strictEqual(lastLine, 'gyp info ok', 'should end in ok') + assert.strictEqual(runHello(notNodePath).trim(), 'world') + fs.unlinkSync(notNodePath) + done() + }) + proc.stdout.setEncoding('utf-8') + proc.stderr.setEncoding('utf-8') }) - proc.stdout.setEncoding('utf-8') - proc.stderr.setEncoding('utf-8') }) diff --git a/node_modules/node-gyp/test/test-configure-python.js b/node_modules/node-gyp/test/test-configure-python.js index aacd75f7c7294..ab1e5511fad98 100644 --- a/node_modules/node-gyp/test/test-configure-python.js +++ b/node_modules/node-gyp/test/test-configure-python.js @@ -1,6 +1,7 @@ 'use strict' -const test = require('tap').test +const { describe, it } = require('mocha') +const assert = require('assert') const path = require('path') const devDir = require('./common').devDir() const gyp = require('../lib/node-gyp') @@ -22,63 +23,59 @@ const configure = requireInject('../lib/configure', { const EXPECTED_PYPATH = path.join(__dirname, '..', 'gyp', 'pylib') const SEPARATOR = process.platform === 'win32' ? ';' : ':' -const SPAWN_RESULT = { on: function () { } } +const SPAWN_RESULT = cb => ({ on: function () { cb() } }) require('npmlog').level = 'warn' -test('configure PYTHONPATH with no existing env', function (t) { - t.plan(1) - - delete process.env.PYTHONPATH - - var prog = gyp() - prog.parseArgv([]) - prog.spawn = function () { - t.equal(process.env.PYTHONPATH, EXPECTED_PYPATH) - return SPAWN_RESULT - } - prog.devDir = devDir - configure(prog, [], t.fail) -}) - -test('configure PYTHONPATH with existing env of one dir', function (t) { - t.plan(2) - - var existingPath = path.join('a', 'b') - process.env.PYTHONPATH = existingPath - - var prog = gyp() - prog.parseArgv([]) - prog.spawn = function () { - t.equal(process.env.PYTHONPATH, [EXPECTED_PYPATH, existingPath].join(SEPARATOR)) - - var dirs = process.env.PYTHONPATH.split(SEPARATOR) - t.deepEqual(dirs, [EXPECTED_PYPATH, existingPath]) - - return SPAWN_RESULT - } - prog.devDir = devDir - configure(prog, [], t.fail) -}) - -test('configure PYTHONPATH with existing env of multiple dirs', function (t) { - t.plan(2) - - var pythonDir1 = path.join('a', 'b') - var pythonDir2 = path.join('b', 'c') - var existingPath = [pythonDir1, pythonDir2].join(SEPARATOR) - process.env.PYTHONPATH = existingPath - - var prog = gyp() - prog.parseArgv([]) - prog.spawn = function () { - t.equal(process.env.PYTHONPATH, [EXPECTED_PYPATH, existingPath].join(SEPARATOR)) - - var dirs = process.env.PYTHONPATH.split(SEPARATOR) - t.deepEqual(dirs, [EXPECTED_PYPATH, pythonDir1, pythonDir2]) - - return SPAWN_RESULT - } - prog.devDir = devDir - configure(prog, [], t.fail) +describe('configure-python', function () { + it('configure PYTHONPATH with no existing env', function (done) { + delete process.env.PYTHONPATH + + var prog = gyp() + prog.parseArgv([]) + prog.spawn = function () { + assert.strictEqual(process.env.PYTHONPATH, EXPECTED_PYPATH) + return SPAWN_RESULT(done) + } + prog.devDir = devDir + configure(prog, [], assert.fail) + }) + + it('configure PYTHONPATH with existing env of one dir', function (done) { + var existingPath = path.join('a', 'b') + process.env.PYTHONPATH = existingPath + + var prog = gyp() + prog.parseArgv([]) + prog.spawn = function () { + assert.strictEqual(process.env.PYTHONPATH, [EXPECTED_PYPATH, existingPath].join(SEPARATOR)) + + var dirs = process.env.PYTHONPATH.split(SEPARATOR) + assert.deepStrictEqual(dirs, [EXPECTED_PYPATH, existingPath]) + + return SPAWN_RESULT(done) + } + prog.devDir = devDir + configure(prog, [], assert.fail) + }) + + it('configure PYTHONPATH with existing env of multiple dirs', function (done) { + var pythonDir1 = path.join('a', 'b') + var pythonDir2 = path.join('b', 'c') + var existingPath = [pythonDir1, pythonDir2].join(SEPARATOR) + process.env.PYTHONPATH = existingPath + + var prog = gyp() + prog.parseArgv([]) + prog.spawn = function () { + assert.strictEqual(process.env.PYTHONPATH, [EXPECTED_PYPATH, existingPath].join(SEPARATOR)) + + var dirs = process.env.PYTHONPATH.split(SEPARATOR) + assert.deepStrictEqual(dirs, [EXPECTED_PYPATH, pythonDir1, pythonDir2]) + + return SPAWN_RESULT(done) + } + prog.devDir = devDir + configure(prog, [], assert.fail) + }) }) diff --git a/node_modules/node-gyp/test/test-create-config-gypi.js b/node_modules/node-gyp/test/test-create-config-gypi.js index eeac73fab1dcc..725819b6aa102 100644 --- a/node_modules/node-gyp/test/test-create-config-gypi.js +++ b/node_modules/node-gyp/test/test-create-config-gypi.js @@ -1,70 +1,61 @@ 'use strict' const path = require('path') -const { test } = require('tap') +const { describe, it } = require('mocha') +const assert = require('assert') const gyp = require('../lib/node-gyp') const createConfigGypi = require('../lib/create-config-gypi') const { parseConfigGypi, getCurrentConfigGypi } = createConfigGypi.test -test('config.gypi with no options', async function (t) { - t.plan(2) +describe('create-config-gypi', function () { + it('config.gypi with no options', async function () { + const prog = gyp() + prog.parseArgv([]) - const prog = gyp() - prog.parseArgv([]) + const config = await getCurrentConfigGypi({ gyp: prog, vsInfo: {} }) + assert.strictEqual(config.target_defaults.default_configuration, 'Release') + assert.strictEqual(config.variables.target_arch, process.arch) + }) - const config = await getCurrentConfigGypi({ gyp: prog, vsInfo: {} }) - t.equal(config.target_defaults.default_configuration, 'Release') - t.equal(config.variables.target_arch, process.arch) -}) - -test('config.gypi with --debug', async function (t) { - t.plan(1) - - const prog = gyp() - prog.parseArgv(['_', '_', '--debug']) + it('config.gypi with --debug', async function () { + const prog = gyp() + prog.parseArgv(['_', '_', '--debug']) - const config = await getCurrentConfigGypi({ gyp: prog, vsInfo: {} }) - t.equal(config.target_defaults.default_configuration, 'Debug') -}) + const config = await getCurrentConfigGypi({ gyp: prog, vsInfo: {} }) + assert.strictEqual(config.target_defaults.default_configuration, 'Debug') + }) -test('config.gypi with custom options', async function (t) { - t.plan(1) + it('config.gypi with custom options', async function () { + const prog = gyp() + prog.parseArgv(['_', '_', '--shared-libxml2']) - const prog = gyp() - prog.parseArgv(['_', '_', '--shared-libxml2']) + const config = await getCurrentConfigGypi({ gyp: prog, vsInfo: {} }) + assert.strictEqual(config.variables.shared_libxml2, true) + }) - const config = await getCurrentConfigGypi({ gyp: prog, vsInfo: {} }) - t.equal(config.variables.shared_libxml2, true) -}) + it('config.gypi with nodedir', async function () { + const nodeDir = path.join(__dirname, 'fixtures', 'nodedir') -test('config.gypi with nodedir', async function (t) { - t.plan(1) + const prog = gyp() + prog.parseArgv(['_', '_', `--nodedir=${nodeDir}`]) - const nodeDir = path.join(__dirname, 'fixtures', 'nodedir') + const config = await getCurrentConfigGypi({ gyp: prog, nodeDir, vsInfo: {} }) + assert.strictEqual(config.variables.build_with_electron, true) + }) - const prog = gyp() - prog.parseArgv(['_', '_', `--nodedir=${nodeDir}`]) + it('config.gypi with --force-process-config', async function () { + const nodeDir = path.join(__dirname, 'fixtures', 'nodedir') - const config = await getCurrentConfigGypi({ gyp: prog, nodeDir, vsInfo: {} }) - t.equal(config.variables.build_with_electron, true) -}) - -test('config.gypi with --force-process-config', async function (t) { - t.plan(1) - - const nodeDir = path.join(__dirname, 'fixtures', 'nodedir') - - const prog = gyp() - prog.parseArgv(['_', '_', '--force-process-config', `--nodedir=${nodeDir}`]) - - const config = await getCurrentConfigGypi({ gyp: prog, nodeDir, vsInfo: {} }) - t.equal(config.variables.build_with_electron, undefined) -}) + const prog = gyp() + prog.parseArgv(['_', '_', '--force-process-config', `--nodedir=${nodeDir}`]) -test('config.gypi parsing', function (t) { - t.plan(1) + const config = await getCurrentConfigGypi({ gyp: prog, nodeDir, vsInfo: {} }) + assert.strictEqual(config.variables.build_with_electron, undefined) + }) - const str = "# Some comments\n{'variables': {'multiline': 'A'\n'B'}}" - const config = parseConfigGypi(str) - t.deepEqual(config, { variables: { multiline: 'AB' } }) + it('config.gypi parsing', function () { + const str = "# Some comments\n{'variables': {'multiline': 'A'\n'B'}}" + const config = parseConfigGypi(str) + assert.deepStrictEqual(config, { variables: { multiline: 'AB' } }) + }) }) diff --git a/node_modules/node-gyp/test/test-download.js b/node_modules/node-gyp/test/test-download.js index c4caad9e8346d..1dd5a51b062c0 100644 --- a/node_modules/node-gyp/test/test-download.js +++ b/node_modules/node-gyp/test/test-download.js @@ -1,6 +1,7 @@ 'use strict' -const { test } = require('tap') +const { describe, it, after } = require('mocha') +const assert = require('assert') const fs = require('fs') const path = require('path') const util = require('util') @@ -16,202 +17,194 @@ const certs = require('./fixtures/certs') log.level = 'warn' -test('download over http', async (t) => { - t.plan(2) - - const server = http.createServer((req, res) => { - t.strictEqual(req.headers['user-agent'], `node-gyp v42 (node ${process.version})`) - res.end('ok') - }) - - t.tearDown(() => new Promise((resolve) => server.close(resolve))) - - const host = 'localhost' - await new Promise((resolve) => server.listen(0, host, resolve)) - const { port } = server.address() - const gyp = { - opts: {}, - version: '42' - } - const url = `http://${host}:${port}` - const res = await install.test.download(gyp, url) - t.strictEqual(await res.text(), 'ok') -}) - -test('download over https with custom ca', async (t) => { - t.plan(3) - - const cafile = path.join(__dirname, 'fixtures/ca.crt') - const cacontents = certs['ca.crt'] - const cert = certs['server.crt'] - const key = certs['server.key'] - await fs.promises.writeFile(cafile, cacontents, 'utf8') - const ca = await install.test.readCAFile(cafile) - - t.strictEqual(ca.length, 1) - - const options = { ca: ca, cert: cert, key: key } - const server = https.createServer(options, (req, res) => { - t.strictEqual(req.headers['user-agent'], `node-gyp v42 (node ${process.version})`) - res.end('ok') +describe('download', function () { + it('download over http', async function () { + const server = http.createServer((req, res) => { + assert.strictEqual(req.headers['user-agent'], `node-gyp v42 (node ${process.version})`) + res.end('ok') + }) + + after(() => new Promise((resolve) => server.close(resolve))) + + const host = 'localhost' + await new Promise((resolve) => server.listen(0, host, resolve)) + const { port } = server.address() + const gyp = { + opts: {}, + version: '42' + } + const url = `http://${host}:${port}` + const res = await install.test.download(gyp, url) + assert.strictEqual(await res.text(), 'ok') }) - t.tearDown(async () => { - await new Promise((resolve) => server.close(resolve)) - await fs.promises.unlink(cafile) + it('download over https with custom ca', async function () { + const cafile = path.join(__dirname, 'fixtures/ca.crt') + const cacontents = certs['ca.crt'] + const cert = certs['server.crt'] + const key = certs['server.key'] + await fs.promises.writeFile(cafile, cacontents, 'utf8') + const ca = await install.test.readCAFile(cafile) + + assert.strictEqual(ca.length, 1) + + const options = { ca: ca, cert: cert, key: key } + const server = https.createServer(options, (req, res) => { + assert.strictEqual(req.headers['user-agent'], `node-gyp v42 (node ${process.version})`) + res.end('ok') + }) + + after(async () => { + await new Promise((resolve) => server.close(resolve)) + await fs.promises.unlink(cafile) + }) + + server.on('clientError', (err) => { throw err }) + + const host = 'localhost' + await new Promise((resolve) => server.listen(0, host, resolve)) + const { port } = server.address() + const gyp = { + opts: { cafile }, + version: '42' + } + const url = `https://${host}:${port}` + const res = await install.test.download(gyp, url) + assert.strictEqual(await res.text(), 'ok') }) - server.on('clientError', (err) => { throw err }) - - const host = 'localhost' - await new Promise((resolve) => server.listen(0, host, resolve)) - const { port } = server.address() - const gyp = { - opts: { cafile }, - version: '42' - } - const url = `https://${host}:${port}` - const res = await install.test.download(gyp, url) - t.strictEqual(await res.text(), 'ok') -}) - -test('download over http with proxy', async (t) => { - t.plan(2) - - const server = http.createServer((_, res) => { - res.end('ok') + it('download over http with proxy', async function () { + const server = http.createServer((_, res) => { + res.end('ok') + }) + + const pserver = http.createServer((req, res) => { + assert.strictEqual(req.headers['user-agent'], `node-gyp v42 (node ${process.version})`) + res.end('proxy ok') + }) + + after(() => Promise.all([ + new Promise((resolve) => server.close(resolve)), + new Promise((resolve) => pserver.close(resolve)) + ])) + + const host = 'localhost' + await new Promise((resolve) => server.listen(0, host, resolve)) + const { port } = server.address() + await new Promise((resolve) => pserver.listen(port + 1, host, resolve)) + const gyp = { + opts: { + proxy: `http://${host}:${port + 1}`, + noproxy: 'bad' + }, + version: '42' + } + const url = `http://${host}:${port}` + const res = await install.test.download(gyp, url) + assert.strictEqual(await res.text(), 'proxy ok') }) - const pserver = http.createServer((req, res) => { - t.strictEqual(req.headers['user-agent'], `node-gyp v42 (node ${process.version})`) - res.end('proxy ok') + it('download over http with noproxy', async function () { + const server = http.createServer((req, res) => { + assert.strictEqual(req.headers['user-agent'], `node-gyp v42 (node ${process.version})`) + res.end('ok') + }) + + const pserver = http.createServer((_, res) => { + res.end('proxy ok') + }) + + after(() => Promise.all([ + new Promise((resolve) => server.close(resolve)), + new Promise((resolve) => pserver.close(resolve)) + ])) + + const host = 'localhost' + await new Promise((resolve) => server.listen(0, host, resolve)) + const { port } = server.address() + await new Promise((resolve) => pserver.listen(port + 1, host, resolve)) + const gyp = { + opts: { + proxy: `http://${host}:${port + 1}`, + noproxy: host + }, + version: '42' + } + const url = `http://${host}:${port}` + const res = await install.test.download(gyp, url) + assert.strictEqual(await res.text(), 'ok') }) - t.tearDown(() => Promise.all([ - new Promise((resolve) => server.close(resolve)), - new Promise((resolve) => pserver.close(resolve)) - ])) - - const host = 'localhost' - await new Promise((resolve) => server.listen(0, host, resolve)) - const { port } = server.address() - await new Promise((resolve) => pserver.listen(port + 1, host, resolve)) - const gyp = { - opts: { - proxy: `http://${host}:${port + 1}`, - noproxy: 'bad' - }, - version: '42' - } - const url = `http://${host}:${port}` - const res = await install.test.download(gyp, url) - t.strictEqual(await res.text(), 'proxy ok') -}) - -test('download over http with noproxy', async (t) => { - t.plan(2) - - const server = http.createServer((req, res) => { - t.strictEqual(req.headers['user-agent'], `node-gyp v42 (node ${process.version})`) - res.end('ok') + it('download with missing cafile', async function () { + const gyp = { + opts: { cafile: 'no.such.file' } + } + try { + await install.test.download(gyp, {}, 'http://bad/') + } catch (e) { + assert.ok(/no.such.file/.test(e.message)) + } }) - const pserver = http.createServer((_, res) => { - res.end('proxy ok') + it('check certificate splitting', async function () { + const cafile = path.join(__dirname, 'fixtures/ca-bundle.crt') + const cacontents = certs['ca-bundle.crt'] + await fs.promises.writeFile(cafile, cacontents, 'utf8') + after(async () => { + await fs.promises.unlink(cafile) + }) + const cas = await install.test.readCAFile(path.join(__dirname, 'fixtures/ca-bundle.crt')) + assert.strictEqual(cas.length, 2) + assert.notStrictEqual(cas[0], cas[1]) }) - t.tearDown(() => Promise.all([ - new Promise((resolve) => server.close(resolve)), - new Promise((resolve) => pserver.close(resolve)) - ])) - - const host = 'localhost' - await new Promise((resolve) => server.listen(0, host, resolve)) - const { port } = server.address() - await new Promise((resolve) => pserver.listen(port + 1, host, resolve)) - const gyp = { - opts: { - proxy: `http://${host}:${port + 1}`, - noproxy: host - }, - version: '42' - } - const url = `http://${host}:${port}` - const res = await install.test.download(gyp, url) - t.strictEqual(await res.text(), 'ok') -}) - -test('download with missing cafile', async (t) => { - t.plan(1) - const gyp = { - opts: { cafile: 'no.such.file' } - } - try { - await install.test.download(gyp, {}, 'http://bad/') - } catch (e) { - t.ok(/no.such.file/.test(e.message)) - } -}) - -test('check certificate splitting', async (t) => { - const cafile = path.join(__dirname, 'fixtures/ca-bundle.crt') - const cacontents = certs['ca-bundle.crt'] - await fs.promises.writeFile(cafile, cacontents, 'utf8') - t.tearDown(async () => { - await fs.promises.unlink(cafile) + // only run this test if we are running a version of Node with predictable version path behavior + + it('download headers (actual)', async function () { + if (process.env.FAST_TEST || + process.release.name !== 'node' || + semver.prerelease(process.version) !== null || + semver.satisfies(process.version, '<10')) { + return this.skip('Skipping actual download of headers due to test environment configuration') + } + + this.timeout(300000) + + const expectedDir = path.join(devDir, process.version.replace(/^v/, '')) + await util.promisify(rimraf)(expectedDir) + + const prog = gyp() + prog.parseArgv([]) + prog.devDir = devDir + log.level = 'warn' + await util.promisify(install)(prog, []) + + const data = await fs.promises.readFile(path.join(expectedDir, 'installVersion'), 'utf8') + assert.strictEqual(data, '11\n', 'correct installVersion') + + const list = await fs.promises.readdir(path.join(expectedDir, 'include/node')) + assert.ok(list.includes('common.gypi')) + assert.ok(list.includes('config.gypi')) + assert.ok(list.includes('node.h')) + assert.ok(list.includes('node_version.h')) + assert.ok(list.includes('openssl')) + assert.ok(list.includes('uv')) + assert.ok(list.includes('uv.h')) + assert.ok(list.includes('v8-platform.h')) + assert.ok(list.includes('v8.h')) + assert.ok(list.includes('zlib.h')) + + const lines = (await fs.promises.readFile(path.join(expectedDir, 'include/node/node_version.h'), 'utf8')).split('\n') + + // extract the 3 version parts from the defines to build a valid version string and + // and check them against our current env version + const version = ['major', 'minor', 'patch'].reduce((version, type) => { + const re = new RegExp(`^#define\\sNODE_${type.toUpperCase()}_VERSION`) + const line = lines.find((l) => re.test(l)) + const i = line ? parseInt(line.replace(/^[^0-9]+([0-9]+).*$/, '$1'), 10) : 'ERROR' + return `${version}${type !== 'major' ? '.' : 'v'}${i}` + }, '') + + assert.strictEqual(version, process.version) }) - const cas = await install.test.readCAFile(path.join(__dirname, 'fixtures/ca-bundle.crt')) - t.plan(2) - t.strictEqual(cas.length, 2) - t.notStrictEqual(cas[0], cas[1]) -}) - -// only run this test if we are running a version of Node with predictable version path behavior - -test('download headers (actual)', async (t) => { - if (process.env.FAST_TEST || - process.release.name !== 'node' || - semver.prerelease(process.version) !== null || - semver.satisfies(process.version, '<10')) { - return t.skip('Skipping actual download of headers due to test environment configuration') - } - - t.plan(12) - - const expectedDir = path.join(devDir, process.version.replace(/^v/, '')) - await util.promisify(rimraf)(expectedDir) - - const prog = gyp() - prog.parseArgv([]) - prog.devDir = devDir - log.level = 'warn' - await util.promisify(install)(prog, []) - - const data = await fs.promises.readFile(path.join(expectedDir, 'installVersion'), 'utf8') - t.strictEqual(data, '9\n', 'correct installVersion') - - const list = await fs.promises.readdir(path.join(expectedDir, 'include/node')) - t.ok(list.includes('common.gypi')) - t.ok(list.includes('config.gypi')) - t.ok(list.includes('node.h')) - t.ok(list.includes('node_version.h')) - t.ok(list.includes('openssl')) - t.ok(list.includes('uv')) - t.ok(list.includes('uv.h')) - t.ok(list.includes('v8-platform.h')) - t.ok(list.includes('v8.h')) - t.ok(list.includes('zlib.h')) - - const lines = (await fs.promises.readFile(path.join(expectedDir, 'include/node/node_version.h'), 'utf8')).split('\n') - - // extract the 3 version parts from the defines to build a valid version string and - // and check them against our current env version - const version = ['major', 'minor', 'patch'].reduce((version, type) => { - const re = new RegExp(`^#define\\sNODE_${type.toUpperCase()}_VERSION`) - const line = lines.find((l) => re.test(l)) - const i = line ? parseInt(line.replace(/^[^0-9]+([0-9]+).*$/, '$1'), 10) : 'ERROR' - return `${version}${type !== 'major' ? '.' : 'v'}${i}` - }, '') - - t.strictEqual(version, process.version) }) diff --git a/node_modules/node-gyp/test/test-find-accessible-sync.js b/node_modules/node-gyp/test/test-find-accessible-sync.js index 0a2e584c4fb33..7edbc0c76446e 100644 --- a/node_modules/node-gyp/test/test-find-accessible-sync.js +++ b/node_modules/node-gyp/test/test-find-accessible-sync.js @@ -1,6 +1,7 @@ 'use strict' -const test = require('tap').test +const { describe, it } = require('mocha') +const assert = require('assert') const path = require('path') const requireInject = require('require-inject') const configure = requireInject('../lib/configure', { @@ -27,58 +28,46 @@ const readableFiles = [ path.resolve(dir, readableFileInDir) ] -test('find accessible - empty array', function (t) { - t.plan(1) - - var candidates = [] - var found = configure.test.findAccessibleSync('test', dir, candidates) - t.strictEqual(found, undefined) -}) - -test('find accessible - single item array, readable', function (t) { - t.plan(1) - - var candidates = [readableFile] - var found = configure.test.findAccessibleSync('test', dir, candidates) - t.strictEqual(found, path.resolve(dir, readableFile)) -}) - -test('find accessible - single item array, readable in subdir', function (t) { - t.plan(1) - - var candidates = [readableFileInDir] - var found = configure.test.findAccessibleSync('test', dir, candidates) - t.strictEqual(found, path.resolve(dir, readableFileInDir)) -}) - -test('find accessible - single item array, unreadable', function (t) { - t.plan(1) - - var candidates = ['unreadable_file'] - var found = configure.test.findAccessibleSync('test', dir, candidates) - t.strictEqual(found, undefined) -}) - -test('find accessible - multi item array, no matches', function (t) { - t.plan(1) - - var candidates = ['non_existent_file', 'unreadable_file'] - var found = configure.test.findAccessibleSync('test', dir, candidates) - t.strictEqual(found, undefined) -}) - -test('find accessible - multi item array, single match', function (t) { - t.plan(1) - - var candidates = ['non_existent_file', readableFile] - var found = configure.test.findAccessibleSync('test', dir, candidates) - t.strictEqual(found, path.resolve(dir, readableFile)) -}) - -test('find accessible - multi item array, return first match', function (t) { - t.plan(1) - - var candidates = ['non_existent_file', anotherReadableFile, readableFile] - var found = configure.test.findAccessibleSync('test', dir, candidates) - t.strictEqual(found, path.resolve(dir, anotherReadableFile)) +describe('find-accessible-sync', function () { + it('find accessible - empty array', function () { + var candidates = [] + var found = configure.test.findAccessibleSync('test', dir, candidates) + assert.strictEqual(found, undefined) + }) + + it('find accessible - single item array, readable', function () { + var candidates = [readableFile] + var found = configure.test.findAccessibleSync('test', dir, candidates) + assert.strictEqual(found, path.resolve(dir, readableFile)) + }) + + it('find accessible - single item array, readable in subdir', function () { + var candidates = [readableFileInDir] + var found = configure.test.findAccessibleSync('test', dir, candidates) + assert.strictEqual(found, path.resolve(dir, readableFileInDir)) + }) + + it('find accessible - single item array, unreadable', function () { + var candidates = ['unreadable_file'] + var found = configure.test.findAccessibleSync('test', dir, candidates) + assert.strictEqual(found, undefined) + }) + + it('find accessible - multi item array, no matches', function () { + var candidates = ['non_existent_file', 'unreadable_file'] + var found = configure.test.findAccessibleSync('test', dir, candidates) + assert.strictEqual(found, undefined) + }) + + it('find accessible - multi item array, single match', function () { + var candidates = ['non_existent_file', readableFile] + var found = configure.test.findAccessibleSync('test', dir, candidates) + assert.strictEqual(found, path.resolve(dir, readableFile)) + }) + + it('find accessible - multi item array, return first match', function () { + var candidates = ['non_existent_file', anotherReadableFile, readableFile] + var found = configure.test.findAccessibleSync('test', dir, candidates) + assert.strictEqual(found, path.resolve(dir, anotherReadableFile)) + }) }) diff --git a/node_modules/node-gyp/test/test-find-node-directory.js b/node_modules/node-gyp/test/test-find-node-directory.js index fa6223c65d03c..ca299f6330646 100644 --- a/node_modules/node-gyp/test/test-find-node-directory.js +++ b/node_modules/node-gyp/test/test-find-node-directory.js @@ -1,119 +1,115 @@ 'use strict' -const test = require('tap').test +const { describe, it } = require('mocha') +const assert = require('assert') const path = require('path') const findNodeDirectory = require('../lib/find-node-directory') const platforms = ['darwin', 'freebsd', 'linux', 'sunos', 'win32', 'aix', 'os400'] -// we should find the directory based on the directory -// the script is running in and it should match the layout -// in a build tree where npm is installed in -// .... /deps/npm -test('test find-node-directory - node install', function (t) { - t.plan(platforms.length) - for (var next = 0; next < platforms.length; next++) { - var processObj = { execPath: '/x/y/bin/node', platform: platforms[next] } - t.equal( - findNodeDirectory('/x/deps/npm/node_modules/node-gyp/lib', processObj), - path.join('/x')) - } -}) +describe('find-node-directory', function () { + // we should find the directory based on the directory + // the script is running in and it should match the layout + // in a build tree where npm is installed in + // .... /deps/npm + it('test find-node-directory - node install', function () { + for (var next = 0; next < platforms.length; next++) { + var processObj = { execPath: '/x/y/bin/node', platform: platforms[next] } + assert.strictEqual( + findNodeDirectory('/x/deps/npm/node_modules/node-gyp/lib', processObj), + path.join('/x')) + } + }) -// we should find the directory based on the directory -// the script is running in and it should match the layout -// in an installed tree where npm is installed in -// .... /lib/node_modules/npm or .../node_modules/npm -// depending on the patform -test('test find-node-directory - node build', function (t) { - t.plan(platforms.length) - for (var next = 0; next < platforms.length; next++) { - var processObj = { execPath: '/x/y/bin/node', platform: platforms[next] } - if (platforms[next] === 'win32') { - t.equal( - findNodeDirectory('/y/node_modules/npm/node_modules/node-gyp/lib', - processObj), path.join('/y')) - } else { - t.equal( - findNodeDirectory('/y/lib/node_modules/npm/node_modules/node-gyp/lib', - processObj), path.join('/y')) + // we should find the directory based on the directory + // the script is running in and it should match the layout + // in an installed tree where npm is installed in + // .... /lib/node_modules/npm or .../node_modules/npm + // depending on the patform + it('test find-node-directory - node build', function () { + for (var next = 0; next < platforms.length; next++) { + var processObj = { execPath: '/x/y/bin/node', platform: platforms[next] } + if (platforms[next] === 'win32') { + assert.strictEqual( + findNodeDirectory('/y/node_modules/npm/node_modules/node-gyp/lib', + processObj), path.join('/y')) + } else { + assert.strictEqual( + findNodeDirectory('/y/lib/node_modules/npm/node_modules/node-gyp/lib', + processObj), path.join('/y')) + } } - } -}) + }) -// we should find the directory based on the execPath -// for node and match because it was in the bin directory -test('test find-node-directory - node in bin directory', function (t) { - t.plan(platforms.length) - for (var next = 0; next < platforms.length; next++) { - var processObj = { execPath: '/x/y/bin/node', platform: platforms[next] } - t.equal( - findNodeDirectory('/nothere/npm/node_modules/node-gyp/lib', processObj), - path.join('/x/y')) - } -}) + // we should find the directory based on the execPath + // for node and match because it was in the bin directory + it('test find-node-directory - node in bin directory', function () { + for (var next = 0; next < platforms.length; next++) { + var processObj = { execPath: '/x/y/bin/node', platform: platforms[next] } + assert.strictEqual( + findNodeDirectory('/nothere/npm/node_modules/node-gyp/lib', processObj), + path.join('/x/y')) + } + }) -// we should find the directory based on the execPath -// for node and match because it was in the Release directory -test('test find-node-directory - node in build release dir', function (t) { - t.plan(platforms.length) - for (var next = 0; next < platforms.length; next++) { - var processObj - if (platforms[next] === 'win32') { - processObj = { execPath: '/x/y/Release/node', platform: platforms[next] } - } else { - processObj = { - execPath: '/x/y/out/Release/node', - platform: platforms[next] + // we should find the directory based on the execPath + // for node and match because it was in the Release directory + it('test find-node-directory - node in build release dir', function () { + for (var next = 0; next < platforms.length; next++) { + var processObj + if (platforms[next] === 'win32') { + processObj = { execPath: '/x/y/Release/node', platform: platforms[next] } + } else { + processObj = { + execPath: '/x/y/out/Release/node', + platform: platforms[next] + } } + + assert.strictEqual( + findNodeDirectory('/nothere/npm/node_modules/node-gyp/lib', processObj), + path.join('/x/y')) } + }) - t.equal( - findNodeDirectory('/nothere/npm/node_modules/node-gyp/lib', processObj), - path.join('/x/y')) - } -}) + // we should find the directory based on the execPath + // for node and match because it was in the Debug directory + it('test find-node-directory - node in Debug release dir', function () { + for (var next = 0; next < platforms.length; next++) { + var processObj + if (platforms[next] === 'win32') { + processObj = { execPath: '/a/b/Debug/node', platform: platforms[next] } + } else { + processObj = { execPath: '/a/b/out/Debug/node', platform: platforms[next] } + } -// we should find the directory based on the execPath -// for node and match because it was in the Debug directory -test('test find-node-directory - node in Debug release dir', function (t) { - t.plan(platforms.length) - for (var next = 0; next < platforms.length; next++) { - var processObj - if (platforms[next] === 'win32') { - processObj = { execPath: '/a/b/Debug/node', platform: platforms[next] } - } else { - processObj = { execPath: '/a/b/out/Debug/node', platform: platforms[next] } + assert.strictEqual( + findNodeDirectory('/nothere/npm/node_modules/node-gyp/lib', processObj), + path.join('/a/b')) } + }) - t.equal( - findNodeDirectory('/nothere/npm/node_modules/node-gyp/lib', processObj), - path.join('/a/b')) - } -}) - -// we should not find it as it will not match based on the execPath nor -// the directory from which the script is running -test('test find-node-directory - not found', function (t) { - t.plan(platforms.length) - for (var next = 0; next < platforms.length; next++) { - var processObj = { execPath: '/x/y/z/y', platform: next } - t.equal(findNodeDirectory('/a/b/c/d', processObj), '') - } -}) + // we should not find it as it will not match based on the execPath nor + // the directory from which the script is running + it('test find-node-directory - not found', function () { + for (var next = 0; next < platforms.length; next++) { + var processObj = { execPath: '/x/y/z/y', platform: next } + assert.strictEqual(findNodeDirectory('/a/b/c/d', processObj), '') + } + }) -// we should find the directory based on the directory -// the script is running in and it should match the layout -// in a build tree where npm is installed in -// .... /deps/npm -// same test as above but make sure additional directory entries -// don't cause an issue -test('test find-node-directory - node install', function (t) { - t.plan(platforms.length) - for (var next = 0; next < platforms.length; next++) { - var processObj = { execPath: '/x/y/bin/node', platform: platforms[next] } - t.equal( - findNodeDirectory('/x/y/z/a/b/c/deps/npm/node_modules/node-gyp/lib', - processObj), path.join('/x/y/z/a/b/c')) - } + // we should find the directory based on the directory + // the script is running in and it should match the layout + // in a build tree where npm is installed in + // .... /deps/npm + // same test as above but make sure additional directory entries + // don't cause an issue + it('test find-node-directory - node install', function () { + for (var next = 0; next < platforms.length; next++) { + var processObj = { execPath: '/x/y/bin/node', platform: platforms[next] } + assert.strictEqual( + findNodeDirectory('/x/y/z/a/b/c/deps/npm/node_modules/node-gyp/lib', + processObj), path.join('/x/y/z/a/b/c')) + } + }) }) diff --git a/node_modules/node-gyp/test/test-find-python.js b/node_modules/node-gyp/test/test-find-python.js index 67d0b2664f0b1..592c480f24fef 100644 --- a/node_modules/node-gyp/test/test-find-python.js +++ b/node_modules/node-gyp/test/test-find-python.js @@ -2,225 +2,212 @@ delete process.env.PYTHON -const test = require('tap').test +const { describe, it } = require('mocha') +const assert = require('assert') const findPython = require('../lib/find-python') const execFile = require('child_process').execFile const PythonFinder = findPython.test.PythonFinder require('npmlog').level = 'warn' -test('find python', function (t) { - t.plan(4) - - findPython.test.findPython(null, function (err, found) { - t.strictEqual(err, null) - var proc = execFile(found, ['-V'], function (err, stdout, stderr) { - t.strictEqual(err, null) - t.ok(/Python 3/.test(stdout)) - t.strictEqual(stderr, '') +describe('find-python', function () { + it('find python', function () { + findPython.test.findPython(null, function (err, found) { + assert.strictEqual(err, null) + var proc = execFile(found, ['-V'], function (err, stdout, stderr) { + assert.strictEqual(err, null) + assert.ok(/Python 3/.test(stdout)) + assert.strictEqual(stderr, '') + }) + proc.stdout.setEncoding('utf-8') + proc.stderr.setEncoding('utf-8') }) - proc.stdout.setEncoding('utf-8') - proc.stderr.setEncoding('utf-8') }) -}) -function poison (object, property) { - function fail () { - console.error(Error(`Property ${property} should not have been accessed.`)) - process.abort() - } - var descriptor = { - configurable: false, - enumerable: false, - get: fail, - set: fail - } - Object.defineProperty(object, property, descriptor) -} - -function TestPythonFinder () { - PythonFinder.apply(this, arguments) -} -TestPythonFinder.prototype = Object.create(PythonFinder.prototype) -// Silence npmlog - remove for debugging -TestPythonFinder.prototype.log = { - silly: () => {}, - verbose: () => {}, - info: () => {}, - warn: () => {}, - error: () => {} -} -delete TestPythonFinder.prototype.env.NODE_GYP_FORCE_PYTHON - -test('find python - python', function (t) { - t.plan(6) - - var f = new TestPythonFinder('python', done) - f.execFile = function (program, args, opts, cb) { - f.execFile = function (program, args, opts, cb) { - poison(f, 'execFile') - t.strictEqual(program, '/path/python') - t.ok(/sys\.version_info/.test(args[1])) - cb(null, '3.9.1') - } - t.strictEqual(program, - process.platform === 'win32' ? '"python"' : 'python') - t.ok(/sys\.executable/.test(args[1])) - cb(null, '/path/python') + function poison (object, property) { + function fail () { + console.error(Error(`Property ${property} should not have been accessed.`)) + process.abort() + } + var descriptor = { + configurable: false, + enumerable: false, + get: fail, + set: fail + } + Object.defineProperty(object, property, descriptor) } - f.findPython() - function done (err, python) { - t.strictEqual(err, null) - t.strictEqual(python, '/path/python') + function TestPythonFinder () { + PythonFinder.apply(this, arguments) } -}) - -test('find python - python too old', function (t) { - t.plan(2) + TestPythonFinder.prototype = Object.create(PythonFinder.prototype) + // Silence npmlog - remove for debugging + TestPythonFinder.prototype.log = { + silly: () => {}, + verbose: () => {}, + info: () => {}, + warn: () => {}, + error: () => {} + } + delete TestPythonFinder.prototype.env.NODE_GYP_FORCE_PYTHON - var f = new TestPythonFinder(null, done) - f.execFile = function (program, args, opts, cb) { - if (/sys\.executable/.test(args[args.length - 1])) { + it('find python - python', function () { + var f = new TestPythonFinder('python', done) + f.execFile = function (program, args, opts, cb) { + f.execFile = function (program, args, opts, cb) { + poison(f, 'execFile') + assert.strictEqual(program, '/path/python') + assert.ok(/sys\.version_info/.test(args[1])) + cb(null, '3.9.1') + } + assert.strictEqual(program, + process.platform === 'win32' ? '"python"' : 'python') + assert.ok(/sys\.executable/.test(args[1])) cb(null, '/path/python') - } else if (/sys\.version_info/.test(args[args.length - 1])) { - cb(null, '2.3.4') - } else { - t.fail() } - } - f.findPython() - - function done (err) { - t.ok(/Could not find any Python/.test(err)) - t.ok(/not supported/i.test(f.errorLog)) - } -}) - -test('find python - no python', function (t) { - t.plan(2) + f.findPython() - var f = new TestPythonFinder(null, done) - f.execFile = function (program, args, opts, cb) { - if (/sys\.executable/.test(args[args.length - 1])) { - cb(new Error('not found')) - } else if (/sys\.version_info/.test(args[args.length - 1])) { - cb(new Error('not a Python executable')) - } else { - t.fail() + function done (err, python) { + assert.strictEqual(err, null) + assert.strictEqual(python, '/path/python') } - } - f.findPython() + }) - function done (err) { - t.ok(/Could not find any Python/.test(err)) - t.ok(/not in PATH/.test(f.errorLog)) - } -}) + it('find python - python too old', function () { + var f = new TestPythonFinder(null, done) + f.execFile = function (program, args, opts, cb) { + if (/sys\.executable/.test(args[args.length - 1])) { + cb(null, '/path/python') + } else if (/sys\.version_info/.test(args[args.length - 1])) { + cb(null, '2.3.4') + } else { + assert.fail() + } + } + f.findPython() -test('find python - no python2, no python, unix', function (t) { - t.plan(2) + function done (err) { + assert.ok(/Could not find any Python/.test(err)) + assert.ok(/not supported/i.test(f.errorLog)) + } + }) - var f = new TestPythonFinder(null, done) - f.checkPyLauncher = t.fail - f.win = false + it('find python - no python', function () { + var f = new TestPythonFinder(null, done) + f.execFile = function (program, args, opts, cb) { + if (/sys\.executable/.test(args[args.length - 1])) { + cb(new Error('not found')) + } else if (/sys\.version_info/.test(args[args.length - 1])) { + cb(new Error('not a Python executable')) + } else { + assert.fail() + } + } + f.findPython() - f.execFile = function (program, args, opts, cb) { - if (/sys\.executable/.test(args[args.length - 1])) { - cb(new Error('not found')) - } else { - t.fail() + function done (err) { + assert.ok(/Could not find any Python/.test(err)) + assert.ok(/not in PATH/.test(f.errorLog)) } - } - f.findPython() + }) - function done (err) { - t.ok(/Could not find any Python/.test(err)) - t.ok(/not in PATH/.test(f.errorLog)) - } -}) + it('find python - no python2, no python, unix', function () { + var f = new TestPythonFinder(null, done) + f.checkPyLauncher = assert.fail + f.win = false -test('find python - no python, use python launcher', function (t) { - t.plan(4) - - var f = new TestPythonFinder(null, done) - f.win = true - - f.execFile = function (program, args, opts, cb) { - if (program === 'py.exe') { - t.notEqual(args.indexOf('-3'), -1) - t.notEqual(args.indexOf('-c'), -1) - return cb(null, 'Z:\\snake.exe') - } - if (/sys\.executable/.test(args[args.length - 1])) { - cb(new Error('not found')) - } else if (f.winDefaultLocations.includes(program)) { - cb(new Error('not found')) - } else if (/sys\.version_info/.test(args[args.length - 1])) { - if (program === 'Z:\\snake.exe') { - cb(null, '3.9.0') + f.execFile = function (program, args, opts, cb) { + if (/sys\.executable/.test(args[args.length - 1])) { + cb(new Error('not found')) } else { - t.fail() + assert.fail() } - } else { - t.fail() } - } - f.findPython() + f.findPython() - function done (err, python) { - t.strictEqual(err, null) - t.strictEqual(python, 'Z:\\snake.exe') - } -}) - -test('find python - no python, no python launcher, good guess', function (t) { - t.plan(2) + function done (err) { + assert.ok(/Could not find any Python/.test(err)) + assert.ok(/not in PATH/.test(f.errorLog)) + } + }) - var f = new TestPythonFinder(null, done) - f.win = true - const expectedProgram = f.winDefaultLocations[0] + it('find python - no python, use python launcher', function () { + var f = new TestPythonFinder(null, done) + f.win = true - f.execFile = function (program, args, opts, cb) { - if (program === 'py.exe') { - return cb(new Error('not found')) + f.execFile = function (program, args, opts, cb) { + if (program === 'py.exe') { + assert.notStrictEqual(args.indexOf('-3'), -1) + assert.notStrictEqual(args.indexOf('-c'), -1) + return cb(null, 'Z:\\snake.exe') + } + if (/sys\.executable/.test(args[args.length - 1])) { + cb(new Error('not found')) + } else if (f.winDefaultLocations.includes(program)) { + cb(new Error('not found')) + } else if (/sys\.version_info/.test(args[args.length - 1])) { + if (program === 'Z:\\snake.exe') { + cb(null, '3.9.0') + } else { + assert.fail() + } + } else { + assert.fail() + } } - if (/sys\.executable/.test(args[args.length - 1])) { - cb(new Error('not found')) - } else if (program === expectedProgram && - /sys\.version_info/.test(args[args.length - 1])) { - cb(null, '3.7.3') - } else { - t.fail() + f.findPython() + + function done (err, python) { + assert.strictEqual(err, null) + assert.strictEqual(python, 'Z:\\snake.exe') } - } - f.findPython() + }) - function done (err, python) { - t.strictEqual(err, null) - t.ok(python === expectedProgram) - } -}) + it('find python - no python, no python launcher, good guess', function () { + var f = new TestPythonFinder(null, done) + f.win = true + const expectedProgram = f.winDefaultLocations[0] + + f.execFile = function (program, args, opts, cb) { + if (program === 'py.exe') { + return cb(new Error('not found')) + } + if (/sys\.executable/.test(args[args.length - 1])) { + cb(new Error('not found')) + } else if (program === expectedProgram && + /sys\.version_info/.test(args[args.length - 1])) { + cb(null, '3.7.3') + } else { + assert.fail() + } + } + f.findPython() -test('find python - no python, no python launcher, bad guess', function (t) { - t.plan(2) + function done (err, python) { + assert.strictEqual(err, null) + assert.ok(python === expectedProgram) + } + }) - var f = new TestPythonFinder(null, done) - f.win = true + it('find python - no python, no python launcher, bad guess', function () { + var f = new TestPythonFinder(null, done) + f.win = true - f.execFile = function (program, args, opts, cb) { - if (/sys\.executable/.test(args[args.length - 1])) { - cb(new Error('not found')) - } else if (/sys\.version_info/.test(args[args.length - 1])) { - cb(new Error('not a Python executable')) - } else { - t.fail() + f.execFile = function (program, args, opts, cb) { + if (/sys\.executable/.test(args[args.length - 1])) { + cb(new Error('not found')) + } else if (/sys\.version_info/.test(args[args.length - 1])) { + cb(new Error('not a Python executable')) + } else { + assert.fail() + } } - } - f.findPython() + f.findPython() - function done (err) { - t.ok(/Could not find any Python/.test(err)) - t.ok(/not in PATH/.test(f.errorLog)) - } + function done (err) { + assert.ok(/Could not find any Python/.test(err)) + assert.ok(/not in PATH/.test(f.errorLog)) + } + }) }) diff --git a/node_modules/node-gyp/test/test-find-visualstudio.js b/node_modules/node-gyp/test/test-find-visualstudio.js index 1327cf8841111..29d9a7dba5f55 100644 --- a/node_modules/node-gyp/test/test-find-visualstudio.js +++ b/node_modules/node-gyp/test/test-find-visualstudio.js @@ -1,6 +1,7 @@ 'use strict' -const test = require('tap').test +const { describe, it } = require('mocha') +const assert = require('assert') const fs = require('fs') const path = require('path') const findVisualStudio = require('../lib/find-visualstudio') @@ -35,642 +36,635 @@ TestVisualStudioFinder.prototype.log = { error: () => {} } -test('VS2013', function (t) { - t.plan(4) - - const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info, { - msBuild: 'C:\\MSBuild12\\MSBuild.exe', - path: 'C:\\VS2013', - sdk: null, - toolset: 'v120', - version: '12.0', - versionMajor: 12, - versionMinor: 0, - versionYear: 2013 +describe('find-visualstudio', function () { + it('VS2013', function () { + const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info, { + msBuild: 'C:\\MSBuild12\\MSBuild.exe', + path: 'C:\\VS2013', + sdk: null, + toolset: 'v120', + version: '12.0', + versionMajor: 12, + versionMinor: 0, + versionYear: 2013 + }) }) - }) - finder.findVisualStudio2017OrNewer = (cb) => { - finder.parseData(new Error(), '', '', cb) - } - finder.regSearchKeys = (keys, value, addOpts, cb) => { - for (var i = 0; i < keys.length; ++i) { - const fullName = `${keys[i]}\\${value}` - switch (fullName) { - case 'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0': - case 'HKLM\\Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0': - continue - case 'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7\\12.0': - t.pass(`expected search for registry value ${fullName}`) - return cb(null, 'C:\\VS2013\\VC\\') - case 'HKLM\\Software\\Microsoft\\MSBuild\\ToolsVersions\\12.0\\MSBuildToolsPath': - t.pass(`expected search for registry value ${fullName}`) - return cb(null, 'C:\\MSBuild12\\') - default: - t.fail(`unexpected search for registry value ${fullName}`) - } + finder.findVisualStudio2017OrNewer = (cb) => { + finder.parseData(new Error(), '', '', cb) } - return cb(new Error()) - } - finder.findVisualStudio() -}) - -test('VS2013 should not be found on new node versions', function (t) { - t.plan(2) - - const finder = new TestVisualStudioFinder({ - major: 10, - minor: 0, - patch: 0 - }, null, (err, info) => { - t.ok(/find .* Visual Studio/i.test(err), 'expect error') - t.false(info, 'no data') - }) - - finder.findVisualStudio2017OrNewer = (cb) => { - const file = path.join(__dirname, 'fixtures', 'VS_2017_Unusable.txt') - const data = fs.readFileSync(file) - finder.parseData(null, data, '', cb) - } - finder.regSearchKeys = (keys, value, addOpts, cb) => { - for (var i = 0; i < keys.length; ++i) { - const fullName = `${keys[i]}\\${value}` - switch (fullName) { - case 'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0': - case 'HKLM\\Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0': - continue - default: - t.fail(`unexpected search for registry value ${fullName}`) + finder.regSearchKeys = (keys, value, addOpts, cb) => { + for (var i = 0; i < keys.length; ++i) { + const fullName = `${keys[i]}\\${value}` + switch (fullName) { + case 'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0': + case 'HKLM\\Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0': + continue + case 'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7\\12.0': + assert.ok(true, `expected search for registry value ${fullName}`) + return cb(null, 'C:\\VS2013\\VC\\') + case 'HKLM\\Software\\Microsoft\\MSBuild\\ToolsVersions\\12.0\\MSBuildToolsPath': + assert.ok(true, `expected search for registry value ${fullName}`) + return cb(null, 'C:\\MSBuild12\\') + default: + assert.fail(`unexpected search for registry value ${fullName}`) + } } + return cb(new Error()) } - return cb(new Error()) - } - finder.findVisualStudio() -}) + finder.findVisualStudio() + }) -test('VS2015', function (t) { - t.plan(4) - - const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info, { - msBuild: 'C:\\MSBuild14\\MSBuild.exe', - path: 'C:\\VS2015', - sdk: null, - toolset: 'v140', - version: '14.0', - versionMajor: 14, - versionMinor: 0, - versionYear: 2015 + it('VS2013 should not be found on new node versions', function () { + const finder = new TestVisualStudioFinder({ + major: 10, + minor: 0, + patch: 0 + }, null, (err, info) => { + assert.ok(/find .* Visual Studio/i.test(err), 'expect error') + assert.ok(!info, 'no data') }) - }) - finder.findVisualStudio2017OrNewer = (cb) => { - finder.parseData(new Error(), '', '', cb) - } - finder.regSearchKeys = (keys, value, addOpts, cb) => { - for (var i = 0; i < keys.length; ++i) { - const fullName = `${keys[i]}\\${value}` - switch (fullName) { - case 'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0': - t.pass(`expected search for registry value ${fullName}`) - return cb(null, 'C:\\VS2015\\VC\\') - case 'HKLM\\Software\\Microsoft\\MSBuild\\ToolsVersions\\14.0\\MSBuildToolsPath': - t.pass(`expected search for registry value ${fullName}`) - return cb(null, 'C:\\MSBuild14\\') - default: - t.fail(`unexpected search for registry value ${fullName}`) + finder.findVisualStudio2017OrNewer = (cb) => { + const file = path.join(__dirname, 'fixtures', 'VS_2017_Unusable.txt') + const data = fs.readFileSync(file) + finder.parseData(null, data, '', cb) + } + finder.regSearchKeys = (keys, value, addOpts, cb) => { + for (var i = 0; i < keys.length; ++i) { + const fullName = `${keys[i]}\\${value}` + switch (fullName) { + case 'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0': + case 'HKLM\\Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0': + continue + default: + assert.fail(`unexpected search for registry value ${fullName}`) + } } + return cb(new Error()) } - return cb(new Error()) - } - finder.findVisualStudio() -}) - -test('error from PowerShell', function (t) { - t.plan(2) - - const finder = new TestVisualStudioFinder(semverV1, null, null) - - finder.parseData(new Error(), '', '', (info) => { - t.ok(/use PowerShell/i.test(finder.errorLog[0]), 'expect error') - t.false(info, 'no data') + finder.findVisualStudio() }) -}) - -test('empty output from PowerShell', function (t) { - t.plan(2) - const finder = new TestVisualStudioFinder(semverV1, null, null) + it('VS2015', function () { + const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info, { + msBuild: 'C:\\MSBuild14\\MSBuild.exe', + path: 'C:\\VS2015', + sdk: null, + toolset: 'v140', + version: '14.0', + versionMajor: 14, + versionMinor: 0, + versionYear: 2015 + }) + }) - finder.parseData(null, '', '', (info) => { - t.ok(/use PowerShell/i.test(finder.errorLog[0]), 'expect error') - t.false(info, 'no data') + finder.findVisualStudio2017OrNewer = (cb) => { + finder.parseData(new Error(), '', '', cb) + } + finder.regSearchKeys = (keys, value, addOpts, cb) => { + for (var i = 0; i < keys.length; ++i) { + const fullName = `${keys[i]}\\${value}` + switch (fullName) { + case 'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0': + assert.ok(true, `expected search for registry value ${fullName}`) + return cb(null, 'C:\\VS2015\\VC\\') + case 'HKLM\\Software\\Microsoft\\MSBuild\\ToolsVersions\\14.0\\MSBuildToolsPath': + assert.ok(true, `expected search for registry value ${fullName}`) + return cb(null, 'C:\\MSBuild14\\') + default: + assert.fail(`unexpected search for registry value ${fullName}`) + } + } + return cb(new Error()) + } + finder.findVisualStudio() }) -}) - -test('output from PowerShell not JSON', function (t) { - t.plan(2) - const finder = new TestVisualStudioFinder(semverV1, null, null) + it('error from PowerShell', function () { + const finder = new TestVisualStudioFinder(semverV1, null, null) - finder.parseData(null, 'AAAABBBB', '', (info) => { - t.ok(/use PowerShell/i.test(finder.errorLog[0]), 'expect error') - t.false(info, 'no data') + finder.parseData(new Error(), '', '', (info) => { + assert.ok(/use PowerShell/i.test(finder.errorLog[0]), 'expect error') + assert.ok(!info, 'no data') + }) }) -}) -test('wrong JSON from PowerShell', function (t) { - t.plan(2) + it('empty output from PowerShell', function () { + const finder = new TestVisualStudioFinder(semverV1, null, null) - const finder = new TestVisualStudioFinder(semverV1, null, null) - - finder.parseData(null, '{}', '', (info) => { - t.ok(/use PowerShell/i.test(finder.errorLog[0]), 'expect error') - t.false(info, 'no data') + finder.parseData(null, '', '', (info) => { + assert.ok(/use PowerShell/i.test(finder.errorLog[0]), 'expect error') + assert.ok(!info, 'no data') + }) }) -}) - -test('empty JSON from PowerShell', function (t) { - t.plan(2) - const finder = new TestVisualStudioFinder(semverV1, null, null) + it('output from PowerShell not JSON', function () { + const finder = new TestVisualStudioFinder(semverV1, null, null) - finder.parseData(null, '[]', '', (info) => { - t.ok(/find .* Visual Studio/i.test(finder.errorLog[0]), 'expect error') - t.false(info, 'no data') + finder.parseData(null, 'AAAABBBB', '', (info) => { + assert.ok(/use PowerShell/i.test(finder.errorLog[0]), 'expect error') + assert.ok(!info, 'no data') + }) }) -}) - -test('future version', function (t) { - t.plan(3) - const finder = new TestVisualStudioFinder(semverV1, null, null) + it('wrong JSON from PowerShell', function () { + const finder = new TestVisualStudioFinder(semverV1, null, null) - finder.parseData(null, JSON.stringify([{ - packages: [ - 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64', - 'Microsoft.VisualStudio.Component.Windows10SDK.17763', - 'Microsoft.VisualStudio.VC.MSBuild.Base' - ], - path: 'C:\\VS', - version: '9999.9999.9999.9999' - }]), '', (info) => { - t.ok(/unknown version/i.test(finder.errorLog[0]), 'expect error') - t.ok(/find .* Visual Studio/i.test(finder.errorLog[1]), 'expect error') - t.false(info, 'no data') + finder.parseData(null, '{}', '', (info) => { + assert.ok(/use PowerShell/i.test(finder.errorLog[0]), 'expect error') + assert.ok(!info, 'no data') + }) }) -}) -test('single unusable VS2017', function (t) { - t.plan(3) + it('empty JSON from PowerShell', function () { + const finder = new TestVisualStudioFinder(semverV1, null, null) - const finder = new TestVisualStudioFinder(semverV1, null, null) - - const file = path.join(__dirname, 'fixtures', 'VS_2017_Unusable.txt') - const data = fs.readFileSync(file) - finder.parseData(null, data, '', (info) => { - t.ok(/checking/i.test(finder.errorLog[0]), 'expect error') - t.ok(/find .* Visual Studio/i.test(finder.errorLog[2]), 'expect error') - t.false(info, 'no data') + finder.parseData(null, '[]', '', (info) => { + assert.ok(/find .* Visual Studio/i.test(finder.errorLog[0]), 'expect error') + assert.ok(!info, 'no data') + }) }) -}) -test('minimal VS2017 Build Tools', function (t) { - t.plan(2) - - const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info, { - msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\' + - 'BuildTools\\MSBuild\\15.0\\Bin\\MSBuild.exe', - path: - 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\BuildTools', - sdk: '10.0.17134.0', - toolset: 'v141', - version: '15.9.28307.665', - versionMajor: 15, - versionMinor: 9, - versionYear: 2017 + it('future version', function () { + const finder = new TestVisualStudioFinder(semverV1, null, null) + + finder.parseData(null, JSON.stringify([{ + packages: [ + 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64', + 'Microsoft.VisualStudio.Component.Windows10SDK.17763', + 'Microsoft.VisualStudio.VC.MSBuild.Base' + ], + path: 'C:\\VS', + version: '9999.9999.9999.9999' + }]), '', (info) => { + assert.ok(/unknown version/i.test(finder.errorLog[0]), 'expect error') + assert.ok(/find .* Visual Studio/i.test(finder.errorLog[1]), 'expect error') + assert.ok(!info, 'no data') }) }) - poison(finder, 'regSearchKeys') - finder.findVisualStudio2017OrNewer = (cb) => { - const file = path.join(__dirname, 'fixtures', - 'VS_2017_BuildTools_minimal.txt') - const data = fs.readFileSync(file) - finder.parseData(null, data, '', cb) - } - finder.findVisualStudio() -}) + it('single unusable VS2017', function () { + const finder = new TestVisualStudioFinder(semverV1, null, null) -test('VS2017 Community with C++ workload', function (t) { - t.plan(2) - - const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info, { - msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\' + - 'Community\\MSBuild\\15.0\\Bin\\MSBuild.exe', - path: - 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community', - sdk: '10.0.17763.0', - toolset: 'v141', - version: '15.9.28307.665', - versionMajor: 15, - versionMinor: 9, - versionYear: 2017 + const file = path.join(__dirname, 'fixtures', 'VS_2017_Unusable.txt') + const data = fs.readFileSync(file) + finder.parseData(null, data, '', (info) => { + assert.ok(/checking/i.test(finder.errorLog[0]), 'expect error') + assert.ok(/find .* Visual Studio/i.test(finder.errorLog[2]), 'expect error') + assert.ok(!info, 'no data') }) }) - poison(finder, 'regSearchKeys') - finder.findVisualStudio2017OrNewer = (cb) => { - const file = path.join(__dirname, 'fixtures', - 'VS_2017_Community_workload.txt') - const data = fs.readFileSync(file) - finder.parseData(null, data, '', cb) - } - finder.findVisualStudio() -}) - -test('VS2017 Express', function (t) { - t.plan(2) - - const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info, { - msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\' + - 'WDExpress\\MSBuild\\15.0\\Bin\\MSBuild.exe', - path: - 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\WDExpress', - sdk: '10.0.17763.0', - toolset: 'v141', - version: '15.9.28307.858', - versionMajor: 15, - versionMinor: 9, - versionYear: 2017 + it('minimal VS2017 Build Tools', function () { + const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info, { + msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\' + + 'BuildTools\\MSBuild\\15.0\\Bin\\MSBuild.exe', + path: + 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\BuildTools', + sdk: '10.0.17134.0', + toolset: 'v141', + version: '15.9.28307.665', + versionMajor: 15, + versionMinor: 9, + versionYear: 2017 + }) }) - }) - poison(finder, 'regSearchKeys') - finder.findVisualStudio2017OrNewer = (cb) => { - const file = path.join(__dirname, 'fixtures', 'VS_2017_Express.txt') - const data = fs.readFileSync(file) - finder.parseData(null, data, '', cb) - } - finder.findVisualStudio() -}) + poison(finder, 'regSearchKeys') + finder.findVisualStudio2017OrNewer = (cb) => { + const file = path.join(__dirname, 'fixtures', + 'VS_2017_BuildTools_minimal.txt') + const data = fs.readFileSync(file) + finder.parseData(null, data, '', cb) + } + finder.findVisualStudio() + }) -test('VS2019 Preview with C++ workload', function (t) { - t.plan(2) - - const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info, { - msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\' + - 'Preview\\MSBuild\\Current\\Bin\\MSBuild.exe', - path: - 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Preview', - sdk: '10.0.17763.0', - toolset: 'v142', - version: '16.0.28608.199', - versionMajor: 16, - versionMinor: 0, - versionYear: 2019 + it('VS2017 Community with C++ workload', function () { + const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info, { + msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\' + + 'Community\\MSBuild\\15.0\\Bin\\MSBuild.exe', + path: + 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community', + sdk: '10.0.17763.0', + toolset: 'v141', + version: '15.9.28307.665', + versionMajor: 15, + versionMinor: 9, + versionYear: 2017 + }) }) - }) - poison(finder, 'regSearchKeys') - finder.findVisualStudio2017OrNewer = (cb) => { - const file = path.join(__dirname, 'fixtures', - 'VS_2019_Preview.txt') - const data = fs.readFileSync(file) - finder.parseData(null, data, '', cb) - } - finder.findVisualStudio() -}) + poison(finder, 'regSearchKeys') + finder.findVisualStudio2017OrNewer = (cb) => { + const file = path.join(__dirname, 'fixtures', + 'VS_2017_Community_workload.txt') + const data = fs.readFileSync(file) + finder.parseData(null, data, '', cb) + } + finder.findVisualStudio() + }) -test('minimal VS2019 Build Tools', function (t) { - t.plan(2) - - const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info, { - msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\' + - 'BuildTools\\MSBuild\\Current\\Bin\\MSBuild.exe', - path: - 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools', - sdk: '10.0.17134.0', - toolset: 'v142', - version: '16.1.28922.388', - versionMajor: 16, - versionMinor: 1, - versionYear: 2019 + it('VS2017 Express', function () { + const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info, { + msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\' + + 'WDExpress\\MSBuild\\15.0\\Bin\\MSBuild.exe', + path: + 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\WDExpress', + sdk: '10.0.17763.0', + toolset: 'v141', + version: '15.9.28307.858', + versionMajor: 15, + versionMinor: 9, + versionYear: 2017 + }) }) - }) - poison(finder, 'regSearchKeys') - finder.findVisualStudio2017OrNewer = (cb) => { - const file = path.join(__dirname, 'fixtures', - 'VS_2019_BuildTools_minimal.txt') - const data = fs.readFileSync(file) - finder.parseData(null, data, '', cb) - } - finder.findVisualStudio() -}) + poison(finder, 'regSearchKeys') + finder.findVisualStudio2017OrNewer = (cb) => { + const file = path.join(__dirname, 'fixtures', 'VS_2017_Express.txt') + const data = fs.readFileSync(file) + finder.parseData(null, data, '', cb) + } + finder.findVisualStudio() + }) -test('VS2019 Community with C++ workload', function (t) { - t.plan(2) - - const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info, { - msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\' + - 'Community\\MSBuild\\Current\\Bin\\MSBuild.exe', - path: - 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community', - sdk: '10.0.17763.0', - toolset: 'v142', - version: '16.1.28922.388', - versionMajor: 16, - versionMinor: 1, - versionYear: 2019 + it('VS2019 Preview with C++ workload', function () { + const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info, { + msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\' + + 'Preview\\MSBuild\\Current\\Bin\\MSBuild.exe', + path: + 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Preview', + sdk: '10.0.17763.0', + toolset: 'v142', + version: '16.0.28608.199', + versionMajor: 16, + versionMinor: 0, + versionYear: 2019 + }) }) + + poison(finder, 'regSearchKeys') + finder.findVisualStudio2017OrNewer = (cb) => { + const file = path.join(__dirname, 'fixtures', + 'VS_2019_Preview.txt') + const data = fs.readFileSync(file) + finder.parseData(null, data, '', cb) + } + finder.findVisualStudio() }) - poison(finder, 'regSearchKeys') - finder.findVisualStudio2017OrNewer = (cb) => { - const file = path.join(__dirname, 'fixtures', - 'VS_2019_Community_workload.txt') - const data = fs.readFileSync(file) - finder.parseData(null, data, '', cb) - } - finder.findVisualStudio() -}) + it('minimal VS2019 Build Tools', function () { + const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info, { + msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\' + + 'BuildTools\\MSBuild\\Current\\Bin\\MSBuild.exe', + path: + 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools', + sdk: '10.0.17134.0', + toolset: 'v142', + version: '16.1.28922.388', + versionMajor: 16, + versionMinor: 1, + versionYear: 2019 + }) + }) -function allVsVersions (t, finder) { - finder.findVisualStudio2017OrNewer = (cb) => { - const data0 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures', - 'VS_2017_Unusable.txt'))) - const data1 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures', - 'VS_2017_BuildTools_minimal.txt'))) - const data2 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures', - 'VS_2017_Community_workload.txt'))) - const data3 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures', - 'VS_2017_Express.txt'))) - const data4 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures', - 'VS_2019_Preview.txt'))) - const data5 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures', - 'VS_2019_BuildTools_minimal.txt'))) - const data6 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures', - 'VS_2019_Community_workload.txt'))) - const data = JSON.stringify(data0.concat(data1, data2, data3, data4, - data5, data6)) - finder.parseData(null, data, '', cb) - } - finder.regSearchKeys = (keys, value, addOpts, cb) => { - for (var i = 0; i < keys.length; ++i) { - const fullName = `${keys[i]}\\${value}` - switch (fullName) { - case 'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0': - case 'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7\\12.0': - continue - case 'HKLM\\Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7\\12.0': - return cb(null, 'C:\\VS2013\\VC\\') - case 'HKLM\\Software\\Microsoft\\MSBuild\\ToolsVersions\\12.0\\MSBuildToolsPath': - return cb(null, 'C:\\MSBuild12\\') - case 'HKLM\\Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0': - return cb(null, 'C:\\VS2015\\VC\\') - case 'HKLM\\Software\\Microsoft\\MSBuild\\ToolsVersions\\14.0\\MSBuildToolsPath': - return cb(null, 'C:\\MSBuild14\\') - default: - t.fail(`unexpected search for registry value ${fullName}`) - } + poison(finder, 'regSearchKeys') + finder.findVisualStudio2017OrNewer = (cb) => { + const file = path.join(__dirname, 'fixtures', + 'VS_2019_BuildTools_minimal.txt') + const data = fs.readFileSync(file) + finder.parseData(null, data, '', cb) } - return cb(new Error()) - } -} + finder.findVisualStudio() + }) -test('fail when looking for invalid path', function (t) { - t.plan(2) + it('VS2019 Community with C++ workload', function () { + const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info, { + msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\' + + 'Community\\MSBuild\\Current\\Bin\\MSBuild.exe', + path: + 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community', + sdk: '10.0.17763.0', + toolset: 'v142', + version: '16.1.28922.388', + versionMajor: 16, + versionMinor: 1, + versionYear: 2019 + }) + }) - const finder = new TestVisualStudioFinder(semverV1, 'AABB', (err, info) => { - t.ok(/find .* Visual Studio/i.test(err), 'expect error') - t.false(info, 'no data') + poison(finder, 'regSearchKeys') + finder.findVisualStudio2017OrNewer = (cb) => { + const file = path.join(__dirname, 'fixtures', + 'VS_2019_Community_workload.txt') + const data = fs.readFileSync(file) + finder.parseData(null, data, '', cb) + } + finder.findVisualStudio() }) - allVsVersions(t, finder) - finder.findVisualStudio() -}) - -test('look for VS2013 by version number', function (t) { - t.plan(2) + it('VS2022 Preview with C++ workload', function () { + const msBuildPath = process.arch === 'arm64' + ? 'C:\\Program Files\\Microsoft Visual Studio\\2022\\' + + 'Community\\MSBuild\\Current\\Bin\\arm64\\MSBuild.exe' + : 'C:\\Program Files\\Microsoft Visual Studio\\2022\\' + + 'Community\\MSBuild\\Current\\Bin\\MSBuild.exe' + + const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info, { + msBuild: msBuildPath, + path: + 'C:\\Program Files\\Microsoft Visual Studio\\2022\\Community', + sdk: '10.0.22621.0', + toolset: 'v143', + version: '17.4.33213.308', + versionMajor: 17, + versionMinor: 4, + versionYear: 2022 + }) + }) - const finder = new TestVisualStudioFinder(semverV1, '2013', (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info.versionYear, 2013) + poison(finder, 'regSearchKeys') + finder.msBuildPathExists = (path) => { + return true + } + finder.findVisualStudio2017OrNewer = (cb) => { + const file = path.join(__dirname, 'fixtures', + 'VS_2022_Community_workload.txt') + const data = fs.readFileSync(file) + finder.parseData(null, data, '', cb) + } + finder.findVisualStudio() }) - allVsVersions(t, finder) - finder.findVisualStudio() -}) - -test('look for VS2013 by installation path', function (t) { - t.plan(2) + function allVsVersions (finder) { + finder.findVisualStudio2017OrNewer = (cb) => { + const data0 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures', + 'VS_2017_Unusable.txt'))) + const data1 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures', + 'VS_2017_BuildTools_minimal.txt'))) + const data2 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures', + 'VS_2017_Community_workload.txt'))) + const data3 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures', + 'VS_2017_Express.txt'))) + const data4 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures', + 'VS_2019_Preview.txt'))) + const data5 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures', + 'VS_2019_BuildTools_minimal.txt'))) + const data6 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures', + 'VS_2019_Community_workload.txt'))) + const data7 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures', + 'VS_2022_Community_workload.txt'))) + const data = JSON.stringify(data0.concat(data1, data2, data3, data4, + data5, data6, data7)) + finder.parseData(null, data, '', cb) + } + finder.regSearchKeys = (keys, value, addOpts, cb) => { + for (var i = 0; i < keys.length; ++i) { + const fullName = `${keys[i]}\\${value}` + switch (fullName) { + case 'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0': + case 'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7\\12.0': + continue + case 'HKLM\\Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7\\12.0': + return cb(null, 'C:\\VS2013\\VC\\') + case 'HKLM\\Software\\Microsoft\\MSBuild\\ToolsVersions\\12.0\\MSBuildToolsPath': + return cb(null, 'C:\\MSBuild12\\') + case 'HKLM\\Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0': + return cb(null, 'C:\\VS2015\\VC\\') + case 'HKLM\\Software\\Microsoft\\MSBuild\\ToolsVersions\\14.0\\MSBuildToolsPath': + return cb(null, 'C:\\MSBuild14\\') + default: + assert.fail(`unexpected search for registry value ${fullName}`) + } + } + return cb(new Error()) + } + } - const finder = new TestVisualStudioFinder(semverV1, 'C:\\VS2013', - (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info.path, 'C:\\VS2013') + it('fail when looking for invalid path', function () { + const finder = new TestVisualStudioFinder(semverV1, 'AABB', (err, info) => { + assert.ok(/find .* Visual Studio/i.test(err), 'expect error') + assert.ok(!info, 'no data') }) - allVsVersions(t, finder) - finder.findVisualStudio() -}) + allVsVersions(finder) + finder.findVisualStudio() + }) -test('look for VS2015 by version number', function (t) { - t.plan(2) + it('look for VS2013 by version number', function () { + const finder = new TestVisualStudioFinder(semverV1, '2013', (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info.versionYear, 2013) + }) - const finder = new TestVisualStudioFinder(semverV1, '2015', (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info.versionYear, 2015) + allVsVersions(finder) + finder.findVisualStudio() }) - allVsVersions(t, finder) - finder.findVisualStudio() -}) + it('look for VS2013 by installation path', function () { + const finder = new TestVisualStudioFinder(semverV1, 'C:\\VS2013', + (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info.path, 'C:\\VS2013') + }) -test('look for VS2015 by installation path', function (t) { - t.plan(2) + allVsVersions(finder) + finder.findVisualStudio() + }) - const finder = new TestVisualStudioFinder(semverV1, 'C:\\VS2015', - (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info.path, 'C:\\VS2015') + it('look for VS2015 by version number', function () { + const finder = new TestVisualStudioFinder(semverV1, '2015', (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info.versionYear, 2015) }) - allVsVersions(t, finder) - finder.findVisualStudio() -}) - -test('look for VS2017 by version number', function (t) { - t.plan(2) - - const finder = new TestVisualStudioFinder(semverV1, '2017', (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info.versionYear, 2017) + allVsVersions(finder) + finder.findVisualStudio() }) - allVsVersions(t, finder) - finder.findVisualStudio() -}) + it('look for VS2015 by installation path', function () { + const finder = new TestVisualStudioFinder(semverV1, 'C:\\VS2015', + (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info.path, 'C:\\VS2015') + }) -test('look for VS2017 by installation path', function (t) { - t.plan(2) + allVsVersions(finder) + finder.findVisualStudio() + }) - const finder = new TestVisualStudioFinder(semverV1, - 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community', - (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info.path, - 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community') + it('look for VS2017 by version number', function () { + const finder = new TestVisualStudioFinder(semverV1, '2017', (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info.versionYear, 2017) }) - allVsVersions(t, finder) - finder.findVisualStudio() -}) - -test('look for VS2019 by version number', function (t) { - t.plan(2) - - const finder = new TestVisualStudioFinder(semverV1, '2019', (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info.versionYear, 2019) + allVsVersions(finder) + finder.findVisualStudio() }) - allVsVersions(t, finder) - finder.findVisualStudio() -}) - -test('look for VS2019 by installation path', function (t) { - t.plan(2) + it('look for VS2017 by installation path', function () { + const finder = new TestVisualStudioFinder(semverV1, + 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community', + (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info.path, + 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community') + }) + + allVsVersions(finder) + finder.findVisualStudio() + }) - const finder = new TestVisualStudioFinder(semverV1, - 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools', - (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info.path, - 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools') + it('look for VS2019 by version number', function () { + const finder = new TestVisualStudioFinder(semverV1, '2019', (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info.versionYear, 2019) }) - allVsVersions(t, finder) - finder.findVisualStudio() -}) + allVsVersions(finder) + finder.findVisualStudio() + }) -test('msvs_version match should be case insensitive', function (t) { - t.plan(2) + it('look for VS2019 by installation path', function () { + const finder = new TestVisualStudioFinder(semverV1, + 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools', + (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info.path, + 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools') + }) + + allVsVersions(finder) + finder.findVisualStudio() + }) - const finder = new TestVisualStudioFinder(semverV1, - 'c:\\program files (x86)\\microsoft visual studio\\2019\\BUILDTOOLS', - (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info.path, - 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools') + it('look for VS2022 by version number', function () { + const finder = new TestVisualStudioFinder(semverV1, '2022', (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info.versionYear, 2022) }) - allVsVersions(t, finder) - finder.findVisualStudio() -}) - -test('latest version should be found by default', function (t) { - t.plan(2) + finder.msBuildPathExists = (path) => { + return true + } - const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info.versionYear, 2019) + allVsVersions(finder) + finder.findVisualStudio() }) - allVsVersions(t, finder) - finder.findVisualStudio() -}) + it('msvs_version match should be case insensitive', function () { + const finder = new TestVisualStudioFinder(semverV1, + 'c:\\program files (x86)\\microsoft visual studio\\2019\\BUILDTOOLS', + (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info.path, + 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools') + }) + + allVsVersions(finder) + finder.findVisualStudio() + }) -test('run on a usable VS Command Prompt', function (t) { - t.plan(2) + it('latest version should be found by default', function () { + const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info.versionYear, 2022) + }) - process.env.VCINSTALLDIR = 'C:\\VS2015\\VC' - // VSINSTALLDIR is not defined on Visual C++ Build Tools 2015 - delete process.env.VSINSTALLDIR + finder.msBuildPathExists = (path) => { + return true + } - const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info.path, 'C:\\VS2015') + allVsVersions(finder) + finder.findVisualStudio() }) - allVsVersions(t, finder) - finder.findVisualStudio() -}) + it('run on a usable VS Command Prompt', function () { + process.env.VCINSTALLDIR = 'C:\\VS2015\\VC' + // VSINSTALLDIR is not defined on Visual C++ Build Tools 2015 + delete process.env.VSINSTALLDIR -test('VCINSTALLDIR match should be case insensitive', function (t) { - t.plan(2) - - process.env.VCINSTALLDIR = - 'c:\\program files (x86)\\microsoft visual studio\\2019\\BUILDTOOLS\\VC' + const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info.path, 'C:\\VS2015') + }) - const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info.path, - 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools') + allVsVersions(finder) + finder.findVisualStudio() }) - allVsVersions(t, finder) - finder.findVisualStudio() -}) - -test('run on a unusable VS Command Prompt', function (t) { - t.plan(2) + it('VCINSTALLDIR match should be case insensitive', function () { + process.env.VCINSTALLDIR = + 'c:\\program files (x86)\\microsoft visual studio\\2019\\BUILDTOOLS\\VC' - process.env.VCINSTALLDIR = - 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildToolsUnusable\\VC' + const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info.path, + 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools') + }) - const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { - t.ok(/find .* Visual Studio/i.test(err), 'expect error') - t.false(info, 'no data') + allVsVersions(finder) + finder.findVisualStudio() }) - allVsVersions(t, finder) - finder.findVisualStudio() -}) + it('run on a unusable VS Command Prompt', function () { + process.env.VCINSTALLDIR = + 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildToolsUnusable\\VC' -test('run on a VS Command Prompt with matching msvs_version', function (t) { - t.plan(2) + const finder = new TestVisualStudioFinder(semverV1, null, (err, info) => { + assert.ok(/find .* Visual Studio/i.test(err), 'expect error') + assert.ok(!info, 'no data') + }) - process.env.VCINSTALLDIR = 'C:\\VS2015\\VC' + allVsVersions(finder) + finder.findVisualStudio() + }) - const finder = new TestVisualStudioFinder(semverV1, 'C:\\VS2015', - (err, info) => { - t.strictEqual(err, null) - t.deepEqual(info.path, 'C:\\VS2015') - }) + it('run on a VS Command Prompt with matching msvs_version', function () { + process.env.VCINSTALLDIR = 'C:\\VS2015\\VC' - allVsVersions(t, finder) - finder.findVisualStudio() -}) + const finder = new TestVisualStudioFinder(semverV1, 'C:\\VS2015', + (err, info) => { + assert.strictEqual(err, null) + assert.deepStrictEqual(info.path, 'C:\\VS2015') + }) -test('run on a VS Command Prompt with mismatched msvs_version', function (t) { - t.plan(2) + allVsVersions(finder) + finder.findVisualStudio() + }) - process.env.VCINSTALLDIR = - 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools\\VC' + it('run on a VS Command Prompt with mismatched msvs_version', function () { + process.env.VCINSTALLDIR = + 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools\\VC' - const finder = new TestVisualStudioFinder(semverV1, 'C:\\VS2015', - (err, info) => { - t.ok(/find .* Visual Studio/i.test(err), 'expect error') - t.false(info, 'no data') - }) + const finder = new TestVisualStudioFinder(semverV1, 'C:\\VS2015', + (err, info) => { + assert.ok(/find .* Visual Studio/i.test(err), 'expect error') + assert.ok(!info, 'no data') + }) - allVsVersions(t, finder) - finder.findVisualStudio() + allVsVersions(finder) + finder.findVisualStudio() + }) }) diff --git a/node_modules/node-gyp/test/test-install.js b/node_modules/node-gyp/test/test-install.js index 5039dc992eb47..235acf5231396 100644 --- a/node_modules/node-gyp/test/test-install.js +++ b/node_modules/node-gyp/test/test-install.js @@ -1,46 +1,137 @@ 'use strict' -const { test } = require('tap') -const { test: { install } } = require('../lib/install') +const { describe, it, after } = require('mocha') +const assert = require('assert') +const path = require('path') +const os = require('os') +const util = require('util') +const { test: { download, install } } = require('../lib/install') +const rimraf = require('rimraf') +const gyp = require('../lib/node-gyp') const log = require('npmlog') +const semver = require('semver') +const stream = require('stream') +const streamPipeline = util.promisify(stream.pipeline) log.level = 'error' // we expect a warning -test('EACCES retry once', async (t) => { - t.plan(3) - - const fs = { - promises: { - stat (_) { - const err = new Error() - err.code = 'EACCES' - t.ok(true) - throw err +describe('install', function () { + it('EACCES retry once', async () => { + const fs = { + promises: { + stat (_) { + const err = new Error() + err.code = 'EACCES' + assert.ok(true) + throw err + } } } - } - const Gyp = { - devDir: __dirname, - opts: { - ensure: true - }, - commands: { - install (argv, cb) { - install(fs, Gyp, argv).then(cb, cb) + const Gyp = { + devDir: __dirname, + opts: { + ensure: true }, - remove (_, cb) { - cb() + commands: { + install (argv, cb) { + install(fs, Gyp, argv).then(cb, cb) + }, + remove (_, cb) { + cb() + } } } - } - try { - await install(fs, Gyp, []) - } catch (err) { - t.ok(true) - if (/"pre" versions of node cannot be installed/.test(err.message)) { - t.ok(true) + try { + await install(fs, Gyp, []) + } catch (err) { + assert.ok(true) + if (/"pre" versions of node cannot be installed/.test(err.message)) { + assert.ok(true) + } + } + }) + + // only run these tests if we are running a version of Node with predictable version path behavior + const skipParallelInstallTests = process.env.FAST_TEST || + process.release.name !== 'node' || + semver.prerelease(process.version) !== null || + semver.satisfies(process.version, '<10') + + async function parallelInstallsTest (test, fs, devDir, prog) { + if (skipParallelInstallTests) { + return test.skip('Skipping parallel installs test due to test environment configuration') } + + after(async () => { + await util.promisify(rimraf)(devDir) + }) + + const expectedDir = path.join(devDir, process.version.replace(/^v/, '')) + await util.promisify(rimraf)(expectedDir) + + await Promise.all([ + install(fs, prog, []), + install(fs, prog, []), + install(fs, prog, []), + install(fs, prog, []), + install(fs, prog, []), + install(fs, prog, []), + install(fs, prog, []), + install(fs, prog, []), + install(fs, prog, []), + install(fs, prog, []) + ]) } + + it('parallel installs (ensure=true)', async function () { + this.timeout(600000) + + const fs = require('graceful-fs') + const devDir = await util.promisify(fs.mkdtemp)(path.join(os.tmpdir(), 'node-gyp-test-')) + + const prog = gyp() + prog.parseArgv([]) + prog.devDir = devDir + prog.opts.ensure = true + log.level = 'warn' + + await parallelInstallsTest(this, fs, devDir, prog) + }) + + it('parallel installs (ensure=false)', async function () { + this.timeout(600000) + + const fs = require('graceful-fs') + const devDir = await util.promisify(fs.mkdtemp)(path.join(os.tmpdir(), 'node-gyp-test-')) + + const prog = gyp() + prog.parseArgv([]) + prog.devDir = devDir + prog.opts.ensure = false + log.level = 'warn' + + await parallelInstallsTest(this, fs, devDir, prog) + }) + + it('parallel installs (tarball)', async function () { + this.timeout(600000) + + const fs = require('graceful-fs') + const devDir = await util.promisify(fs.mkdtemp)(path.join(os.tmpdir(), 'node-gyp-test-')) + + const prog = gyp() + prog.parseArgv([]) + prog.devDir = devDir + prog.opts.tarball = path.join(devDir, 'node-headers.tar.gz') + log.level = 'warn' + + await streamPipeline( + (await download(prog, `https://nodejs.org/dist/${process.version}/node-${process.version}.tar.gz`)).body, + fs.createWriteStream(prog.opts.tarball) + ) + + await parallelInstallsTest(this, fs, devDir, prog) + }) }) diff --git a/node_modules/node-gyp/test/test-options.js b/node_modules/node-gyp/test/test-options.js index 8a634f0e0955d..24e79c80a1843 100644 --- a/node_modules/node-gyp/test/test-options.js +++ b/node_modules/node-gyp/test/test-options.js @@ -1,42 +1,41 @@ 'use strict' -const test = require('tap').test +const { describe, it } = require('mocha') +const assert = require('assert') const gyp = require('../lib/node-gyp') -test('options in environment', (t) => { - t.plan(1) +describe('options', function () { + it('options in environment', () => { + // `npm test` dumps a ton of npm_config_* variables in the environment. + Object.keys(process.env) + .filter((key) => /^npm_config_/.test(key)) + .forEach((key) => { delete process.env[key] }) - // `npm test` dumps a ton of npm_config_* variables in the environment. - Object.keys(process.env) - .filter((key) => /^npm_config_/.test(key)) - .forEach((key) => { delete process.env[key] }) + // in some platforms, certain keys are stubborn and cannot be removed + const keys = Object.keys(process.env) + .filter((key) => /^npm_config_/.test(key)) + .map((key) => key.substring('npm_config_'.length)) + .concat('argv', 'x') - // in some platforms, certain keys are stubborn and cannot be removed - const keys = Object.keys(process.env) - .filter((key) => /^npm_config_/.test(key)) - .map((key) => key.substring('npm_config_'.length)) - .concat('argv', 'x') + // Zero-length keys should get filtered out. + process.env.npm_config_ = '42' + // Other keys should get added. + process.env.npm_config_x = '42' + // Except loglevel. + process.env.npm_config_loglevel = 'debug' - // Zero-length keys should get filtered out. - process.env.npm_config_ = '42' - // Other keys should get added. - process.env.npm_config_x = '42' - // Except loglevel. - process.env.npm_config_loglevel = 'debug' + const g = gyp() + g.parseArgv(['rebuild']) // Also sets opts.argv. - const g = gyp() - g.parseArgv(['rebuild']) // Also sets opts.argv. + assert.deepStrictEqual(Object.keys(g.opts).sort(), keys.sort()) + }) - t.deepEqual(Object.keys(g.opts).sort(), keys.sort()) -}) - -test('options with spaces in environment', (t) => { - t.plan(1) - - process.env.npm_config_force_process_config = 'true' + it('options with spaces in environment', () => { + process.env.npm_config_force_process_config = 'true' - const g = gyp() - g.parseArgv(['rebuild']) // Also sets opts.argv. + const g = gyp() + g.parseArgv(['rebuild']) // Also sets opts.argv. - t.equal(g.opts['force-process-config'], 'true') + assert.strictEqual(g.opts['force-process-config'], 'true') + }) }) diff --git a/node_modules/node-gyp/test/test-process-release.js b/node_modules/node-gyp/test/test-process-release.js index c3ee0703c532f..0f40666473028 100644 --- a/node_modules/node-gyp/test/test-process-release.js +++ b/node_modules/node-gyp/test/test-process-release.js @@ -1,434 +1,401 @@ 'use strict' -const test = require('tap').test +const { describe, it } = require('mocha') +const assert = require('assert') const processRelease = require('../lib/process-release') -test('test process release - process.version = 0.8.20', function (t) { - t.plan(2) - - var release = processRelease([], { opts: {} }, 'v0.8.20', null) - - t.equal(release.semver.version, '0.8.20') - delete release.semver - - t.deepEqual(release, { - version: '0.8.20', - name: 'node', - baseUrl: 'https://nodejs.org/dist/v0.8.20/', - tarballUrl: 'https://nodejs.org/dist/v0.8.20/node-v0.8.20.tar.gz', - shasumsUrl: 'https://nodejs.org/dist/v0.8.20/SHASUMS256.txt', - versionDir: '0.8.20', - ia32: { libUrl: 'https://nodejs.org/dist/v0.8.20/node.lib', libPath: 'node.lib' }, - x64: { libUrl: 'https://nodejs.org/dist/v0.8.20/x64/node.lib', libPath: 'x64/node.lib' }, - arm64: { libUrl: 'https://nodejs.org/dist/v0.8.20/arm64/node.lib', libPath: 'arm64/node.lib' } +describe('process-release', function () { + it('test process release - process.version = 0.8.20', function () { + var release = processRelease([], { opts: {} }, 'v0.8.20', null) + + assert.strictEqual(release.semver.version, '0.8.20') + delete release.semver + + assert.deepStrictEqual(release, { + version: '0.8.20', + name: 'node', + baseUrl: 'https://nodejs.org/dist/v0.8.20/', + tarballUrl: 'https://nodejs.org/dist/v0.8.20/node-v0.8.20.tar.gz', + shasumsUrl: 'https://nodejs.org/dist/v0.8.20/SHASUMS256.txt', + versionDir: '0.8.20', + ia32: { libUrl: 'https://nodejs.org/dist/v0.8.20/node.lib', libPath: 'node.lib' }, + x64: { libUrl: 'https://nodejs.org/dist/v0.8.20/x64/node.lib', libPath: 'x64/node.lib' }, + arm64: { libUrl: 'https://nodejs.org/dist/v0.8.20/arm64/node.lib', libPath: 'arm64/node.lib' } + }) }) -}) -test('test process release - process.version = 0.10.21', function (t) { - t.plan(2) - - var release = processRelease([], { opts: {} }, 'v0.10.21', null) - - t.equal(release.semver.version, '0.10.21') - delete release.semver - - t.deepEqual(release, { - version: '0.10.21', - name: 'node', - baseUrl: 'https://nodejs.org/dist/v0.10.21/', - tarballUrl: 'https://nodejs.org/dist/v0.10.21/node-v0.10.21.tar.gz', - shasumsUrl: 'https://nodejs.org/dist/v0.10.21/SHASUMS256.txt', - versionDir: '0.10.21', - ia32: { libUrl: 'https://nodejs.org/dist/v0.10.21/node.lib', libPath: 'node.lib' }, - x64: { libUrl: 'https://nodejs.org/dist/v0.10.21/x64/node.lib', libPath: 'x64/node.lib' }, - arm64: { libUrl: 'https://nodejs.org/dist/v0.10.21/arm64/node.lib', libPath: 'arm64/node.lib' } + it('test process release - process.version = 0.10.21', function () { + var release = processRelease([], { opts: {} }, 'v0.10.21', null) + + assert.strictEqual(release.semver.version, '0.10.21') + delete release.semver + + assert.deepStrictEqual(release, { + version: '0.10.21', + name: 'node', + baseUrl: 'https://nodejs.org/dist/v0.10.21/', + tarballUrl: 'https://nodejs.org/dist/v0.10.21/node-v0.10.21.tar.gz', + shasumsUrl: 'https://nodejs.org/dist/v0.10.21/SHASUMS256.txt', + versionDir: '0.10.21', + ia32: { libUrl: 'https://nodejs.org/dist/v0.10.21/node.lib', libPath: 'node.lib' }, + x64: { libUrl: 'https://nodejs.org/dist/v0.10.21/x64/node.lib', libPath: 'x64/node.lib' }, + arm64: { libUrl: 'https://nodejs.org/dist/v0.10.21/arm64/node.lib', libPath: 'arm64/node.lib' } + }) }) -}) -// prior to -headers.tar.gz -test('test process release - process.version = 0.12.9', function (t) { - t.plan(2) - - var release = processRelease([], { opts: {} }, 'v0.12.9', null) - - t.equal(release.semver.version, '0.12.9') - delete release.semver - - t.deepEqual(release, { - version: '0.12.9', - name: 'node', - baseUrl: 'https://nodejs.org/dist/v0.12.9/', - tarballUrl: 'https://nodejs.org/dist/v0.12.9/node-v0.12.9.tar.gz', - shasumsUrl: 'https://nodejs.org/dist/v0.12.9/SHASUMS256.txt', - versionDir: '0.12.9', - ia32: { libUrl: 'https://nodejs.org/dist/v0.12.9/node.lib', libPath: 'node.lib' }, - x64: { libUrl: 'https://nodejs.org/dist/v0.12.9/x64/node.lib', libPath: 'x64/node.lib' }, - arm64: { libUrl: 'https://nodejs.org/dist/v0.12.9/arm64/node.lib', libPath: 'arm64/node.lib' } + // prior to -headers.tar.gz + it('test process release - process.version = 0.12.9', function () { + var release = processRelease([], { opts: {} }, 'v0.12.9', null) + + assert.strictEqual(release.semver.version, '0.12.9') + delete release.semver + + assert.deepStrictEqual(release, { + version: '0.12.9', + name: 'node', + baseUrl: 'https://nodejs.org/dist/v0.12.9/', + tarballUrl: 'https://nodejs.org/dist/v0.12.9/node-v0.12.9.tar.gz', + shasumsUrl: 'https://nodejs.org/dist/v0.12.9/SHASUMS256.txt', + versionDir: '0.12.9', + ia32: { libUrl: 'https://nodejs.org/dist/v0.12.9/node.lib', libPath: 'node.lib' }, + x64: { libUrl: 'https://nodejs.org/dist/v0.12.9/x64/node.lib', libPath: 'x64/node.lib' }, + arm64: { libUrl: 'https://nodejs.org/dist/v0.12.9/arm64/node.lib', libPath: 'arm64/node.lib' } + }) }) -}) -// prior to -headers.tar.gz -test('test process release - process.version = 0.10.41', function (t) { - t.plan(2) - - var release = processRelease([], { opts: {} }, 'v0.10.41', null) - - t.equal(release.semver.version, '0.10.41') - delete release.semver - - t.deepEqual(release, { - version: '0.10.41', - name: 'node', - baseUrl: 'https://nodejs.org/dist/v0.10.41/', - tarballUrl: 'https://nodejs.org/dist/v0.10.41/node-v0.10.41.tar.gz', - shasumsUrl: 'https://nodejs.org/dist/v0.10.41/SHASUMS256.txt', - versionDir: '0.10.41', - ia32: { libUrl: 'https://nodejs.org/dist/v0.10.41/node.lib', libPath: 'node.lib' }, - x64: { libUrl: 'https://nodejs.org/dist/v0.10.41/x64/node.lib', libPath: 'x64/node.lib' }, - arm64: { libUrl: 'https://nodejs.org/dist/v0.10.41/arm64/node.lib', libPath: 'arm64/node.lib' } + // prior to -headers.tar.gz + it('test process release - process.version = 0.10.41', function () { + var release = processRelease([], { opts: {} }, 'v0.10.41', null) + + assert.strictEqual(release.semver.version, '0.10.41') + delete release.semver + + assert.deepStrictEqual(release, { + version: '0.10.41', + name: 'node', + baseUrl: 'https://nodejs.org/dist/v0.10.41/', + tarballUrl: 'https://nodejs.org/dist/v0.10.41/node-v0.10.41.tar.gz', + shasumsUrl: 'https://nodejs.org/dist/v0.10.41/SHASUMS256.txt', + versionDir: '0.10.41', + ia32: { libUrl: 'https://nodejs.org/dist/v0.10.41/node.lib', libPath: 'node.lib' }, + x64: { libUrl: 'https://nodejs.org/dist/v0.10.41/x64/node.lib', libPath: 'x64/node.lib' }, + arm64: { libUrl: 'https://nodejs.org/dist/v0.10.41/arm64/node.lib', libPath: 'arm64/node.lib' } + }) }) -}) -// has -headers.tar.gz -test('test process release - process.release ~ node@0.10.42', function (t) { - t.plan(2) - - var release = processRelease([], { opts: {} }, 'v0.10.42', null) - - t.equal(release.semver.version, '0.10.42') - delete release.semver - - t.deepEqual(release, { - version: '0.10.42', - name: 'node', - baseUrl: 'https://nodejs.org/dist/v0.10.42/', - tarballUrl: 'https://nodejs.org/dist/v0.10.42/node-v0.10.42-headers.tar.gz', - shasumsUrl: 'https://nodejs.org/dist/v0.10.42/SHASUMS256.txt', - versionDir: '0.10.42', - ia32: { libUrl: 'https://nodejs.org/dist/v0.10.42/node.lib', libPath: 'node.lib' }, - x64: { libUrl: 'https://nodejs.org/dist/v0.10.42/x64/node.lib', libPath: 'x64/node.lib' }, - arm64: { libUrl: 'https://nodejs.org/dist/v0.10.42/arm64/node.lib', libPath: 'arm64/node.lib' } + // has -headers.tar.gz + it('test process release - process.release ~ node@0.10.42', function () { + var release = processRelease([], { opts: {} }, 'v0.10.42', null) + + assert.strictEqual(release.semver.version, '0.10.42') + delete release.semver + + assert.deepStrictEqual(release, { + version: '0.10.42', + name: 'node', + baseUrl: 'https://nodejs.org/dist/v0.10.42/', + tarballUrl: 'https://nodejs.org/dist/v0.10.42/node-v0.10.42-headers.tar.gz', + shasumsUrl: 'https://nodejs.org/dist/v0.10.42/SHASUMS256.txt', + versionDir: '0.10.42', + ia32: { libUrl: 'https://nodejs.org/dist/v0.10.42/node.lib', libPath: 'node.lib' }, + x64: { libUrl: 'https://nodejs.org/dist/v0.10.42/x64/node.lib', libPath: 'x64/node.lib' }, + arm64: { libUrl: 'https://nodejs.org/dist/v0.10.42/arm64/node.lib', libPath: 'arm64/node.lib' } + }) }) -}) -// has -headers.tar.gz -test('test process release - process.release ~ node@0.12.10', function (t) { - t.plan(2) - - var release = processRelease([], { opts: {} }, 'v0.12.10', null) - - t.equal(release.semver.version, '0.12.10') - delete release.semver - - t.deepEqual(release, { - version: '0.12.10', - name: 'node', - baseUrl: 'https://nodejs.org/dist/v0.12.10/', - tarballUrl: 'https://nodejs.org/dist/v0.12.10/node-v0.12.10-headers.tar.gz', - shasumsUrl: 'https://nodejs.org/dist/v0.12.10/SHASUMS256.txt', - versionDir: '0.12.10', - ia32: { libUrl: 'https://nodejs.org/dist/v0.12.10/node.lib', libPath: 'node.lib' }, - x64: { libUrl: 'https://nodejs.org/dist/v0.12.10/x64/node.lib', libPath: 'x64/node.lib' }, - arm64: { libUrl: 'https://nodejs.org/dist/v0.12.10/arm64/node.lib', libPath: 'arm64/node.lib' } + // has -headers.tar.gz + it('test process release - process.release ~ node@0.12.10', function () { + var release = processRelease([], { opts: {} }, 'v0.12.10', null) + + assert.strictEqual(release.semver.version, '0.12.10') + delete release.semver + + assert.deepStrictEqual(release, { + version: '0.12.10', + name: 'node', + baseUrl: 'https://nodejs.org/dist/v0.12.10/', + tarballUrl: 'https://nodejs.org/dist/v0.12.10/node-v0.12.10-headers.tar.gz', + shasumsUrl: 'https://nodejs.org/dist/v0.12.10/SHASUMS256.txt', + versionDir: '0.12.10', + ia32: { libUrl: 'https://nodejs.org/dist/v0.12.10/node.lib', libPath: 'node.lib' }, + x64: { libUrl: 'https://nodejs.org/dist/v0.12.10/x64/node.lib', libPath: 'x64/node.lib' }, + arm64: { libUrl: 'https://nodejs.org/dist/v0.12.10/arm64/node.lib', libPath: 'arm64/node.lib' } + }) }) -}) -test('test process release - process.release ~ node@4.1.23', function (t) { - t.plan(2) - - var release = processRelease([], { opts: {} }, 'v4.1.23', { - name: 'node', - headersUrl: 'https://nodejs.org/dist/v4.1.23/node-v4.1.23-headers.tar.gz' + it('test process release - process.release ~ node@4.1.23', function () { + var release = processRelease([], { opts: {} }, 'v4.1.23', { + name: 'node', + headersUrl: 'https://nodejs.org/dist/v4.1.23/node-v4.1.23-headers.tar.gz' + }) + + assert.strictEqual(release.semver.version, '4.1.23') + delete release.semver + + assert.deepStrictEqual(release, { + version: '4.1.23', + name: 'node', + baseUrl: 'https://nodejs.org/dist/v4.1.23/', + tarballUrl: 'https://nodejs.org/dist/v4.1.23/node-v4.1.23-headers.tar.gz', + shasumsUrl: 'https://nodejs.org/dist/v4.1.23/SHASUMS256.txt', + versionDir: '4.1.23', + ia32: { libUrl: 'https://nodejs.org/dist/v4.1.23/win-x86/node.lib', libPath: 'win-x86/node.lib' }, + x64: { libUrl: 'https://nodejs.org/dist/v4.1.23/win-x64/node.lib', libPath: 'win-x64/node.lib' }, + arm64: { libUrl: 'https://nodejs.org/dist/v4.1.23/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } + }) }) - t.equal(release.semver.version, '4.1.23') - delete release.semver - - t.deepEqual(release, { - version: '4.1.23', - name: 'node', - baseUrl: 'https://nodejs.org/dist/v4.1.23/', - tarballUrl: 'https://nodejs.org/dist/v4.1.23/node-v4.1.23-headers.tar.gz', - shasumsUrl: 'https://nodejs.org/dist/v4.1.23/SHASUMS256.txt', - versionDir: '4.1.23', - ia32: { libUrl: 'https://nodejs.org/dist/v4.1.23/win-x86/node.lib', libPath: 'win-x86/node.lib' }, - x64: { libUrl: 'https://nodejs.org/dist/v4.1.23/win-x64/node.lib', libPath: 'win-x64/node.lib' }, - arm64: { libUrl: 'https://nodejs.org/dist/v4.1.23/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } + it('test process release - process.release ~ node@4.1.23 / corp build', function () { + var release = processRelease([], { opts: {} }, 'v4.1.23', { + name: 'node', + headersUrl: 'https://some.custom.location/node-v4.1.23-headers.tar.gz' + }) + + assert.strictEqual(release.semver.version, '4.1.23') + delete release.semver + + assert.deepStrictEqual(release, { + version: '4.1.23', + name: 'node', + baseUrl: 'https://some.custom.location/', + tarballUrl: 'https://some.custom.location/node-v4.1.23-headers.tar.gz', + shasumsUrl: 'https://some.custom.location/SHASUMS256.txt', + versionDir: '4.1.23', + ia32: { libUrl: 'https://some.custom.location/win-x86/node.lib', libPath: 'win-x86/node.lib' }, + x64: { libUrl: 'https://some.custom.location/win-x64/node.lib', libPath: 'win-x64/node.lib' }, + arm64: { libUrl: 'https://some.custom.location/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } + }) }) -}) -test('test process release - process.release ~ node@4.1.23 / corp build', function (t) { - t.plan(2) - - var release = processRelease([], { opts: {} }, 'v4.1.23', { - name: 'node', - headersUrl: 'https://some.custom.location/node-v4.1.23-headers.tar.gz' + it('test process release - process.release ~ node@12.8.0 Windows', function () { + var release = processRelease([], { opts: {} }, 'v12.8.0', { + name: 'node', + sourceUrl: 'https://nodejs.org/download/release/v12.8.0/node-v12.8.0.tar.gz', + headersUrl: 'https://nodejs.org/download/release/v12.8.0/node-v12.8.0-headers.tar.gz', + libUrl: 'https://nodejs.org/download/release/v12.8.0/win-x64/node.lib' + }) + + assert.strictEqual(release.semver.version, '12.8.0') + delete release.semver + + assert.deepStrictEqual(release, { + version: '12.8.0', + name: 'node', + baseUrl: 'https://nodejs.org/download/release/v12.8.0/', + tarballUrl: 'https://nodejs.org/download/release/v12.8.0/node-v12.8.0-headers.tar.gz', + shasumsUrl: 'https://nodejs.org/download/release/v12.8.0/SHASUMS256.txt', + versionDir: '12.8.0', + ia32: { libUrl: 'https://nodejs.org/download/release/v12.8.0/win-x86/node.lib', libPath: 'win-x86/node.lib' }, + x64: { libUrl: 'https://nodejs.org/download/release/v12.8.0/win-x64/node.lib', libPath: 'win-x64/node.lib' }, + arm64: { libUrl: 'https://nodejs.org/download/release/v12.8.0/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } + }) }) - t.equal(release.semver.version, '4.1.23') - delete release.semver - - t.deepEqual(release, { - version: '4.1.23', - name: 'node', - baseUrl: 'https://some.custom.location/', - tarballUrl: 'https://some.custom.location/node-v4.1.23-headers.tar.gz', - shasumsUrl: 'https://some.custom.location/SHASUMS256.txt', - versionDir: '4.1.23', - ia32: { libUrl: 'https://some.custom.location/win-x86/node.lib', libPath: 'win-x86/node.lib' }, - x64: { libUrl: 'https://some.custom.location/win-x64/node.lib', libPath: 'win-x64/node.lib' }, - arm64: { libUrl: 'https://some.custom.location/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } + it('test process release - process.release ~ node@12.8.0 Windows ARM64', function () { + var release = processRelease([], { opts: {} }, 'v12.8.0', { + name: 'node', + sourceUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/node-v12.8.0.tar.gz', + headersUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/node-v12.8.0-headers.tar.gz', + libUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/win-arm64/node.lib' + }) + + assert.strictEqual(release.semver.version, '12.8.0') + delete release.semver + + assert.deepStrictEqual(release, { + version: '12.8.0', + name: 'node', + baseUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/', + tarballUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/node-v12.8.0-headers.tar.gz', + shasumsUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/SHASUMS256.txt', + versionDir: '12.8.0', + ia32: { libUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/win-x86/node.lib', libPath: 'win-x86/node.lib' }, + x64: { libUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/win-x64/node.lib', libPath: 'win-x64/node.lib' }, + arm64: { libUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } + }) }) -}) -test('test process release - process.release ~ node@12.8.0 Windows', function (t) { - t.plan(2) - - var release = processRelease([], { opts: {} }, 'v12.8.0', { - name: 'node', - sourceUrl: 'https://nodejs.org/download/release/v12.8.0/node-v12.8.0.tar.gz', - headersUrl: 'https://nodejs.org/download/release/v12.8.0/node-v12.8.0-headers.tar.gz', - libUrl: 'https://nodejs.org/download/release/v12.8.0/win-x64/node.lib' - }) - - t.equal(release.semver.version, '12.8.0') - delete release.semver - - t.deepEqual(release, { - version: '12.8.0', - name: 'node', - baseUrl: 'https://nodejs.org/download/release/v12.8.0/', - tarballUrl: 'https://nodejs.org/download/release/v12.8.0/node-v12.8.0-headers.tar.gz', - shasumsUrl: 'https://nodejs.org/download/release/v12.8.0/SHASUMS256.txt', - versionDir: '12.8.0', - ia32: { libUrl: 'https://nodejs.org/download/release/v12.8.0/win-x86/node.lib', libPath: 'win-x86/node.lib' }, - x64: { libUrl: 'https://nodejs.org/download/release/v12.8.0/win-x64/node.lib', libPath: 'win-x64/node.lib' }, - arm64: { libUrl: 'https://nodejs.org/download/release/v12.8.0/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } + it('test process release - process.release ~ node@4.1.23 --target=0.10.40', function () { + var release = processRelease([], { opts: { target: '0.10.40' } }, 'v4.1.23', { + name: 'node', + headersUrl: 'https://nodejs.org/dist/v4.1.23/node-v4.1.23-headers.tar.gz' + }) + + assert.strictEqual(release.semver.version, '0.10.40') + delete release.semver + + assert.deepStrictEqual(release, { + version: '0.10.40', + name: 'node', + baseUrl: 'https://nodejs.org/dist/v0.10.40/', + tarballUrl: 'https://nodejs.org/dist/v0.10.40/node-v0.10.40.tar.gz', + shasumsUrl: 'https://nodejs.org/dist/v0.10.40/SHASUMS256.txt', + versionDir: '0.10.40', + ia32: { libUrl: 'https://nodejs.org/dist/v0.10.40/node.lib', libPath: 'node.lib' }, + x64: { libUrl: 'https://nodejs.org/dist/v0.10.40/x64/node.lib', libPath: 'x64/node.lib' }, + arm64: { libUrl: 'https://nodejs.org/dist/v0.10.40/arm64/node.lib', libPath: 'arm64/node.lib' } + }) }) -}) -test('test process release - process.release ~ node@12.8.0 Windows ARM64', function (t) { - t.plan(2) - - var release = processRelease([], { opts: {} }, 'v12.8.0', { - name: 'node', - sourceUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/node-v12.8.0.tar.gz', - headersUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/node-v12.8.0-headers.tar.gz', - libUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/win-arm64/node.lib' + it('test process release - process.release ~ node@4.1.23 --dist-url=https://foo.bar/baz', function () { + var release = processRelease([], { opts: { 'dist-url': 'https://foo.bar/baz' } }, 'v4.1.23', { + name: 'node', + headersUrl: 'https://nodejs.org/dist/v4.1.23/node-v4.1.23-headers.tar.gz' + }) + + assert.strictEqual(release.semver.version, '4.1.23') + delete release.semver + + assert.deepStrictEqual(release, { + version: '4.1.23', + name: 'node', + baseUrl: 'https://foo.bar/baz/v4.1.23/', + tarballUrl: 'https://foo.bar/baz/v4.1.23/node-v4.1.23-headers.tar.gz', + shasumsUrl: 'https://foo.bar/baz/v4.1.23/SHASUMS256.txt', + versionDir: '4.1.23', + ia32: { libUrl: 'https://foo.bar/baz/v4.1.23/win-x86/node.lib', libPath: 'win-x86/node.lib' }, + x64: { libUrl: 'https://foo.bar/baz/v4.1.23/win-x64/node.lib', libPath: 'win-x64/node.lib' }, + arm64: { libUrl: 'https://foo.bar/baz/v4.1.23/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } + }) }) - t.equal(release.semver.version, '12.8.0') - delete release.semver - - t.deepEqual(release, { - version: '12.8.0', - name: 'node', - baseUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/', - tarballUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/node-v12.8.0-headers.tar.gz', - shasumsUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/SHASUMS256.txt', - versionDir: '12.8.0', - ia32: { libUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/win-x86/node.lib', libPath: 'win-x86/node.lib' }, - x64: { libUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/win-x64/node.lib', libPath: 'win-x64/node.lib' }, - arm64: { libUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } + it('test process release - process.release ~ frankenstein@4.1.23', function () { + var release = processRelease([], { opts: {} }, 'v4.1.23', { + name: 'frankenstein', + headersUrl: 'https://frankensteinjs.org/dist/v4.1.23/frankenstein-v4.1.23-headers.tar.gz' + }) + + assert.strictEqual(release.semver.version, '4.1.23') + delete release.semver + + assert.deepStrictEqual(release, { + version: '4.1.23', + name: 'frankenstein', + baseUrl: 'https://frankensteinjs.org/dist/v4.1.23/', + tarballUrl: 'https://frankensteinjs.org/dist/v4.1.23/frankenstein-v4.1.23-headers.tar.gz', + shasumsUrl: 'https://frankensteinjs.org/dist/v4.1.23/SHASUMS256.txt', + versionDir: 'frankenstein-4.1.23', + ia32: { libUrl: 'https://frankensteinjs.org/dist/v4.1.23/win-x86/frankenstein.lib', libPath: 'win-x86/frankenstein.lib' }, + x64: { libUrl: 'https://frankensteinjs.org/dist/v4.1.23/win-x64/frankenstein.lib', libPath: 'win-x64/frankenstein.lib' }, + arm64: { libUrl: 'https://frankensteinjs.org/dist/v4.1.23/win-arm64/frankenstein.lib', libPath: 'win-arm64/frankenstein.lib' } + }) }) -}) -test('test process release - process.release ~ node@4.1.23 --target=0.10.40', function (t) { - t.plan(2) - - var release = processRelease([], { opts: { target: '0.10.40' } }, 'v4.1.23', { - name: 'node', - headersUrl: 'https://nodejs.org/dist/v4.1.23/node-v4.1.23-headers.tar.gz' + it('test process release - process.release ~ frankenstein@4.1.23 --dist-url=http://foo.bar/baz/', function () { + var release = processRelease([], { opts: { 'dist-url': 'http://foo.bar/baz/' } }, 'v4.1.23', { + name: 'frankenstein', + headersUrl: 'https://frankensteinjs.org/dist/v4.1.23/frankenstein-v4.1.23.tar.gz' + }) + + assert.strictEqual(release.semver.version, '4.1.23') + delete release.semver + + assert.deepStrictEqual(release, { + version: '4.1.23', + name: 'frankenstein', + baseUrl: 'http://foo.bar/baz/v4.1.23/', + tarballUrl: 'http://foo.bar/baz/v4.1.23/frankenstein-v4.1.23-headers.tar.gz', + shasumsUrl: 'http://foo.bar/baz/v4.1.23/SHASUMS256.txt', + versionDir: 'frankenstein-4.1.23', + ia32: { libUrl: 'http://foo.bar/baz/v4.1.23/win-x86/frankenstein.lib', libPath: 'win-x86/frankenstein.lib' }, + x64: { libUrl: 'http://foo.bar/baz/v4.1.23/win-x64/frankenstein.lib', libPath: 'win-x64/frankenstein.lib' }, + arm64: { libUrl: 'http://foo.bar/baz/v4.1.23/win-arm64/frankenstein.lib', libPath: 'win-arm64/frankenstein.lib' } + }) }) - t.equal(release.semver.version, '0.10.40') - delete release.semver - - t.deepEqual(release, { - version: '0.10.40', - name: 'node', - baseUrl: 'https://nodejs.org/dist/v0.10.40/', - tarballUrl: 'https://nodejs.org/dist/v0.10.40/node-v0.10.40.tar.gz', - shasumsUrl: 'https://nodejs.org/dist/v0.10.40/SHASUMS256.txt', - versionDir: '0.10.40', - ia32: { libUrl: 'https://nodejs.org/dist/v0.10.40/node.lib', libPath: 'node.lib' }, - x64: { libUrl: 'https://nodejs.org/dist/v0.10.40/x64/node.lib', libPath: 'x64/node.lib' }, - arm64: { libUrl: 'https://nodejs.org/dist/v0.10.40/arm64/node.lib', libPath: 'arm64/node.lib' } + it('test process release - process.release ~ node@4.0.0-rc.4', function () { + var release = processRelease([], { opts: {} }, 'v4.0.0-rc.4', { + name: 'node', + headersUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/node-v4.0.0-rc.4-headers.tar.gz' + }) + + assert.strictEqual(release.semver.version, '4.0.0-rc.4') + delete release.semver + + assert.deepStrictEqual(release, { + version: '4.0.0-rc.4', + name: 'node', + baseUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/', + tarballUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/node-v4.0.0-rc.4-headers.tar.gz', + shasumsUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/SHASUMS256.txt', + versionDir: '4.0.0-rc.4', + ia32: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-x86/node.lib', libPath: 'win-x86/node.lib' }, + x64: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-x64/node.lib', libPath: 'win-x64/node.lib' }, + arm64: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } + }) }) -}) - -test('test process release - process.release ~ node@4.1.23 --dist-url=https://foo.bar/baz', function (t) { - t.plan(2) - - var release = processRelease([], { opts: { 'dist-url': 'https://foo.bar/baz' } }, 'v4.1.23', { - name: 'node', - headersUrl: 'https://nodejs.org/dist/v4.1.23/node-v4.1.23-headers.tar.gz' - }) - - t.equal(release.semver.version, '4.1.23') - delete release.semver - - t.deepEqual(release, { - version: '4.1.23', - name: 'node', - baseUrl: 'https://foo.bar/baz/v4.1.23/', - tarballUrl: 'https://foo.bar/baz/v4.1.23/node-v4.1.23-headers.tar.gz', - shasumsUrl: 'https://foo.bar/baz/v4.1.23/SHASUMS256.txt', - versionDir: '4.1.23', - ia32: { libUrl: 'https://foo.bar/baz/v4.1.23/win-x86/node.lib', libPath: 'win-x86/node.lib' }, - x64: { libUrl: 'https://foo.bar/baz/v4.1.23/win-x64/node.lib', libPath: 'win-x64/node.lib' }, - arm64: { libUrl: 'https://foo.bar/baz/v4.1.23/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } - }) -}) - -test('test process release - process.release ~ frankenstein@4.1.23', function (t) { - t.plan(2) - - var release = processRelease([], { opts: {} }, 'v4.1.23', { - name: 'frankenstein', - headersUrl: 'https://frankensteinjs.org/dist/v4.1.23/frankenstein-v4.1.23-headers.tar.gz' - }) - - t.equal(release.semver.version, '4.1.23') - delete release.semver - - t.deepEqual(release, { - version: '4.1.23', - name: 'frankenstein', - baseUrl: 'https://frankensteinjs.org/dist/v4.1.23/', - tarballUrl: 'https://frankensteinjs.org/dist/v4.1.23/frankenstein-v4.1.23-headers.tar.gz', - shasumsUrl: 'https://frankensteinjs.org/dist/v4.1.23/SHASUMS256.txt', - versionDir: 'frankenstein-4.1.23', - ia32: { libUrl: 'https://frankensteinjs.org/dist/v4.1.23/win-x86/frankenstein.lib', libPath: 'win-x86/frankenstein.lib' }, - x64: { libUrl: 'https://frankensteinjs.org/dist/v4.1.23/win-x64/frankenstein.lib', libPath: 'win-x64/frankenstein.lib' }, - arm64: { libUrl: 'https://frankensteinjs.org/dist/v4.1.23/win-arm64/frankenstein.lib', libPath: 'win-arm64/frankenstein.lib' } - }) -}) - -test('test process release - process.release ~ frankenstein@4.1.23 --dist-url=http://foo.bar/baz/', function (t) { - t.plan(2) - - var release = processRelease([], { opts: { 'dist-url': 'http://foo.bar/baz/' } }, 'v4.1.23', { - name: 'frankenstein', - headersUrl: 'https://frankensteinjs.org/dist/v4.1.23/frankenstein-v4.1.23.tar.gz' - }) - - t.equal(release.semver.version, '4.1.23') - delete release.semver - - t.deepEqual(release, { - version: '4.1.23', - name: 'frankenstein', - baseUrl: 'http://foo.bar/baz/v4.1.23/', - tarballUrl: 'http://foo.bar/baz/v4.1.23/frankenstein-v4.1.23-headers.tar.gz', - shasumsUrl: 'http://foo.bar/baz/v4.1.23/SHASUMS256.txt', - versionDir: 'frankenstein-4.1.23', - ia32: { libUrl: 'http://foo.bar/baz/v4.1.23/win-x86/frankenstein.lib', libPath: 'win-x86/frankenstein.lib' }, - x64: { libUrl: 'http://foo.bar/baz/v4.1.23/win-x64/frankenstein.lib', libPath: 'win-x64/frankenstein.lib' }, - arm64: { libUrl: 'http://foo.bar/baz/v4.1.23/win-arm64/frankenstein.lib', libPath: 'win-arm64/frankenstein.lib' } - }) -}) - -test('test process release - process.release ~ node@4.0.0-rc.4', function (t) { - t.plan(2) - - var release = processRelease([], { opts: {} }, 'v4.0.0-rc.4', { - name: 'node', - headersUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/node-v4.0.0-rc.4-headers.tar.gz' - }) - - t.equal(release.semver.version, '4.0.0-rc.4') - delete release.semver - - t.deepEqual(release, { - version: '4.0.0-rc.4', - name: 'node', - baseUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/', - tarballUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/node-v4.0.0-rc.4-headers.tar.gz', - shasumsUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/SHASUMS256.txt', - versionDir: '4.0.0-rc.4', - ia32: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-x86/node.lib', libPath: 'win-x86/node.lib' }, - x64: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-x64/node.lib', libPath: 'win-x64/node.lib' }, - arm64: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } - }) -}) - -test('test process release - process.release ~ node@4.0.0-rc.4 passed as argv[0]', function (t) { - t.plan(2) + it('test process release - process.release ~ node@4.0.0-rc.4 passed as argv[0]', function () { // note the missing 'v' on the arg, it should normalise when checking - // whether we're on the default or not - var release = processRelease(['4.0.0-rc.4'], { opts: {} }, 'v4.0.0-rc.4', { - name: 'node', - headersUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/node-v4.0.0-rc.4-headers.tar.gz' - }) - - t.equal(release.semver.version, '4.0.0-rc.4') - delete release.semver - - t.deepEqual(release, { - version: '4.0.0-rc.4', - name: 'node', - baseUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/', - tarballUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/node-v4.0.0-rc.4-headers.tar.gz', - shasumsUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/SHASUMS256.txt', - versionDir: '4.0.0-rc.4', - ia32: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-x86/node.lib', libPath: 'win-x86/node.lib' }, - x64: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-x64/node.lib', libPath: 'win-x64/node.lib' }, - arm64: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } + // whether we're on the default or not + var release = processRelease(['4.0.0-rc.4'], { opts: {} }, 'v4.0.0-rc.4', { + name: 'node', + headersUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/node-v4.0.0-rc.4-headers.tar.gz' + }) + + assert.strictEqual(release.semver.version, '4.0.0-rc.4') + delete release.semver + + assert.deepStrictEqual(release, { + version: '4.0.0-rc.4', + name: 'node', + baseUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/', + tarballUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/node-v4.0.0-rc.4-headers.tar.gz', + shasumsUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/SHASUMS256.txt', + versionDir: '4.0.0-rc.4', + ia32: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-x86/node.lib', libPath: 'win-x86/node.lib' }, + x64: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-x64/node.lib', libPath: 'win-x64/node.lib' }, + arm64: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } + }) }) -}) - -test('test process release - process.release ~ node@4.0.0-rc.4 - bogus string passed as argv[0]', function (t) { - t.plan(2) + it('test process release - process.release ~ node@4.0.0-rc.4 - bogus string passed as argv[0]', function () { // additional arguments can be passed in on the commandline that should be ignored if they - // are not specifying a valid version @ position 0 - var release = processRelease(['this is no version!'], { opts: {} }, 'v4.0.0-rc.4', { - name: 'node', - headersUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/node-v4.0.0-rc.4-headers.tar.gz' + // are not specifying a valid version @ position 0 + var release = processRelease(['this is no version!'], { opts: {} }, 'v4.0.0-rc.4', { + name: 'node', + headersUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/node-v4.0.0-rc.4-headers.tar.gz' + }) + + assert.strictEqual(release.semver.version, '4.0.0-rc.4') + delete release.semver + + assert.deepStrictEqual(release, { + version: '4.0.0-rc.4', + name: 'node', + baseUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/', + tarballUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/node-v4.0.0-rc.4-headers.tar.gz', + shasumsUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/SHASUMS256.txt', + versionDir: '4.0.0-rc.4', + ia32: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-x86/node.lib', libPath: 'win-x86/node.lib' }, + x64: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-x64/node.lib', libPath: 'win-x64/node.lib' }, + arm64: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } + }) }) - t.equal(release.semver.version, '4.0.0-rc.4') - delete release.semver - - t.deepEqual(release, { - version: '4.0.0-rc.4', - name: 'node', - baseUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/', - tarballUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/node-v4.0.0-rc.4-headers.tar.gz', - shasumsUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/SHASUMS256.txt', - versionDir: '4.0.0-rc.4', - ia32: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-x86/node.lib', libPath: 'win-x86/node.lib' }, - x64: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-x64/node.lib', libPath: 'win-x64/node.lib' }, - arm64: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } + it('test process release - NODEJS_ORG_MIRROR', function () { + process.env.NODEJS_ORG_MIRROR = 'http://foo.bar' + + var release = processRelease([], { opts: {} }, 'v4.1.23', { + name: 'node', + headersUrl: 'https://nodejs.org/dist/v4.1.23/node-v4.1.23-headers.tar.gz' + }) + + assert.strictEqual(release.semver.version, '4.1.23') + delete release.semver + + assert.deepStrictEqual(release, { + version: '4.1.23', + name: 'node', + baseUrl: 'http://foo.bar/v4.1.23/', + tarballUrl: 'http://foo.bar/v4.1.23/node-v4.1.23-headers.tar.gz', + shasumsUrl: 'http://foo.bar/v4.1.23/SHASUMS256.txt', + versionDir: '4.1.23', + ia32: { libUrl: 'http://foo.bar/v4.1.23/win-x86/node.lib', libPath: 'win-x86/node.lib' }, + x64: { libUrl: 'http://foo.bar/v4.1.23/win-x64/node.lib', libPath: 'win-x64/node.lib' }, + arm64: { libUrl: 'http://foo.bar/v4.1.23/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } + }) + + delete process.env.NODEJS_ORG_MIRROR }) }) - -test('test process release - NODEJS_ORG_MIRROR', function (t) { - t.plan(2) - - process.env.NODEJS_ORG_MIRROR = 'http://foo.bar' - - var release = processRelease([], { opts: {} }, 'v4.1.23', { - name: 'node', - headersUrl: 'https://nodejs.org/dist/v4.1.23/node-v4.1.23-headers.tar.gz' - }) - - t.equal(release.semver.version, '4.1.23') - delete release.semver - - t.deepEqual(release, { - version: '4.1.23', - name: 'node', - baseUrl: 'http://foo.bar/v4.1.23/', - tarballUrl: 'http://foo.bar/v4.1.23/node-v4.1.23-headers.tar.gz', - shasumsUrl: 'http://foo.bar/v4.1.23/SHASUMS256.txt', - versionDir: '4.1.23', - ia32: { libUrl: 'http://foo.bar/v4.1.23/win-x86/node.lib', libPath: 'win-x86/node.lib' }, - x64: { libUrl: 'http://foo.bar/v4.1.23/win-x64/node.lib', libPath: 'win-x64/node.lib' }, - arm64: { libUrl: 'http://foo.bar/v4.1.23/win-arm64/node.lib', libPath: 'win-arm64/node.lib' } - }) - - delete process.env.NODEJS_ORG_MIRROR -}) diff --git a/node_modules/node-gyp/update-gyp.py b/node_modules/node-gyp/update-gyp.py index 19524bd6a7ad1..70e2d100288ec 100755 --- a/node_modules/node-gyp/update-gyp.py +++ b/node_modules/node-gyp/update-gyp.py @@ -49,7 +49,7 @@ def safe_extract(tar, path=".", members=None, *, numeric_owner=False): if not is_within_directory(path, member_path): raise Exception("Attempted Path Traversal in Tar File") - tar.extractall(path, members, numeric_owner) + tar.extractall(path, members, numeric_owner=numeric_owner) safe_extract(tar_ref, unzip_target) diff --git a/node_modules/nopt/bin/nopt.js b/node_modules/nopt/bin/nopt.js index bb04291c607ac..6ed2082064b5e 100755 --- a/node_modules/nopt/bin/nopt.js +++ b/node_modules/nopt/bin/nopt.js @@ -1,7 +1,8 @@ #!/usr/bin/env node -var nopt = require('../lib/nopt') -var path = require('path') -var types = { num: Number, +const nopt = require('../lib/nopt') +const path = require('path') +console.log('parsed', nopt({ + num: Number, bool: Boolean, help: Boolean, list: Array, @@ -13,8 +14,8 @@ var types = { num: Number, config: Boolean, length: Number, file: path, -} -var shorthands = { s: ['--str', 'astring'], +}, { + s: ['--str', 'astring'], b: ['--bool'], nb: ['--no-bool'], tft: ['--bool-list', '--no-bool-list', '--bool-list', 'true'], @@ -25,32 +26,4 @@ var shorthands = { s: ['--str', 'astring'], c: ['--config'], l: ['--length'], f: ['--file'], -} -var parsed = nopt(types - , shorthands - , process.argv - , 2) - -console.log('parsed', parsed) - -if (parsed.help) { - console.log('') - console.log('nopt cli tester') - console.log('') - console.log('types') - console.log(Object.keys(types).map(function M (t) { - var type = types[t] - if (Array.isArray(type)) { - return [t, type.map(function (mappedType) { - return mappedType.name - })] - } - return [t, type && type.name] - }).reduce(function (s, i) { - s[i[0]] = i[1] - return s - }, {})) - console.log('') - console.log('shorthands') - console.log(shorthands) -} +}, process.argv, 2)) diff --git a/node_modules/nopt/lib/debug.js b/node_modules/nopt/lib/debug.js index 194d0c6881882..e62198eb92e9a 100644 --- a/node_modules/nopt/lib/debug.js +++ b/node_modules/nopt/lib/debug.js @@ -1,6 +1,4 @@ /* istanbul ignore next */ module.exports = process.env.DEBUG_NOPT || process.env.NOPT_DEBUG - ? function () { - console.error.apply(console, arguments) - } - : function () {} + ? (...a) => console.error(...a) + : () => {} diff --git a/node_modules/nopt/lib/nopt-lib.js b/node_modules/nopt/lib/nopt-lib.js index 89d269fb43f1a..d3d1de0255ba9 100644 --- a/node_modules/nopt/lib/nopt-lib.js +++ b/node_modules/nopt/lib/nopt-lib.js @@ -1,21 +1,47 @@ -var abbrev = require('abbrev') +const abbrev = require('abbrev') const debug = require('./debug') const defaultTypeDefs = require('./type-defs') -function nopt (args, { types, shorthands, typeDefs, invalidHandler }) { +const hasOwn = (o, k) => Object.prototype.hasOwnProperty.call(o, k) + +const getType = (k, { types, dynamicTypes }) => { + let hasType = hasOwn(types, k) + let type = types[k] + if (!hasType && typeof dynamicTypes === 'function') { + const matchedType = dynamicTypes(k) + if (matchedType !== undefined) { + type = matchedType + hasType = true + } + } + return [hasType, type] +} + +const isTypeDef = (type, def) => def && type === def +const hasTypeDef = (type, def) => def && type.indexOf(def) !== -1 +const doesNotHaveTypeDef = (type, def) => def && !hasTypeDef(type, def) + +function nopt (args, { + types, + shorthands, + typeDefs, + invalidHandler, + typeDefault, + dynamicTypes, +} = {}) { debug(types, shorthands, args, typeDefs) - var data = {} - var argv = { + const data = {} + const argv = { remain: [], cooked: args, original: args.slice(0), } - parse(args, data, argv.remain, { typeDefs, types, shorthands }) + parse(args, data, argv.remain, { typeDefs, types, dynamicTypes, shorthands }) // now data is full - clean(data, { types, typeDefs, invalidHandler }) + clean(data, { types, dynamicTypes, typeDefs, invalidHandler, typeDefault }) data.argv = argv Object.defineProperty(data.argv, 'toString', { @@ -28,30 +54,48 @@ function nopt (args, { types, shorthands, typeDefs, invalidHandler }) { return data } -function clean (data, { types, typeDefs, invalidHandler }) { - const StringType = typeDefs.String.type - const NumberType = typeDefs.Number.type - const ArrayType = typeDefs.Array.type - const BooleanType = typeDefs.Boolean.type - const DateType = typeDefs.Date.type +function clean (data, { + types = {}, + typeDefs = {}, + dynamicTypes, + invalidHandler, + typeDefault, +} = {}) { + const StringType = typeDefs.String?.type + const NumberType = typeDefs.Number?.type + const ArrayType = typeDefs.Array?.type + const BooleanType = typeDefs.Boolean?.type + const DateType = typeDefs.Date?.type + + const hasTypeDefault = typeof typeDefault !== 'undefined' + if (!hasTypeDefault) { + typeDefault = [false, true, null] + if (StringType) { + typeDefault.push(StringType) + } + if (ArrayType) { + typeDefault.push(ArrayType) + } + } - var remove = {} - var typeDefault = [false, true, null, StringType, ArrayType] + const remove = {} - Object.keys(data).forEach(function (k) { + Object.keys(data).forEach((k) => { if (k === 'argv') { return } - var val = data[k] - var isArray = Array.isArray(val) - var type = types[k] + let val = data[k] + debug('val=%j', val) + const isArray = Array.isArray(val) + let [hasType, rawType] = getType(k, { types, dynamicTypes }) + let type = rawType if (!isArray) { val = [val] } if (!type) { type = typeDefault } - if (type === ArrayType) { + if (isTypeDef(type, ArrayType)) { type = typeDefault.concat(ArrayType) } if (!Array.isArray(type)) { @@ -60,57 +104,62 @@ function clean (data, { types, typeDefs, invalidHandler }) { debug('val=%j', val) debug('types=', type) - val = val.map(function (v) { + val = val.map((v) => { // if it's an unknown value, then parse false/true/null/numbers/dates if (typeof v === 'string') { debug('string %j', v) v = v.trim() if ((v === 'null' && ~type.indexOf(null)) || (v === 'true' && - (~type.indexOf(true) || ~type.indexOf(BooleanType))) + (~type.indexOf(true) || hasTypeDef(type, BooleanType))) || (v === 'false' && - (~type.indexOf(false) || ~type.indexOf(BooleanType)))) { + (~type.indexOf(false) || hasTypeDef(type, BooleanType)))) { v = JSON.parse(v) debug('jsonable %j', v) - } else if (~type.indexOf(NumberType) && !isNaN(v)) { + } else if (hasTypeDef(type, NumberType) && !isNaN(v)) { debug('convert to number', v) v = +v - } else if (~type.indexOf(DateType) && !isNaN(Date.parse(v))) { + } else if (hasTypeDef(type, DateType) && !isNaN(Date.parse(v))) { debug('convert to date', v) v = new Date(v) } } - if (!Object.prototype.hasOwnProperty.call(types, k)) { - return v + if (!hasType) { + if (!hasTypeDefault) { + return v + } + // if the default type has been passed in then we want to validate the + // unknown data key instead of bailing out earlier. we also set the raw + // type which is passed to the invalid handler so that it can be + // determined if during validation if it is unknown vs invalid + rawType = typeDefault } // allow `--no-blah` to set 'blah' to null if null is allowed if (v === false && ~type.indexOf(null) && - !(~type.indexOf(false) || ~type.indexOf(BooleanType))) { + !(~type.indexOf(false) || hasTypeDef(type, BooleanType))) { v = null } - var d = {} + const d = {} d[k] = v - debug('prevalidated val', d, v, types[k]) - if (!validate(d, k, v, types[k], { typeDefs })) { + debug('prevalidated val', d, v, rawType) + if (!validate(d, k, v, rawType, { typeDefs })) { if (invalidHandler) { - invalidHandler(k, v, types[k], data) + invalidHandler(k, v, rawType, data) } else if (invalidHandler !== false) { - debug('invalid: ' + k + '=' + v, types[k]) + debug('invalid: ' + k + '=' + v, rawType) } return remove } - debug('validated v', d, v, types[k]) + debug('validated v', d, v, rawType) return d[k] - }).filter(function (v) { - return v !== remove - }) + }).filter((v) => v !== remove) // if we allow Array specifically, then an empty array is how we // express 'no value here', not null. Allow it. - if (!val.length && type.indexOf(ArrayType) === -1) { + if (!val.length && doesNotHaveTypeDef(type, ArrayType)) { debug('VAL HAS NO LENGTH, DELETE IT', val, k, type.indexOf(ArrayType)) delete data[k] } else if (isArray) { @@ -124,12 +173,12 @@ function clean (data, { types, typeDefs, invalidHandler }) { }) } -function validate (data, k, val, type, { typeDefs }) { - const ArrayType = typeDefs.Array.type +function validate (data, k, val, type, { typeDefs } = {}) { + const ArrayType = typeDefs?.Array?.type // arrays are lists of types. if (Array.isArray(type)) { for (let i = 0, l = type.length; i < l; i++) { - if (type[i] === ArrayType) { + if (isTypeDef(type[i], ArrayType)) { continue } if (validate(data, k, val, type[i], { typeDefs })) { @@ -141,7 +190,7 @@ function validate (data, k, val, type, { typeDefs }) { } // an array of anything? - if (type === ArrayType) { + if (isTypeDef(type, ArrayType)) { return true } @@ -166,17 +215,17 @@ function validate (data, k, val, type, { typeDefs }) { } // now go through the list of typeDefs, validate against each one. - var ok = false - var types = Object.keys(typeDefs) + let ok = false + const types = Object.keys(typeDefs) for (let i = 0, l = types.length; i < l; i++) { debug('test type %j %j %j', k, val, types[i]) - var t = typeDefs[types[i]] + const t = typeDefs[types[i]] if (t && ( (type && type.name && t.type && t.type.name) ? (type.name === t.type.name) : (type === t.type) )) { - var d = {} + const d = {} ok = t.validate(d, k, val) !== false val = d[k] if (ok) { @@ -193,19 +242,25 @@ function validate (data, k, val, type, { typeDefs }) { return ok } -function parse (args, data, remain, { typeDefs, types, shorthands }) { - const StringType = typeDefs.String.type - const NumberType = typeDefs.String.type - const ArrayType = typeDefs.Array.type - const BooleanType = typeDefs.Boolean.type +function parse (args, data, remain, { + types = {}, + typeDefs = {}, + shorthands = {}, + dynamicTypes, +} = {}) { + const StringType = typeDefs.String?.type + const NumberType = typeDefs.Number?.type + const ArrayType = typeDefs.Array?.type + const BooleanType = typeDefs.Boolean?.type debug('parse', args, data, remain) - var abbrevs = abbrev(Object.keys(types)) - var shortAbbr = abbrev(Object.keys(shorthands)) + const abbrevs = abbrev(Object.keys(types)) + debug('abbrevs=%j', abbrevs) + const shortAbbr = abbrev(Object.keys(shorthands)) - for (var i = 0; i < args.length; i++) { - var arg = args[i] + for (let i = 0; i < args.length; i++) { + let arg = args[i] debug('arg', arg) if (arg.match(/^-{2,}$/)) { @@ -215,22 +270,21 @@ function parse (args, data, remain, { typeDefs, types, shorthands }) { args[i] = '--' break } - var hadEq = false + let hadEq = false if (arg.charAt(0) === '-' && arg.length > 1) { - var at = arg.indexOf('=') + const at = arg.indexOf('=') if (at > -1) { hadEq = true - var v = arg.slice(at + 1) + const v = arg.slice(at + 1) arg = arg.slice(0, at) args.splice(i, 1, arg, v) } // see if it's a shorthand // if so, splice and back up to re-parse it. - var shRes = resolveShort(arg, shortAbbr, abbrevs, { shorthands }) + const shRes = resolveShort(arg, shortAbbr, abbrevs, { shorthands }) debug('arg=%j shRes=%j', arg, shRes) if (shRes) { - debug(arg, shRes) args.splice.apply(args, [i, 1].concat(shRes)) if (arg !== shRes[0]) { i-- @@ -238,7 +292,7 @@ function parse (args, data, remain, { typeDefs, types, shorthands }) { } } arg = arg.replace(/^-+/, '') - var no = null + let no = null while (arg.toLowerCase().indexOf('no-') === 0) { no = !no arg = arg.slice(3) @@ -248,33 +302,30 @@ function parse (args, data, remain, { typeDefs, types, shorthands }) { arg = abbrevs[arg] } - var argType = types[arg] - var isTypeArray = Array.isArray(argType) + let [hasType, argType] = getType(arg, { types, dynamicTypes }) + let isTypeArray = Array.isArray(argType) if (isTypeArray && argType.length === 1) { isTypeArray = false argType = argType[0] } - var isArray = argType === ArrayType || - isTypeArray && argType.indexOf(ArrayType) !== -1 + let isArray = isTypeDef(argType, ArrayType) || + isTypeArray && hasTypeDef(argType, ArrayType) // allow unknown things to be arrays if specified multiple times. - if ( - !Object.prototype.hasOwnProperty.call(types, arg) && - Object.prototype.hasOwnProperty.call(data, arg) - ) { + if (!hasType && hasOwn(data, arg)) { if (!Array.isArray(data[arg])) { data[arg] = [data[arg]] } isArray = true } - var val - var la = args[i + 1] + let val + let la = args[i + 1] - var isBool = typeof no === 'boolean' || - argType === BooleanType || - isTypeArray && argType.indexOf(BooleanType) !== -1 || + const isBool = typeof no === 'boolean' || + isTypeDef(argType, BooleanType) || + isTypeArray && hasTypeDef(argType, BooleanType) || (typeof argType === 'undefined' && !hadEq) || (la === 'false' && (argType === null || @@ -305,11 +356,11 @@ function parse (args, data, remain, { typeDefs, types, shorthands }) { i++ } else if (!la.match(/^-{2,}[^-]/) && !isNaN(la) && - ~argType.indexOf(NumberType)) { + hasTypeDef(argType, NumberType)) { // number val = +la i++ - } else if (!la.match(/^-[^-]/) && ~argType.indexOf(StringType)) { + } else if (!la.match(/^-[^-]/) && hasTypeDef(argType, StringType)) { // string val = la i++ @@ -325,7 +376,7 @@ function parse (args, data, remain, { typeDefs, types, shorthands }) { continue } - if (argType === StringType) { + if (isTypeDef(argType, StringType)) { if (la === undefined) { la = '' } else if (la.match(/^-{1,2}[^-]+/)) { @@ -353,7 +404,26 @@ function parse (args, data, remain, { typeDefs, types, shorthands }) { } } -function resolveShort (arg, shortAbbr, abbrevs, { shorthands }) { +const SINGLES = Symbol('singles') +const singleCharacters = (arg, shorthands) => { + let singles = shorthands[SINGLES] + if (!singles) { + singles = Object.keys(shorthands).filter((s) => s.length === 1).reduce((l, r) => { + l[r] = true + return l + }, {}) + shorthands[SINGLES] = singles + debug('shorthand singles', singles) + } + const chrs = arg.split('').filter((c) => singles[c]) + return chrs.join('') === arg ? chrs : null +} + +function resolveShort (arg, ...rest) { + const { types = {}, shorthands = {} } = rest.length ? rest.pop() : {} + const shortAbbr = rest[0] ?? abbrev(Object.keys(shorthands)) + const abbrevs = rest[1] ?? abbrev(Object.keys(types)) + // handle single-char shorthands glommed together, like // npm ls -glp, but only if there is one dash, and only if // all of the chars are single-char shorthands, and it's @@ -376,28 +446,9 @@ function resolveShort (arg, shortAbbr, abbrevs, { shorthands }) { } // first check to see if this arg is a set of single-char shorthands - var singles = shorthands.___singles - if (!singles) { - singles = Object.keys(shorthands).filter(function (s) { - return s.length === 1 - }).reduce(function (l, r) { - l[r] = true - return l - }, {}) - shorthands.___singles = singles - debug('shorthand singles', singles) - } - - var chrs = arg.split('').filter(function (c) { - return singles[c] - }) - - if (chrs.join('') === arg) { - return chrs.map(function (c) { - return shorthands[c] - }).reduce(function (l, r) { - return l.concat(r) - }, []) + const chrs = singleCharacters(arg, shorthands) + if (chrs) { + return chrs.map((c) => shorthands[c]).reduce((l, r) => l.concat(r), []) } // if it's an arg abbrev, and not a literal shorthand, then prefer the arg diff --git a/node_modules/nopt/lib/nopt.js b/node_modules/nopt/lib/nopt.js index 70fd809bc111e..37f01a08783f8 100644 --- a/node_modules/nopt/lib/nopt.js +++ b/node_modules/nopt/lib/nopt.js @@ -12,9 +12,9 @@ exports.clean = clean exports.typeDefs = defaultTypeDefs exports.lib = lib -function nopt (types = {}, shorthands = {}, args = process.argv, slice = 2) { +function nopt (types, shorthands, args = process.argv, slice = 2) { return lib.nopt(args.slice(slice), { - types, + types: types || {}, shorthands: shorthands || {}, typeDefs: exports.typeDefs, invalidHandler: exports.invalidHandler, @@ -23,7 +23,7 @@ function nopt (types = {}, shorthands = {}, args = process.argv, slice = 2) { function clean (data, types, typeDefs = exports.typeDefs) { return lib.clean(data, { - types, + types: types || {}, typeDefs, invalidHandler: exports.invalidHandler, }) diff --git a/node_modules/nopt/lib/type-defs.js b/node_modules/nopt/lib/type-defs.js index 6acf5e0a5b9d4..608352ee248cc 100644 --- a/node_modules/nopt/lib/type-defs.js +++ b/node_modules/nopt/lib/type-defs.js @@ -1,7 +1,7 @@ -var url = require('url') -var path = require('path') -var Stream = require('stream').Stream -var os = require('os') +const url = require('url') +const path = require('path') +const Stream = require('stream').Stream +const os = require('os') const debug = require('./debug') function validateString (data, k, val) { @@ -18,9 +18,9 @@ function validatePath (data, k, val) { val = String(val) - var isWin = process.platform === 'win32' - var homePattern = isWin ? /^~(\/|\\)/ : /^~\// - var home = os.homedir() + const isWin = process.platform === 'win32' + const homePattern = isWin ? /^~(\/|\\)/ : /^~\// + const home = os.homedir() if (home && val.match(homePattern)) { data[k] = path.resolve(home, val.slice(2)) @@ -39,7 +39,7 @@ function validateNumber (data, k, val) { } function validateDate (data, k, val) { - var s = Date.parse(val) + const s = Date.parse(val) debug('validate Date %j %j %j', k, val, s) if (isNaN(s)) { return false diff --git a/node_modules/nopt/package.json b/node_modules/nopt/package.json index a61cae4535f88..01b7de8fed934 100644 --- a/node_modules/nopt/package.json +++ b/node_modules/nopt/package.json @@ -1,6 +1,6 @@ { "name": "nopt", - "version": "7.1.0", + "version": "7.2.0", "description": "Option parsing for Node, supporting types, shorthands, etc. Used by npm.", "author": "GitHub Inc.", "main": "lib/nopt.js", @@ -26,13 +26,10 @@ }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", - "@npmcli/template-oss": "4.12.0", + "@npmcli/template-oss": "4.15.1", "tap": "^16.3.0" }, "tap": { - "lines": 91, - "branches": 87, - "statements": 91, "nyc-arg": [ "--exclude", "tap-snapshots/**" @@ -48,6 +45,7 @@ "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", "windowsCI": false, - "version": "4.12.0" + "version": "4.15.1", + "publish": true } } diff --git a/node_modules/npm-audit-report/lib/colors.js b/node_modules/npm-audit-report/lib/colors.js index 2fbf5c36093de..e6688f2f1c8c6 100644 --- a/node_modules/npm-audit-report/lib/colors.js +++ b/node_modules/npm-audit-report/lib/colors.js @@ -1,16 +1,14 @@ -const chalk = require('chalk') -module.exports = color => { - const identity = x => x - const green = color ? s => chalk.green.bold(s) : identity - const red = color ? s => chalk.red.bold(s) : identity - const magenta = color ? s => chalk.magenta.bold(s) : identity - const yellow = color ? s => chalk.yellow.bold(s) : identity - const white = color ? s => chalk.bold(s) : identity +module.exports = (chalk) => { + const green = s => chalk.green.bold(s) + const red = s => chalk.red.bold(s) + const magenta = s => chalk.magenta.bold(s) + const yellow = s => chalk.yellow.bold(s) + const white = s => chalk.bold(s) const severity = (sev, s) => sev.toLowerCase() === 'moderate' ? yellow(s || sev) : sev.toLowerCase() === 'high' ? red(s || sev) : sev.toLowerCase() === 'critical' ? magenta(s || sev) : white(s || sev) - const dim = color ? s => chalk.dim(s) : identity + const dim = s => chalk.dim(s) return { dim, diff --git a/node_modules/npm-audit-report/lib/index.js b/node_modules/npm-audit-report/lib/index.js index 63063f92526a1..d0ced01efefec 100644 --- a/node_modules/npm-audit-report/lib/index.js +++ b/node_modules/npm-audit-report/lib/index.js @@ -12,7 +12,7 @@ const exitCode = require('./exit-code.js') module.exports = Object.assign((data, options = {}) => { const { reporter = 'install', - color = true, + chalk, unicode = true, indent = 2, } = options @@ -35,7 +35,7 @@ module.exports = Object.assign((data, options = {}) => { } return { - report: reporters[reporter](data, { color, unicode, indent }), + report: reporters[reporter](data, { chalk, unicode, indent }), exitCode: exitCode(data, auditLevel), } }, { reporters }) diff --git a/node_modules/npm-audit-report/lib/reporters/detail.js b/node_modules/npm-audit-report/lib/reporters/detail.js index ba2f013836d9d..6dde8ec88de44 100644 --- a/node_modules/npm-audit-report/lib/reporters/detail.js +++ b/node_modules/npm-audit-report/lib/reporters/detail.js @@ -3,14 +3,14 @@ const colors = require('../colors.js') const install = require('./install.js') -module.exports = (data, { color }) => { - const summary = install.summary(data, { color }) +module.exports = (data, { chalk }) => { + const summary = install.summary(data, { chalk }) const none = data.metadata.vulnerabilities.total === 0 - return none ? summary : fullReport(data, { color, summary }) + return none ? summary : fullReport(data, { chalk, summary }) } -const fullReport = (data, { color, summary }) => { - const c = colors(color) +const fullReport = (data, { chalk, summary }) => { + const c = colors(chalk) const output = [c.white('# npm audit report'), ''] const printed = new Set() diff --git a/node_modules/npm-audit-report/lib/reporters/install.js b/node_modules/npm-audit-report/lib/reporters/install.js index cb8a249691e29..0a1e82533e657 100644 --- a/node_modules/npm-audit-report/lib/reporters/install.js +++ b/node_modules/npm-audit-report/lib/reporters/install.js @@ -1,7 +1,7 @@ const colors = require('../colors.js') -const calculate = (data, { color }) => { - const c = colors(color) +const calculate = (data, { chalk }) => { + const c = colors(chalk) const output = [] const { metadata: { vulnerabilities } } = data const vulnCount = vulnerabilities.total diff --git a/node_modules/npm-audit-report/package.json b/node_modules/npm-audit-report/package.json index 8779f4c1d2c7e..492071c1faf90 100644 --- a/node_modules/npm-audit-report/package.json +++ b/node_modules/npm-audit-report/package.json @@ -1,6 +1,6 @@ { "name": "npm-audit-report", - "version": "4.0.0", + "version": "5.0.0", "description": "Given a response from the npm security api, render it into a variety of security reports", "main": "lib/index.js", "scripts": { @@ -28,13 +28,10 @@ ], "author": "GitHub Inc.", "license": "ISC", - "dependencies": { - "chalk": "^4.0.0" - }, "devDependencies": { - "@npmcli/eslint-config": "^3.0.1", - "@npmcli/template-oss": "4.5.1", - "require-inject": "^1.4.4", + "@npmcli/eslint-config": "^4.0.0", + "@npmcli/template-oss": "4.14.1", + "chalk": "^5.2.0", "tap": "^16.0.0" }, "directories": { @@ -58,6 +55,6 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.5.1" + "version": "4.14.1" } } diff --git a/node_modules/pacote/lib/fetcher.js b/node_modules/pacote/lib/fetcher.js index 6694a57f6af36..f961a45c7d346 100644 --- a/node_modules/pacote/lib/fetcher.js +++ b/node_modules/pacote/lib/fetcher.js @@ -61,7 +61,8 @@ class FetcherBase { // by adding/modifying the integrity value. this.opts = { ...opts } - this.cache = opts.cache || cacheDir() + this.cache = opts.cache || cacheDir().cacache + this.tufCache = opts.tufCache || cacheDir().tufcache this.resolved = opts.resolved || null // default to caching/verifying with sha512, that's what we usually have diff --git a/node_modules/pacote/lib/registry.js b/node_modules/pacote/lib/registry.js index 625bedc9a7736..34d9b2b87f3f3 100644 --- a/node_modules/pacote/lib/registry.js +++ b/node_modules/pacote/lib/registry.js @@ -295,7 +295,10 @@ class RegistryFetcher extends Fetcher { // // Publish attestations are signed with a keyid so we need to // specify a public key from the keys endpoint: `registry-host.tld/-/npm/v1/keys` - const options = { keySelector: publicKey ? () => publicKey.pemkey : undefined } + const options = { + tufCachePath: this.tufCache, + keySelector: publicKey ? () => publicKey.pemkey : undefined, + } await sigstore.verify(bundle, null, options) } catch (e) { throw Object.assign(new Error( diff --git a/node_modules/pacote/lib/util/cache-dir.js b/node_modules/pacote/lib/util/cache-dir.js index 4236213edd409..ac83b1793f199 100644 --- a/node_modules/pacote/lib/util/cache-dir.js +++ b/node_modules/pacote/lib/util/cache-dir.js @@ -8,5 +8,8 @@ module.exports = (fakePlatform = false) => { const platform = fakePlatform || process.platform const cacheExtra = platform === 'win32' ? 'npm-cache' : '.npm' const cacheRoot = (platform === 'win32' && process.env.LOCALAPPDATA) || home - return resolve(cacheRoot, cacheExtra, '_cacache') + return { + cacache: resolve(cacheRoot, cacheExtra, '_cacache'), + tufcache: resolve(cacheRoot, cacheExtra, '_tuf'), + } } diff --git a/node_modules/pacote/package.json b/node_modules/pacote/package.json index 48f2bb0ac3fee..bc8d984704af5 100644 --- a/node_modules/pacote/package.json +++ b/node_modules/pacote/package.json @@ -1,6 +1,6 @@ { "name": "pacote", - "version": "15.1.3", + "version": "15.2.0", "description": "JavaScript package downloader", "author": "GitHub Inc.", "bin": { diff --git a/node_modules/path-scurry/dist/cjs/index.js b/node_modules/path-scurry/dist/cjs/index.js index d209f0e833049..8044c7e581d2e 100644 --- a/node_modules/path-scurry/dist/cjs/index.js +++ b/node_modules/path-scurry/dist/cjs/index.js @@ -159,6 +159,7 @@ class ChildrenCache extends lru_cache_1.LRUCache { } } exports.ChildrenCache = ChildrenCache; +const setAsCwd = Symbol('PathScurry setAsCwd'); /** * Path objects are sort of like a super-powered * {@link https://nodejs.org/docs/latest/api/fs.html#class-fsdirent fs.Dirent} @@ -291,6 +292,16 @@ class PathBase { #children; #linkTarget; #realpath; + /** + * This property is for compatibility with the Dirent class as of + * Node v20, where Dirent['path'] refers to the path of the directory + * that was passed to readdir. So, somewhat counterintuitively, this + * property refers to the *parent* path, not the path object itself. + * For root entries, it's the path to the entry itself. + */ + get path() { + return (this.parent || this).fullpath(); + } /** * Do not create new Path objects directly. They should always be accessed * via the PathScurry class or other methods on the Path class. @@ -438,8 +449,7 @@ class PathBase { return (this.#relative = this.name); } const pv = p.relative(); - const rp = pv + (!pv || !p.parent ? '' : this.sep) + name; - return (this.#relative = rp); + return pv + (!pv || !p.parent ? '' : this.sep) + name; } /** * The relative path from the cwd, using / as the path separator. @@ -458,8 +468,7 @@ class PathBase { return (this.#relativePosix = this.fullpathPosix()); } const pv = p.relativePosix(); - const rp = pv + (!pv || !p.parent ? '' : '/') + name; - return (this.#relativePosix = rp); + return pv + (!pv || !p.parent ? '' : '/') + name; } /** * The fully resolved path string for this Path entry @@ -1111,6 +1120,33 @@ class PathBase { this.#markENOREALPATH(); } } + /** + * Internal method to mark this Path object as the scurry cwd, + * called by {@link PathScurry#chdir} + * + * @internal + */ + [setAsCwd](oldCwd) { + if (oldCwd === this) + return; + const changed = new Set([]); + let rp = []; + let p = this; + while (p && p.parent) { + changed.add(p); + p.#relative = rp.join(this.sep); + p.#relativePosix = rp.join('/'); + p = p.parent; + rp.push('..'); + } + // now un-memoize parents of old cwd + p = oldCwd; + while (p && p.parent && !changed.has(p)) { + p.#relative = undefined; + p.#relativePosix = undefined; + p = p.parent; + } + } } exports.PathBase = PathBase; /** @@ -1838,6 +1874,11 @@ class PathScurryBase { process(); return results; } + chdir(path = this.cwd) { + const oldCwd = this.cwd; + this.cwd = typeof path === 'string' ? this.cwd.resolve(path) : path; + this.cwd[setAsCwd](oldCwd); + } } exports.PathScurryBase = PathScurryBase; /** diff --git a/node_modules/path-scurry/dist/mjs/index.js b/node_modules/path-scurry/dist/mjs/index.js index 8490cf73124f3..957f087c86514 100644 --- a/node_modules/path-scurry/dist/mjs/index.js +++ b/node_modules/path-scurry/dist/mjs/index.js @@ -131,6 +131,7 @@ export class ChildrenCache extends LRUCache { }); } } +const setAsCwd = Symbol('PathScurry setAsCwd'); /** * Path objects are sort of like a super-powered * {@link https://nodejs.org/docs/latest/api/fs.html#class-fsdirent fs.Dirent} @@ -263,6 +264,16 @@ export class PathBase { #children; #linkTarget; #realpath; + /** + * This property is for compatibility with the Dirent class as of + * Node v20, where Dirent['path'] refers to the path of the directory + * that was passed to readdir. So, somewhat counterintuitively, this + * property refers to the *parent* path, not the path object itself. + * For root entries, it's the path to the entry itself. + */ + get path() { + return (this.parent || this).fullpath(); + } /** * Do not create new Path objects directly. They should always be accessed * via the PathScurry class or other methods on the Path class. @@ -410,8 +421,7 @@ export class PathBase { return (this.#relative = this.name); } const pv = p.relative(); - const rp = pv + (!pv || !p.parent ? '' : this.sep) + name; - return (this.#relative = rp); + return pv + (!pv || !p.parent ? '' : this.sep) + name; } /** * The relative path from the cwd, using / as the path separator. @@ -430,8 +440,7 @@ export class PathBase { return (this.#relativePosix = this.fullpathPosix()); } const pv = p.relativePosix(); - const rp = pv + (!pv || !p.parent ? '' : '/') + name; - return (this.#relativePosix = rp); + return pv + (!pv || !p.parent ? '' : '/') + name; } /** * The fully resolved path string for this Path entry @@ -1083,6 +1092,33 @@ export class PathBase { this.#markENOREALPATH(); } } + /** + * Internal method to mark this Path object as the scurry cwd, + * called by {@link PathScurry#chdir} + * + * @internal + */ + [setAsCwd](oldCwd) { + if (oldCwd === this) + return; + const changed = new Set([]); + let rp = []; + let p = this; + while (p && p.parent) { + changed.add(p); + p.#relative = rp.join(this.sep); + p.#relativePosix = rp.join('/'); + p = p.parent; + rp.push('..'); + } + // now un-memoize parents of old cwd + p = oldCwd; + while (p && p.parent && !changed.has(p)) { + p.#relative = undefined; + p.#relativePosix = undefined; + p = p.parent; + } + } } /** * Path class used on win32 systems @@ -1807,6 +1843,11 @@ export class PathScurryBase { process(); return results; } + chdir(path = this.cwd) { + const oldCwd = this.cwd; + this.cwd = typeof path === 'string' ? this.cwd.resolve(path) : path; + this.cwd[setAsCwd](oldCwd); + } } /** * Windows implementation of {@link PathScurryBase} diff --git a/node_modules/path-scurry/package.json b/node_modules/path-scurry/package.json index bb282b966c53c..5b900825e44e0 100644 --- a/node_modules/path-scurry/package.json +++ b/node_modules/path-scurry/package.json @@ -1,6 +1,6 @@ { "name": "path-scurry", - "version": "1.7.0", + "version": "1.9.2", "description": "walk paths fast and efficiently", "author": "Isaac Z. Schlueter (https://blog.izs.me)", "main": "./dist/cjs/index.js", @@ -58,7 +58,7 @@ }, "devDependencies": { "@nodelib/fs.walk": "^1.2.8", - "@types/node": "^18.11.18", + "@types/node": "^20.1.4", "@types/tap": "^15.0.7", "c8": "^7.12.0", "eslint-config-prettier": "^8.6.0", @@ -81,7 +81,7 @@ "url": "git+https://github.com/isaacs/path-walker" }, "dependencies": { - "lru-cache": "^9.0.0", - "minipass": "^5.0.0" + "lru-cache": "^9.1.1", + "minipass": "^5.0.0 || ^6.0.2" } } diff --git a/node_modules/postcss-selector-parser/API.md b/node_modules/postcss-selector-parser/API.md index 36c7298fc9753..64459e3376fba 100644 --- a/node_modules/postcss-selector-parser/API.md +++ b/node_modules/postcss-selector-parser/API.md @@ -278,16 +278,13 @@ if (node.type === 'id') { } ``` -### `node.clone()` +### `node.clone([opts])` Returns a copy of a node, detached from any parent containers that the original might have had. ```js -const cloned = parser.id({value: 'search'}); -String(cloned); - -// => #search +const cloned = node.clone(); ``` ### `node.isAtPosition(line, column)` diff --git a/node_modules/postcss-selector-parser/dist/parser.js b/node_modules/postcss-selector-parser/dist/parser.js index 2a1e72c6c6c00..b4c75e3edc3fe 100644 --- a/node_modules/postcss-selector-parser/dist/parser.js +++ b/node_modules/postcss-selector-parser/dist/parser.js @@ -609,6 +609,9 @@ var Parser = /*#__PURE__*/function () { _proto.unexpected = function unexpected() { return this.error("Unexpected '" + this.content() + "'. Escaping special characters with \\ may help.", this.currToken[_tokenize.FIELDS.START_POS]); }; + _proto.unexpectedPipe = function unexpectedPipe() { + return this.error("Unexpected '|'.", this.currToken[_tokenize.FIELDS.START_POS]); + }; _proto.namespace = function namespace() { var before = this.prevToken && this.content(this.prevToken) || true; if (this.nextToken[_tokenize.FIELDS.TYPE] === tokens.word) { @@ -618,6 +621,7 @@ var Parser = /*#__PURE__*/function () { this.position++; return this.universal(before); } + this.unexpectedPipe(); }; _proto.nesting = function nesting() { if (this.nextToken) { diff --git a/node_modules/postcss-selector-parser/package.json b/node_modules/postcss-selector-parser/package.json index ff9c40960f737..dce071cdcb2b3 100644 --- a/node_modules/postcss-selector-parser/package.json +++ b/node_modules/postcss-selector-parser/package.json @@ -1,6 +1,6 @@ { "name": "postcss-selector-parser", - "version": "6.0.12", + "version": "6.0.13", "devDependencies": { "@babel/cli": "^7.11.6", "@babel/core": "^7.11.6", diff --git a/node_modules/read-package-json/lib/read-json.js b/node_modules/read-package-json/lib/read-json.js index aaf24e94a7375..d35f09ebd208f 100644 --- a/node_modules/read-package-json/lib/read-json.js +++ b/node_modules/read-package-json/lib/read-json.js @@ -352,7 +352,7 @@ function bins (file, data, cb) { return cb(null, data) } - m = path.resolve(path.dirname(file), m) + m = path.resolve(path.dirname(file), path.join('.', path.join('/', m))) glob('**', { cwd: m }) .then(binsGlob => bins_(file, data, binsGlob, cb)) .catch(er => cb(er)) diff --git a/node_modules/read-package-json/package.json b/node_modules/read-package-json/package.json index a2f93088f37fc..90ab321d51743 100644 --- a/node_modules/read-package-json/package.json +++ b/node_modules/read-package-json/package.json @@ -1,6 +1,6 @@ { "name": "read-package-json", - "version": "6.0.3", + "version": "6.0.4", "author": "GitHub Inc.", "description": "The thing npm uses to read package.json files with semantics and defaults and validation", "repository": { @@ -30,7 +30,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", - "@npmcli/template-oss": "4.14.1", + "@npmcli/template-oss": "4.15.1", "tap": "^16.0.1" }, "license": "ISC", @@ -42,10 +42,10 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" }, "tap": { - "branches": 68, - "functions": 74, - "lines": 74, - "statements": 74, + "branches": 73, + "functions": 77, + "lines": 77, + "statements": 77, "nyc-arg": [ "--exclude", "tap-snapshots/**" @@ -53,7 +53,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.14.1", + "version": "4.15.1", "publish": "true" } } diff --git a/node_modules/readable-stream/lib/internal/streams/add-abort-signal.js b/node_modules/readable-stream/lib/internal/streams/add-abort-signal.js index c6ba8b9c298f1..3a26a1d3e6d76 100644 --- a/node_modules/readable-stream/lib/internal/streams/add-abort-signal.js +++ b/node_modules/readable-stream/lib/internal/streams/add-abort-signal.js @@ -1,6 +1,7 @@ 'use strict' const { AbortError, codes } = require('../../ours/errors') +const { isNodeStream, isWebStream, kControllerErrorFunction } = require('./utils') const eos = require('./end-of-stream') const { ERR_INVALID_ARG_TYPE } = codes @@ -12,13 +13,10 @@ const validateAbortSignal = (signal, name) => { throw new ERR_INVALID_ARG_TYPE(name, 'AbortSignal', signal) } } -function isNodeStream(obj) { - return !!(obj && typeof obj.pipe === 'function') -} module.exports.addAbortSignal = function addAbortSignal(signal, stream) { validateAbortSignal(signal, 'signal') - if (!isNodeStream(stream)) { - throw new ERR_INVALID_ARG_TYPE('stream', 'stream.Stream', stream) + if (!isNodeStream(stream) && !isWebStream(stream)) { + throw new ERR_INVALID_ARG_TYPE('stream', ['ReadableStream', 'WritableStream', 'Stream'], stream) } return module.exports.addAbortSignalNoValidate(signal, stream) } @@ -26,13 +24,21 @@ module.exports.addAbortSignalNoValidate = function (signal, stream) { if (typeof signal !== 'object' || !('aborted' in signal)) { return stream } - const onAbort = () => { - stream.destroy( - new AbortError(undefined, { - cause: signal.reason - }) - ) - } + const onAbort = isNodeStream(stream) + ? () => { + stream.destroy( + new AbortError(undefined, { + cause: signal.reason + }) + ) + } + : () => { + stream[kControllerErrorFunction]( + new AbortError(undefined, { + cause: signal.reason + }) + ) + } if (signal.aborted) { onAbort() } else { diff --git a/node_modules/readable-stream/lib/internal/streams/compose.js b/node_modules/readable-stream/lib/internal/streams/compose.js index 4a00aead883c2..f565c12ef3620 100644 --- a/node_modules/readable-stream/lib/internal/streams/compose.js +++ b/node_modules/readable-stream/lib/internal/streams/compose.js @@ -3,11 +3,20 @@ const { pipeline } = require('./pipeline') const Duplex = require('./duplex') const { destroyer } = require('./destroy') -const { isNodeStream, isReadable, isWritable } = require('./utils') +const { + isNodeStream, + isReadable, + isWritable, + isWebStream, + isTransformStream, + isWritableStream, + isReadableStream +} = require('./utils') const { AbortError, codes: { ERR_INVALID_ARG_VALUE, ERR_MISSING_ARGS } } = require('../../ours/errors') +const eos = require('./end-of-stream') module.exports = function compose(...streams) { if (streams.length === 0) { throw new ERR_MISSING_ARGS('streams') @@ -24,14 +33,17 @@ module.exports = function compose(...streams) { streams[idx] = Duplex.from(streams[idx]) } for (let n = 0; n < streams.length; ++n) { - if (!isNodeStream(streams[n])) { + if (!isNodeStream(streams[n]) && !isWebStream(streams[n])) { // TODO(ronag): Add checks for non streams. continue } - if (n < streams.length - 1 && !isReadable(streams[n])) { + if ( + n < streams.length - 1 && + !(isReadable(streams[n]) || isReadableStream(streams[n]) || isTransformStream(streams[n])) + ) { throw new ERR_INVALID_ARG_VALUE(`streams[${n}]`, orgStreams[n], 'must be readable') } - if (n > 0 && !isWritable(streams[n])) { + if (n > 0 && !(isWritable(streams[n]) || isWritableStream(streams[n]) || isTransformStream(streams[n]))) { throw new ERR_INVALID_ARG_VALUE(`streams[${n}]`, orgStreams[n], 'must be writable') } } @@ -53,8 +65,8 @@ module.exports = function compose(...streams) { } const head = streams[0] const tail = pipeline(streams, onfinished) - const writable = !!isWritable(head) - const readable = !!isReadable(tail) + const writable = !!(isWritable(head) || isWritableStream(head) || isTransformStream(head)) + const readable = !!(isReadable(tail) || isReadableStream(tail) || isTransformStream(tail)) // TODO(ronag): Avoid double buffering. // Implement Writable/Readable/Duplex traits. @@ -67,25 +79,49 @@ module.exports = function compose(...streams) { readable }) if (writable) { - d._write = function (chunk, encoding, callback) { - if (head.write(chunk, encoding)) { - callback() - } else { - ondrain = callback + if (isNodeStream(head)) { + d._write = function (chunk, encoding, callback) { + if (head.write(chunk, encoding)) { + callback() + } else { + ondrain = callback + } } - } - d._final = function (callback) { - head.end() - onfinish = callback - } - head.on('drain', function () { - if (ondrain) { - const cb = ondrain - ondrain = null - cb() + d._final = function (callback) { + head.end() + onfinish = callback } - }) - tail.on('finish', function () { + head.on('drain', function () { + if (ondrain) { + const cb = ondrain + ondrain = null + cb() + } + }) + } else if (isWebStream(head)) { + const writable = isTransformStream(head) ? head.writable : head + const writer = writable.getWriter() + d._write = async function (chunk, encoding, callback) { + try { + await writer.ready + writer.write(chunk).catch(() => {}) + callback() + } catch (err) { + callback(err) + } + } + d._final = async function (callback) { + try { + await writer.ready + writer.close().catch(() => {}) + onfinish = callback + } catch (err) { + callback(err) + } + } + } + const toRead = isTransformStream(tail) ? tail.readable : tail + eos(toRead, () => { if (onfinish) { const cb = onfinish onfinish = null @@ -94,25 +130,46 @@ module.exports = function compose(...streams) { }) } if (readable) { - tail.on('readable', function () { - if (onreadable) { - const cb = onreadable - onreadable = null - cb() - } - }) - tail.on('end', function () { - d.push(null) - }) - d._read = function () { - while (true) { - const buf = tail.read() - if (buf === null) { - onreadable = d._read - return + if (isNodeStream(tail)) { + tail.on('readable', function () { + if (onreadable) { + const cb = onreadable + onreadable = null + cb() + } + }) + tail.on('end', function () { + d.push(null) + }) + d._read = function () { + while (true) { + const buf = tail.read() + if (buf === null) { + onreadable = d._read + return + } + if (!d.push(buf)) { + return + } } - if (!d.push(buf)) { - return + } + } else if (isWebStream(tail)) { + const readable = isTransformStream(tail) ? tail.readable : tail + const reader = readable.getReader() + d._read = async function () { + while (true) { + try { + const { value, done } = await reader.read() + if (!d.push(value)) { + return + } + if (done) { + d.push(null) + return + } + } catch { + return + } } } } @@ -128,7 +185,9 @@ module.exports = function compose(...streams) { callback(err) } else { onclose = callback - destroyer(tail, err) + if (isNodeStream(tail)) { + destroyer(tail, err) + } } } return d diff --git a/node_modules/readable-stream/lib/internal/streams/destroy.js b/node_modules/readable-stream/lib/internal/streams/destroy.js index 768f2d79d3a89..db76c29f94bab 100644 --- a/node_modules/readable-stream/lib/internal/streams/destroy.js +++ b/node_modules/readable-stream/lib/internal/streams/destroy.js @@ -36,7 +36,7 @@ function destroy(err, cb) { const w = this._writableState // With duplex streams we use the writable side for state. const s = w || r - if ((w && w.destroyed) || (r && r.destroyed)) { + if ((w !== null && w !== undefined && w.destroyed) || (r !== null && r !== undefined && r.destroyed)) { if (typeof cb === 'function') { cb() } @@ -107,14 +107,14 @@ function emitCloseNT(self) { if (r) { r.closeEmitted = true } - if ((w && w.emitClose) || (r && r.emitClose)) { + if ((w !== null && w !== undefined && w.emitClose) || (r !== null && r !== undefined && r.emitClose)) { self.emit('close') } } function emitErrorNT(self, err) { const r = self._readableState const w = self._writableState - if ((w && w.errorEmitted) || (r && r.errorEmitted)) { + if ((w !== null && w !== undefined && w.errorEmitted) || (r !== null && r !== undefined && r.errorEmitted)) { return } if (w) { @@ -162,10 +162,11 @@ function errorOrDestroy(stream, err, sync) { const r = stream._readableState const w = stream._writableState - if ((w && w.destroyed) || (r && r.destroyed)) { + if ((w !== null && w !== undefined && w.destroyed) || (r !== null && r !== undefined && r.destroyed)) { return this } - if ((r && r.autoDestroy) || (w && w.autoDestroy)) stream.destroy(err) + if ((r !== null && r !== undefined && r.autoDestroy) || (w !== null && w !== undefined && w.autoDestroy)) + stream.destroy(err) else if (err) { // Avoid V8 leak, https://github.com/nodejs/node/pull/34103#issuecomment-652002364 err.stack // eslint-disable-line no-unused-expressions @@ -228,16 +229,18 @@ function constructNT(stream) { } } try { - stream._construct(onConstruct) + stream._construct((err) => { + process.nextTick(onConstruct, err) + }) } catch (err) { - onConstruct(err) + process.nextTick(onConstruct, err) } } function emitConstructNT(stream) { stream.emit(kConstruct) } function isRequest(stream) { - return stream && stream.setHeader && typeof stream.abort === 'function' + return (stream === null || stream === undefined ? undefined : stream.setHeader) && typeof stream.abort === 'function' } function emitCloseLegacy(stream) { stream.emit('close') diff --git a/node_modules/readable-stream/lib/internal/streams/duplexify.js b/node_modules/readable-stream/lib/internal/streams/duplexify.js index 43300ddc8a45b..599fb47ab53c2 100644 --- a/node_modules/readable-stream/lib/internal/streams/duplexify.js +++ b/node_modules/readable-stream/lib/internal/streams/duplexify.js @@ -282,8 +282,6 @@ function _duplexify(pair) { cb(err) } else if (err) { d.destroy(err) - } else if (!readable && !writable) { - d.destroy() } } diff --git a/node_modules/readable-stream/lib/internal/streams/end-of-stream.js b/node_modules/readable-stream/lib/internal/streams/end-of-stream.js index 57dbaa48a3ca5..043c9c4bdac51 100644 --- a/node_modules/readable-stream/lib/internal/streams/end-of-stream.js +++ b/node_modules/readable-stream/lib/internal/streams/end-of-stream.js @@ -10,20 +10,23 @@ const process = require('process/') const { AbortError, codes } = require('../../ours/errors') const { ERR_INVALID_ARG_TYPE, ERR_STREAM_PREMATURE_CLOSE } = codes const { kEmptyObject, once } = require('../../ours/util') -const { validateAbortSignal, validateFunction, validateObject } = require('../validators') -const { Promise } = require('../../ours/primordials') +const { validateAbortSignal, validateFunction, validateObject, validateBoolean } = require('../validators') +const { Promise, PromisePrototypeThen } = require('../../ours/primordials') const { isClosed, isReadable, isReadableNodeStream, + isReadableStream, isReadableFinished, isReadableErrored, isWritable, isWritableNodeStream, + isWritableStream, isWritableFinished, isWritableErrored, isNodeStream, - willEmitClose: _willEmitClose + willEmitClose: _willEmitClose, + kIsClosedPromise } = require('./utils') function isRequest(stream) { return stream.setHeader && typeof stream.abort === 'function' @@ -42,6 +45,12 @@ function eos(stream, options, callback) { validateFunction(callback, 'callback') validateAbortSignal(options.signal, 'options.signal') callback = once(callback) + if (isReadableStream(stream) || isWritableStream(stream)) { + return eosWeb(stream, options, callback) + } + if (!isNodeStream(stream)) { + throw new ERR_INVALID_ARG_TYPE('stream', ['ReadableStream', 'WritableStream', 'Stream'], stream) + } const readable = (_options$readable = options.readable) !== null && _options$readable !== undefined ? _options$readable @@ -50,10 +59,6 @@ function eos(stream, options, callback) { (_options$writable = options.writable) !== null && _options$writable !== undefined ? _options$writable : isWritableNodeStream(stream) - if (!isNodeStream(stream)) { - // TODO: Webstreams. - throw new ERR_INVALID_ARG_TYPE('stream', 'Stream', stream) - } const wState = stream._writableState const rState = stream._readableState const onlegacyfinish = () => { @@ -117,6 +122,14 @@ function eos(stream, options, callback) { } callback.call(stream) } + const onclosed = () => { + closed = true + const errored = isWritableErrored(stream) || isReadableErrored(stream) + if (errored && typeof errored !== 'boolean') { + return callback.call(stream, errored) + } + callback.call(stream) + } const onrequest = () => { stream.req.on('finish', onfinish) } @@ -153,22 +166,22 @@ function eos(stream, options, callback) { (rState !== null && rState !== undefined && rState.errorEmitted) ) { if (!willEmitClose) { - process.nextTick(onclose) + process.nextTick(onclosed) } } else if ( !readable && (!willEmitClose || isReadable(stream)) && (writableFinished || isWritable(stream) === false) ) { - process.nextTick(onclose) + process.nextTick(onclosed) } else if ( !writable && (!willEmitClose || isWritable(stream)) && (readableFinished || isReadable(stream) === false) ) { - process.nextTick(onclose) + process.nextTick(onclosed) } else if (rState && stream.req && stream.aborted) { - process.nextTick(onclose) + process.nextTick(onclosed) } const cleanup = () => { callback = nop @@ -209,9 +222,53 @@ function eos(stream, options, callback) { } return cleanup } +function eosWeb(stream, options, callback) { + let isAborted = false + let abort = nop + if (options.signal) { + abort = () => { + isAborted = true + callback.call( + stream, + new AbortError(undefined, { + cause: options.signal.reason + }) + ) + } + if (options.signal.aborted) { + process.nextTick(abort) + } else { + const originalCallback = callback + callback = once((...args) => { + options.signal.removeEventListener('abort', abort) + originalCallback.apply(stream, args) + }) + options.signal.addEventListener('abort', abort) + } + } + const resolverFn = (...args) => { + if (!isAborted) { + process.nextTick(() => callback.apply(stream, args)) + } + } + PromisePrototypeThen(stream[kIsClosedPromise].promise, resolverFn, resolverFn) + return nop +} function finished(stream, opts) { + var _opts + let autoCleanup = false + if (opts === null) { + opts = kEmptyObject + } + if ((_opts = opts) !== null && _opts !== undefined && _opts.cleanup) { + validateBoolean(opts.cleanup, 'cleanup') + autoCleanup = opts.cleanup + } return new Promise((resolve, reject) => { - eos(stream, opts, (err) => { + const cleanup = eos(stream, opts, (err) => { + if (autoCleanup) { + cleanup() + } if (err) { reject(err) } else { diff --git a/node_modules/readable-stream/lib/internal/streams/operators.js b/node_modules/readable-stream/lib/internal/streams/operators.js index 323a74a17c32e..869cacb39faca 100644 --- a/node_modules/readable-stream/lib/internal/streams/operators.js +++ b/node_modules/readable-stream/lib/internal/streams/operators.js @@ -2,12 +2,15 @@ const AbortController = globalThis.AbortController || require('abort-controller').AbortController const { - codes: { ERR_INVALID_ARG_TYPE, ERR_MISSING_ARGS, ERR_OUT_OF_RANGE }, + codes: { ERR_INVALID_ARG_VALUE, ERR_INVALID_ARG_TYPE, ERR_MISSING_ARGS, ERR_OUT_OF_RANGE }, AbortError } = require('../../ours/errors') const { validateAbortSignal, validateInteger, validateObject } = require('../validators') const kWeakHandler = require('../../ours/primordials').Symbol('kWeak') const { finished } = require('./end-of-stream') +const staticCompose = require('./compose') +const { addAbortSignalNoValidate } = require('./add-abort-signal') +const { isWritable, isNodeStream } = require('./utils') const { ArrayPrototypePush, MathFloor, @@ -20,6 +23,23 @@ const { } = require('../../ours/primordials') const kEmpty = Symbol('kEmpty') const kEof = Symbol('kEof') +function compose(stream, options) { + if (options != null) { + validateObject(options, 'options') + } + if ((options === null || options === undefined ? undefined : options.signal) != null) { + validateAbortSignal(options.signal, 'options.signal') + } + if (isNodeStream(stream) && !isWritable(stream)) { + throw new ERR_INVALID_ARG_VALUE('stream', stream, 'must be writable') + } + const composedStream = staticCompose(this, stream) + if (options !== null && options !== undefined && options.signal) { + // Not validating as we already validated before + addAbortSignalNoValidate(options.signal, composedStream) + } + return composedStream +} function map(fn, options) { if (typeof fn !== 'function') { throw new ERR_INVALID_ARG_TYPE('fn', ['Function', 'AsyncFunction'], fn) @@ -424,7 +444,8 @@ module.exports.streamReturningOperators = { filter, flatMap, map, - take + take, + compose } module.exports.promiseReturningOperators = { every, diff --git a/node_modules/readable-stream/lib/internal/streams/pipeline.js b/node_modules/readable-stream/lib/internal/streams/pipeline.js index 016e96ee6ff24..8393ba5146991 100644 --- a/node_modules/readable-stream/lib/internal/streams/pipeline.js +++ b/node_modules/readable-stream/lib/internal/streams/pipeline.js @@ -24,7 +24,16 @@ const { AbortError } = require('../../ours/errors') const { validateFunction, validateAbortSignal } = require('../validators') -const { isIterable, isReadable, isReadableNodeStream, isNodeStream } = require('./utils') +const { + isIterable, + isReadable, + isReadableNodeStream, + isNodeStream, + isTransformStream, + isWebStream, + isReadableStream, + isReadableEnded +} = require('./utils') const AbortController = globalThis.AbortController || require('abort-controller').AbortController let PassThrough let Readable @@ -74,7 +83,7 @@ async function* fromReadable(val) { } yield* Readable.prototype[SymbolAsyncIterator].call(val) } -async function pump(iterable, writable, finish, { end }) { +async function pumpToNode(iterable, writable, finish, { end }) { let error let onresolve = null const resume = (err) => { @@ -130,6 +139,31 @@ async function pump(iterable, writable, finish, { end }) { writable.off('drain', resume) } } +async function pumpToWeb(readable, writable, finish, { end }) { + if (isTransformStream(writable)) { + writable = writable.writable + } + // https://streams.spec.whatwg.org/#example-manual-write-with-backpressure + const writer = writable.getWriter() + try { + for await (const chunk of readable) { + await writer.ready + writer.write(chunk).catch(() => {}) + } + await writer.ready + if (end) { + await writer.close() + } + finish() + } catch (err) { + try { + await writer.abort(err) + finish(err) + } catch (err) { + finish(err) + } + } +} function pipeline(...streams) { return pipelineImpl(streams, once(popCallback(streams))) } @@ -215,13 +249,18 @@ function pipelineImpl(streams, callback, opts) { if (!isIterable(ret)) { throw new ERR_INVALID_RETURN_VALUE('Iterable, AsyncIterable or Stream', 'source', ret) } - } else if (isIterable(stream) || isReadableNodeStream(stream)) { + } else if (isIterable(stream) || isReadableNodeStream(stream) || isTransformStream(stream)) { ret = stream } else { ret = Duplex.from(stream) } } else if (typeof stream === 'function') { - ret = makeAsyncIterable(ret) + if (isTransformStream(ret)) { + var _ret + ret = makeAsyncIterable((_ret = ret) === null || _ret === undefined ? undefined : _ret.readable) + } else { + ret = makeAsyncIterable(ret) + } ret = stream(ret, { signal }) @@ -230,7 +269,7 @@ function pipelineImpl(streams, callback, opts) { throw new ERR_INVALID_RETURN_VALUE('AsyncIterable', `transform[${i - 1}]`, ret) } } else { - var _ret + var _ret2 if (!PassThrough) { PassThrough = require('./passthrough') } @@ -246,7 +285,7 @@ function pipelineImpl(streams, callback, opts) { // Handle Promises/A+ spec, `then` could be a getter that throws on // second use. - const then = (_ret = ret) === null || _ret === undefined ? undefined : _ret.then + const then = (_ret2 = ret) === null || _ret2 === undefined ? undefined : _ret2.then if (typeof then === 'function') { finishCount++ then.call( @@ -268,7 +307,13 @@ function pipelineImpl(streams, callback, opts) { ) } else if (isIterable(ret, true)) { finishCount++ - pump(ret, pt, finish, { + pumpToNode(ret, pt, finish, { + end + }) + } else if (isReadableStream(ret) || isTransformStream(ret)) { + const toRead = ret.readable || ret + finishCount++ + pumpToNode(toRead, pt, finish, { end }) } else { @@ -290,13 +335,47 @@ function pipelineImpl(streams, callback, opts) { if (isReadable(stream) && isLastStream) { lastStreamCleanup.push(cleanup) } + } else if (isTransformStream(ret) || isReadableStream(ret)) { + const toRead = ret.readable || ret + finishCount++ + pumpToNode(toRead, stream, finish, { + end + }) } else if (isIterable(ret)) { finishCount++ - pump(ret, stream, finish, { + pumpToNode(ret, stream, finish, { end }) } else { - throw new ERR_INVALID_ARG_TYPE('val', ['Readable', 'Iterable', 'AsyncIterable'], ret) + throw new ERR_INVALID_ARG_TYPE( + 'val', + ['Readable', 'Iterable', 'AsyncIterable', 'ReadableStream', 'TransformStream'], + ret + ) + } + ret = stream + } else if (isWebStream(stream)) { + if (isReadableNodeStream(ret)) { + finishCount++ + pumpToWeb(makeAsyncIterable(ret), stream, finish, { + end + }) + } else if (isReadableStream(ret) || isIterable(ret)) { + finishCount++ + pumpToWeb(ret, stream, finish, { + end + }) + } else if (isTransformStream(ret)) { + finishCount++ + pumpToWeb(ret.readable, stream, finish, { + end + }) + } else { + throw new ERR_INVALID_ARG_TYPE( + 'val', + ['Readable', 'Iterable', 'AsyncIterable', 'ReadableStream', 'TransformStream'], + ret + ) } ret = stream } else { @@ -320,16 +399,24 @@ function pipe(src, dst, finish, { end }) { } }) src.pipe(dst, { - end - }) + end: false + }) // If end is true we already will have a listener to end dst. + if (end) { // Compat. Before node v10.12.0 stdio used to throw an error so // pipe() did/does not end() stdio destinations. // Now they allow it but "secretly" don't close the underlying fd. - src.once('end', () => { + + function endFn() { ended = true dst.end() - }) + } + if (isReadableEnded(src)) { + // End the destination if the source has already ended. + process.nextTick(endFn) + } else { + src.once('end', endFn) + } } else { finish() } diff --git a/node_modules/readable-stream/lib/internal/streams/utils.js b/node_modules/readable-stream/lib/internal/streams/utils.js index f87e9fe68e6a8..e589ad96c6924 100644 --- a/node_modules/readable-stream/lib/internal/streams/utils.js +++ b/node_modules/readable-stream/lib/internal/streams/utils.js @@ -1,10 +1,12 @@ 'use strict' -const { Symbol, SymbolAsyncIterator, SymbolIterator } = require('../../ours/primordials') +const { Symbol, SymbolAsyncIterator, SymbolIterator, SymbolFor } = require('../../ours/primordials') const kDestroyed = Symbol('kDestroyed') const kIsErrored = Symbol('kIsErrored') const kIsReadable = Symbol('kIsReadable') const kIsDisturbed = Symbol('kIsDisturbed') +const kIsClosedPromise = SymbolFor('nodejs.webstream.isClosedPromise') +const kControllerErrorFunction = SymbolFor('nodejs.webstream.controllerErrorFunction') function isReadableNodeStream(obj, strict = false) { var _obj$_readableState return !!( @@ -56,6 +58,24 @@ function isNodeStream(obj) { (typeof obj.pipe === 'function' && typeof obj.on === 'function')) ) } +function isReadableStream(obj) { + return !!( + obj && + !isNodeStream(obj) && + typeof obj.pipeThrough === 'function' && + typeof obj.getReader === 'function' && + typeof obj.cancel === 'function' + ) +} +function isWritableStream(obj) { + return !!(obj && !isNodeStream(obj) && typeof obj.getWriter === 'function' && typeof obj.abort === 'function') +} +function isTransformStream(obj) { + return !!(obj && !isNodeStream(obj) && typeof obj.readable === 'object' && typeof obj.writable === 'object') +} +function isWebStream(obj) { + return isReadableStream(obj) || isWritableStream(obj) || isTransformStream(obj) +} function isIterable(obj, isAsync) { if (obj == null) return false if (isAsync === true) return typeof obj[SymbolAsyncIterator] === 'function' @@ -274,22 +294,28 @@ module.exports = { kIsErrored, isReadable, kIsReadable, + kIsClosedPromise, + kControllerErrorFunction, isClosed, isDestroyed, isDuplexNodeStream, isFinished, isIterable, isReadableNodeStream, + isReadableStream, isReadableEnded, isReadableFinished, isReadableErrored, isNodeStream, + isWebStream, isWritable, isWritableNodeStream, + isWritableStream, isWritableEnded, isWritableFinished, isWritableErrored, isServerRequest, isServerResponse, - willEmitClose + willEmitClose, + isTransformStream } diff --git a/node_modules/readable-stream/lib/internal/validators.js b/node_modules/readable-stream/lib/internal/validators.js index f9e6e555971a1..85b2e9cd593d9 100644 --- a/node_modules/readable-stream/lib/internal/validators.js +++ b/node_modules/readable-stream/lib/internal/validators.js @@ -1,3 +1,5 @@ +/* eslint jsdoc/require-jsdoc: "error" */ + 'use strict' const { @@ -199,6 +201,13 @@ const validateOneOf = hideStackFrames((value, name, oneOf) => { function validateBoolean(value, name) { if (typeof value !== 'boolean') throw new ERR_INVALID_ARG_TYPE(name, 'boolean', value) } + +/** + * @param {any} options + * @param {string} key + * @param {boolean} defaultValue + * @returns {boolean} + */ function getOwnPropertyValueOrDefault(options, key, defaultValue) { return options == null || !ObjectPrototypeHasOwnProperty(options, key) ? defaultValue : options[key] } @@ -228,6 +237,24 @@ const validateObject = hideStackFrames((value, name, options = null) => { } }) +/** + * @callback validateDictionary - We are using the Web IDL Standard definition + * of "dictionary" here, which means any value + * whose Type is either Undefined, Null, or + * Object (which includes functions). + * @param {*} value + * @param {string} name + * @see https://webidl.spec.whatwg.org/#es-dictionary + * @see https://tc39.es/ecma262/#table-typeof-operator-results + */ + +/** @type {validateDictionary} */ +const validateDictionary = hideStackFrames((value, name) => { + if (value != null && typeof value !== 'object' && typeof value !== 'function') { + throw new ERR_INVALID_ARG_TYPE(name, 'a dictionary', value) + } +}) + /** * @callback validateArray * @param {*} value @@ -247,7 +274,36 @@ const validateArray = hideStackFrames((value, name, minLength = 0) => { } }) -// eslint-disable-next-line jsdoc/require-returns-check +/** + * @callback validateStringArray + * @param {*} value + * @param {string} name + * @returns {asserts value is string[]} + */ + +/** @type {validateStringArray} */ +function validateStringArray(value, name) { + validateArray(value, name) + for (let i = 0; i < value.length; i++) { + validateString(value[i], `${name}[${i}]`) + } +} + +/** + * @callback validateBooleanArray + * @param {*} value + * @param {string} name + * @returns {asserts value is boolean[]} + */ + +/** @type {validateBooleanArray} */ +function validateBooleanArray(value, name) { + validateArray(value, name) + for (let i = 0; i < value.length; i++) { + validateBoolean(value[i], `${name}[${i}]`) + } +} + /** * @param {*} signal * @param {string} [name='signal'] @@ -370,13 +426,71 @@ function validateUnion(value, name, union) { throw new ERR_INVALID_ARG_TYPE(name, `('${ArrayPrototypeJoin(union, '|')}')`, value) } } + +/* + The rules for the Link header field are described here: + https://www.rfc-editor.org/rfc/rfc8288.html#section-3 + + This regex validates any string surrounded by angle brackets + (not necessarily a valid URI reference) followed by zero or more + link-params separated by semicolons. +*/ +const linkValueRegExp = /^(?:<[^>]*>)(?:\s*;\s*[^;"\s]+(?:=(")?[^;"\s]*\1)?)*$/ + +/** + * @param {any} value + * @param {string} name + */ +function validateLinkHeaderFormat(value, name) { + if (typeof value === 'undefined' || !RegExpPrototypeExec(linkValueRegExp, value)) { + throw new ERR_INVALID_ARG_VALUE( + name, + value, + 'must be an array or string of format "; rel=preload; as=style"' + ) + } +} + +/** + * @param {any} hints + * @return {string} + */ +function validateLinkHeaderValue(hints) { + if (typeof hints === 'string') { + validateLinkHeaderFormat(hints, 'hints') + return hints + } else if (ArrayIsArray(hints)) { + const hintsLength = hints.length + let result = '' + if (hintsLength === 0) { + return result + } + for (let i = 0; i < hintsLength; i++) { + const link = hints[i] + validateLinkHeaderFormat(link, 'hints') + result += link + if (i !== hintsLength - 1) { + result += ', ' + } + } + return result + } + throw new ERR_INVALID_ARG_VALUE( + 'hints', + hints, + 'must be an array or string of format "; rel=preload; as=style"' + ) +} module.exports = { isInt32, isUint32, parseFileMode, validateArray, + validateStringArray, + validateBooleanArray, validateBoolean, validateBuffer, + validateDictionary, validateEncoding, validateFunction, validateInt32, @@ -391,5 +505,6 @@ module.exports = { validateUint32, validateUndefined, validateUnion, - validateAbortSignal + validateAbortSignal, + validateLinkHeaderValue } diff --git a/node_modules/readable-stream/lib/ours/primordials.js b/node_modules/readable-stream/lib/ours/primordials.js index 6a98b01681caf..9464cc7fea6a1 100644 --- a/node_modules/readable-stream/lib/ours/primordials.js +++ b/node_modules/readable-stream/lib/ours/primordials.js @@ -90,6 +90,7 @@ module.exports = { return self.trim() }, Symbol, + SymbolFor: Symbol.for, SymbolAsyncIterator: Symbol.asyncIterator, SymbolHasInstance: Symbol.hasInstance, SymbolIterator: Symbol.iterator, diff --git a/node_modules/readable-stream/lib/stream/promises.js b/node_modules/readable-stream/lib/stream/promises.js index d44dd8ad0e0f3..b85c51f47f1ce 100644 --- a/node_modules/readable-stream/lib/stream/promises.js +++ b/node_modules/readable-stream/lib/stream/promises.js @@ -1,15 +1,22 @@ 'use strict' const { ArrayPrototypePop, Promise } = require('../ours/primordials') -const { isIterable, isNodeStream } = require('../internal/streams/utils') +const { isIterable, isNodeStream, isWebStream } = require('../internal/streams/utils') const { pipelineImpl: pl } = require('../internal/streams/pipeline') const { finished } = require('../internal/streams/end-of-stream') +require('stream') function pipeline(...streams) { return new Promise((resolve, reject) => { let signal let end const lastArg = streams[streams.length - 1] - if (lastArg && typeof lastArg === 'object' && !isNodeStream(lastArg) && !isIterable(lastArg)) { + if ( + lastArg && + typeof lastArg === 'object' && + !isNodeStream(lastArg) && + !isIterable(lastArg) && + !isWebStream(lastArg) + ) { const options = ArrayPrototypePop(streams) signal = options.signal end = options.end diff --git a/node_modules/readable-stream/package.json b/node_modules/readable-stream/package.json index 7df83d9eb990a..c4f6504cc7cc6 100644 --- a/node_modules/readable-stream/package.json +++ b/node_modules/readable-stream/package.json @@ -1,6 +1,6 @@ { "name": "readable-stream", - "version": "4.3.0", + "version": "4.4.0", "description": "Node.js Streams, a user-land copy of the stream library from Node.js", "homepage": "https://github.com/nodejs/readable-stream", "license": "MIT", diff --git a/node_modules/safe-buffer/index.js b/node_modules/safe-buffer/index.js index 22438dabbbcee..f8d3ec98852f4 100644 --- a/node_modules/safe-buffer/index.js +++ b/node_modules/safe-buffer/index.js @@ -1,3 +1,4 @@ +/*! safe-buffer. MIT License. Feross Aboukhadijeh */ /* eslint-disable node/no-deprecated-api */ var buffer = require('buffer') var Buffer = buffer.Buffer @@ -20,6 +21,8 @@ function SafeBuffer (arg, encodingOrOffset, length) { return Buffer(arg, encodingOrOffset, length) } +SafeBuffer.prototype = Object.create(Buffer.prototype) + // Copy static methods from Buffer copyProps(Buffer, SafeBuffer) diff --git a/node_modules/safe-buffer/package.json b/node_modules/safe-buffer/package.json index 623fbc3f6b0c4..f2869e256477a 100644 --- a/node_modules/safe-buffer/package.json +++ b/node_modules/safe-buffer/package.json @@ -1,18 +1,18 @@ { "name": "safe-buffer", "description": "Safer Node.js Buffer API", - "version": "5.1.2", + "version": "5.2.1", "author": { "name": "Feross Aboukhadijeh", "email": "feross@feross.org", - "url": "http://feross.org" + "url": "https://feross.org" }, "bugs": { "url": "https://github.com/feross/safe-buffer/issues" }, "devDependencies": { "standard": "*", - "tape": "^4.0.0" + "tape": "^5.0.0" }, "homepage": "https://github.com/feross/safe-buffer", "keywords": [ @@ -33,5 +33,19 @@ }, "scripts": { "test": "standard && tape test/*.js" - } + }, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] } diff --git a/node_modules/semver/classes/comparator.js b/node_modules/semver/classes/comparator.js index 2146c884bd937..3d39c0eef7802 100644 --- a/node_modules/semver/classes/comparator.js +++ b/node_modules/semver/classes/comparator.js @@ -16,6 +16,7 @@ class Comparator { } } + comp = comp.trim().split(/\s+/).join(' ') debug('comparator', comp, options) this.options = options this.loose = !!options.loose @@ -133,7 +134,7 @@ class Comparator { module.exports = Comparator const parseOptions = require('../internal/parse-options') -const { re, t } = require('../internal/re') +const { safeRe: re, t } = require('../internal/re') const cmp = require('../functions/cmp') const debug = require('../internal/debug') const SemVer = require('./semver') diff --git a/node_modules/semver/classes/range.js b/node_modules/semver/classes/range.js index d9e866de4dcd1..53c2540fd012e 100644 --- a/node_modules/semver/classes/range.js +++ b/node_modules/semver/classes/range.js @@ -26,19 +26,26 @@ class Range { this.loose = !!options.loose this.includePrerelease = !!options.includePrerelease - // First, split based on boolean or || + // First reduce all whitespace as much as possible so we do not have to rely + // on potentially slow regexes like \s*. This is then stored and used for + // future error messages as well. this.raw = range - this.set = range + .trim() + .split(/\s+/) + .join(' ') + + // First, split on || + this.set = this.raw .split('||') // map the range to a 2d array of comparators - .map(r => this.parseRange(r.trim())) + .map(r => this.parseRange(r)) // throw out any comparator lists that are empty // this generally means that it was not a valid range, which is allowed // in loose mode, but will still throw if the WHOLE range is invalid. .filter(c => c.length) if (!this.set.length) { - throw new TypeError(`Invalid SemVer Range: ${range}`) + throw new TypeError(`Invalid SemVer Range: ${this.raw}`) } // if we have any that are not the null set, throw out null sets. @@ -64,9 +71,7 @@ class Range { format () { this.range = this.set - .map((comps) => { - return comps.join(' ').trim() - }) + .map((comps) => comps.join(' ').trim()) .join('||') .trim() return this.range @@ -77,8 +82,6 @@ class Range { } parseRange (range) { - range = range.trim() - // memoize range parsing for performance. // this is a very hot path, and fully deterministic. const memoOpts = @@ -105,9 +108,6 @@ class Range { // `^ 1.2.3` => `^1.2.3` range = range.replace(re[t.CARETTRIM], caretTrimReplace) - // normalize spaces - range = range.split(/\s+/).join(' ') - // At this point, the range is completely trimmed and // ready to be split into comparators. @@ -203,7 +203,7 @@ const Comparator = require('./comparator') const debug = require('../internal/debug') const SemVer = require('./semver') const { - re, + safeRe: re, t, comparatorTrimReplace, tildeTrimReplace, @@ -257,10 +257,13 @@ const isX = id => !id || id.toLowerCase() === 'x' || id === '*' // ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0-0 // ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0-0 // ~0.0.1 --> >=0.0.1 <0.1.0-0 -const replaceTildes = (comp, options) => - comp.trim().split(/\s+/).map((c) => { - return replaceTilde(c, options) - }).join(' ') +const replaceTildes = (comp, options) => { + return comp + .trim() + .split(/\s+/) + .map((c) => replaceTilde(c, options)) + .join(' ') +} const replaceTilde = (comp, options) => { const r = options.loose ? re[t.TILDELOOSE] : re[t.TILDE] @@ -298,10 +301,13 @@ const replaceTilde = (comp, options) => { // ^1.2.0 --> >=1.2.0 <2.0.0-0 // ^0.0.1 --> >=0.0.1 <0.0.2-0 // ^0.1.0 --> >=0.1.0 <0.2.0-0 -const replaceCarets = (comp, options) => - comp.trim().split(/\s+/).map((c) => { - return replaceCaret(c, options) - }).join(' ') +const replaceCarets = (comp, options) => { + return comp + .trim() + .split(/\s+/) + .map((c) => replaceCaret(c, options)) + .join(' ') +} const replaceCaret = (comp, options) => { debug('caret', comp, options) @@ -358,9 +364,10 @@ const replaceCaret = (comp, options) => { const replaceXRanges = (comp, options) => { debug('replaceXRanges', comp, options) - return comp.split(/\s+/).map((c) => { - return replaceXRange(c, options) - }).join(' ') + return comp + .split(/\s+/) + .map((c) => replaceXRange(c, options)) + .join(' ') } const replaceXRange = (comp, options) => { @@ -443,12 +450,15 @@ const replaceXRange = (comp, options) => { const replaceStars = (comp, options) => { debug('replaceStars', comp, options) // Looseness is ignored here. star is always as loose as it gets! - return comp.trim().replace(re[t.STAR], '') + return comp + .trim() + .replace(re[t.STAR], '') } const replaceGTE0 = (comp, options) => { debug('replaceGTE0', comp, options) - return comp.trim() + return comp + .trim() .replace(re[options.includePrerelease ? t.GTE0PRE : t.GTE0], '') } @@ -486,7 +496,7 @@ const hyphenReplace = incPr => ($0, to = `<=${to}` } - return (`${from} ${to}`).trim() + return `${from} ${to}`.trim() } const testSet = (set, version, options) => { diff --git a/node_modules/semver/classes/semver.js b/node_modules/semver/classes/semver.js index 25ee889d1492a..84e84590e3871 100644 --- a/node_modules/semver/classes/semver.js +++ b/node_modules/semver/classes/semver.js @@ -1,6 +1,6 @@ const debug = require('../internal/debug') const { MAX_LENGTH, MAX_SAFE_INTEGER } = require('../internal/constants') -const { re, t } = require('../internal/re') +const { safeRe: re, t } = require('../internal/re') const parseOptions = require('../internal/parse-options') const { compareIdentifiers } = require('../internal/identifiers') @@ -16,7 +16,7 @@ class SemVer { version = version.version } } else if (typeof version !== 'string') { - throw new TypeError(`Invalid Version: ${require('util').inspect(version)}`) + throw new TypeError(`Invalid version. Must be a string. Got type "${typeof version}".`) } if (version.length > MAX_LENGTH) { @@ -291,8 +291,10 @@ class SemVer { default: throw new Error(`invalid increment argument: ${release}`) } - this.format() - this.raw = this.version + this.raw = this.format() + if (this.build.length) { + this.raw += `+${this.build.join('.')}` + } return this } } diff --git a/node_modules/semver/functions/coerce.js b/node_modules/semver/functions/coerce.js index 2e01452fddad6..febbff9c273ce 100644 --- a/node_modules/semver/functions/coerce.js +++ b/node_modules/semver/functions/coerce.js @@ -1,6 +1,6 @@ const SemVer = require('../classes/semver') const parse = require('./parse') -const { re, t } = require('../internal/re') +const { safeRe: re, t } = require('../internal/re') const coerce = (version, options) => { if (version instanceof SemVer) { diff --git a/node_modules/semver/functions/diff.js b/node_modules/semver/functions/diff.js index fafc11c40d345..fc224e302c0e4 100644 --- a/node_modules/semver/functions/diff.js +++ b/node_modules/semver/functions/diff.js @@ -13,6 +13,35 @@ const diff = (version1, version2) => { const highVersion = v1Higher ? v1 : v2 const lowVersion = v1Higher ? v2 : v1 const highHasPre = !!highVersion.prerelease.length + const lowHasPre = !!lowVersion.prerelease.length + + if (lowHasPre && !highHasPre) { + // Going from prerelease -> no prerelease requires some special casing + + // If the low version has only a major, then it will always be a major + // Some examples: + // 1.0.0-1 -> 1.0.0 + // 1.0.0-1 -> 1.1.1 + // 1.0.0-1 -> 2.0.0 + if (!lowVersion.patch && !lowVersion.minor) { + return 'major' + } + + // Otherwise it can be determined by checking the high version + + if (highVersion.patch) { + // anything higher than a patch bump would result in the wrong version + return 'patch' + } + + if (highVersion.minor) { + // anything higher than a minor bump would result in the wrong version + return 'minor' + } + + // bumping major/minor/patch all have same result + return 'major' + } // add the `pre` prefix if we are going to a prerelease version const prefix = highHasPre ? 'pre' : '' @@ -29,26 +58,8 @@ const diff = (version1, version2) => { return prefix + 'patch' } - // at this point we know stable versions match but overall versions are not equal, - // so either they are both prereleases, or the lower version is a prerelease - - if (highHasPre) { - // high and low are preleases - return 'prerelease' - } - - if (lowVersion.patch) { - // anything higher than a patch bump would result in the wrong version - return 'patch' - } - - if (lowVersion.minor) { - // anything higher than a minor bump would result in the wrong version - return 'minor' - } - - // bumping major/minor/patch all have same result - return 'major' + // high and low are preleases + return 'prerelease' } module.exports = diff diff --git a/node_modules/semver/internal/re.js b/node_modules/semver/internal/re.js index ed88398a9dbf5..f73ef1aa06263 100644 --- a/node_modules/semver/internal/re.js +++ b/node_modules/semver/internal/re.js @@ -4,16 +4,27 @@ exports = module.exports = {} // The actual regexps go on exports.re const re = exports.re = [] +const safeRe = exports.safeRe = [] const src = exports.src = [] const t = exports.t = {} let R = 0 const createToken = (name, value, isGlobal) => { + // Replace all greedy whitespace to prevent regex dos issues. These regex are + // used internally via the safeRe object since all inputs in this library get + // normalized first to trim and collapse all extra whitespace. The original + // regexes are exported for userland consumption and lower level usage. A + // future breaking change could export the safer regex only with a note that + // all input should have extra whitespace removed. + const safe = value + .split('\\s*').join('\\s{0,1}') + .split('\\s+').join('\\s') const index = R++ debug(name, index, value) t[name] = index src[index] = value re[index] = new RegExp(value, isGlobal ? 'g' : undefined) + safeRe[index] = new RegExp(safe, isGlobal ? 'g' : undefined) } // The following Regular Expressions can be used for tokenizing, diff --git a/node_modules/semver/package.json b/node_modules/semver/package.json index 0a6095b8900a6..7d0aff3c03c27 100644 --- a/node_modules/semver/package.json +++ b/node_modules/semver/package.json @@ -1,6 +1,6 @@ { "name": "semver", - "version": "7.5.0", + "version": "7.5.2", "description": "The semantic version parser used by npm.", "main": "index.js", "scripts": { @@ -14,7 +14,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", - "@npmcli/template-oss": "4.13.0", + "@npmcli/template-oss": "4.15.1", "tap": "^16.0.0" }, "license": "ISC", @@ -37,7 +37,7 @@ "range.bnf" ], "tap": { - "check-coverage": true, + "timeout": 30, "coverage-map": "map.js", "nyc-arg": [ "--exclude", @@ -53,7 +53,7 @@ "author": "GitHub Inc.", "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.13.0", + "version": "4.15.1", "engines": ">=10", "ciVersions": [ "10.0.0", diff --git a/node_modules/signal-exit/dist/cjs/index.js b/node_modules/signal-exit/dist/cjs/index.js index aef98326598c2..9312d0c96e879 100644 --- a/node_modules/signal-exit/dist/cjs/index.js +++ b/node_modules/signal-exit/dist/cjs/index.js @@ -34,7 +34,6 @@ class Emitter { id = Math.random(); constructor() { if (global[kExitEmitter]) { - console.error('reusing global emitter'); return global[kExitEmitter]; } ObjectDefineProperty(global, kExitEmitter, { diff --git a/node_modules/signal-exit/dist/mjs/index.js b/node_modules/signal-exit/dist/mjs/index.js index b9d1b569b733f..97f409239c8f3 100644 --- a/node_modules/signal-exit/dist/mjs/index.js +++ b/node_modules/signal-exit/dist/mjs/index.js @@ -30,7 +30,6 @@ class Emitter { id = Math.random(); constructor() { if (global[kExitEmitter]) { - console.error('reusing global emitter'); return global[kExitEmitter]; } ObjectDefineProperty(global, kExitEmitter, { diff --git a/node_modules/signal-exit/package.json b/node_modules/signal-exit/package.json index 5e7e3a74d95d8..455452f96a0b3 100644 --- a/node_modules/signal-exit/package.json +++ b/node_modules/signal-exit/package.json @@ -1,6 +1,6 @@ { "name": "signal-exit", - "version": "4.0.1", + "version": "4.0.2", "description": "when you want to fire an event no matter how a process exits.", "main": "./dist/cjs/index.js", "module": "./dist/mjs/index.js", diff --git a/node_modules/sigstore/dist/ca/index.js b/node_modules/sigstore/dist/ca/index.js index 7e0f9e0c5c4c0..340dd46609aad 100644 --- a/node_modules/sigstore/dist/ca/index.js +++ b/node_modules/sigstore/dist/ca/index.js @@ -6,13 +6,26 @@ const external_1 = require("../external"); const format_1 = require("./format"); class CAClient { constructor(options) { - this.fulcio = new external_1.Fulcio({ baseURL: options.fulcioBaseURL }); + this.fulcio = new external_1.Fulcio({ + baseURL: options.fulcioBaseURL, + retry: options.retry, + timeout: options.timeout, + }); } async createSigningCertificate(identityToken, publicKey, challenge) { const request = (0, format_1.toCertificateRequest)(identityToken, publicKey, challenge); try { - const certificate = await this.fulcio.createSigningCertificate(request); - return certificate.signedCertificateEmbeddedSct.chain.certificates; + const resp = await this.fulcio.createSigningCertificate(request); + // Account for the fact that the response may contain either a + // signedCertificateEmbeddedSct or a signedCertificateDetachedSct. + const cert = resp.signedCertificateEmbeddedSct + ? resp.signedCertificateEmbeddedSct + : resp.signedCertificateDetachedSct; + // Return the first certificate in the chain, which is the signing + // certificate. Specifically not returning the rest of the chain to + // mitigate the risk of errors when verifying the certificate chain. + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return cert.chain.certificates.slice(0, 1); } catch (err) { throw new error_1.InternalError({ diff --git a/node_modules/sigstore/dist/ca/verify/chain.js b/node_modules/sigstore/dist/ca/verify/chain.js index 0f6f714695728..3246c7a154e2d 100644 --- a/node_modules/sigstore/dist/ca/verify/chain.js +++ b/node_modules/sigstore/dist/ca/verify/chain.js @@ -19,12 +19,11 @@ limitations under the License. const error_1 = require("../../error"); const cert_1 = require("../../x509/cert"); const verify_1 = require("../../x509/verify"); -function verifyChain(bundleCerts, certificateAuthorities) { - const certs = parseCerts(bundleCerts); - const signingCert = certs[0]; +function verifyChain(certificate, certificateAuthorities) { + const untrustedCert = cert_1.x509Certificate.parse(certificate.rawBytes); // Filter the list of certificate authorities to those which are valid for the // signing certificate's notBefore date. - const validCAs = filterCertificateAuthorities(certificateAuthorities, signingCert.notBefore); + const validCAs = filterCertificateAuthorities(certificateAuthorities, untrustedCert.notBefore); if (validCAs.length === 0) { throw new error_1.VerificationError('No valid certificate authorities'); } @@ -34,9 +33,9 @@ function verifyChain(bundleCerts, certificateAuthorities) { const trustedCerts = parseCerts(ca.certChain?.certificates || []); try { trustedChain = (0, verify_1.verifyCertificateChain)({ + untrustedCert, trustedCerts, - certs, - validAt: signingCert.notBefore, + validAt: untrustedCert.notBefore, }); return true; } diff --git a/node_modules/sigstore/dist/ca/verify/index.js b/node_modules/sigstore/dist/ca/verify/index.js index 9c42f3094338f..32f85c828fe5a 100644 --- a/node_modules/sigstore/dist/ca/verify/index.js +++ b/node_modules/sigstore/dist/ca/verify/index.js @@ -6,8 +6,9 @@ const sct_1 = require("./sct"); const signer_1 = require("./signer"); function verifySigningCertificate(bundle, trustedRoot, options) { // Check that a trusted certificate chain can be found for the signing - // certificate in the bundle - const trustedChain = (0, chain_1.verifyChain)(bundle.verificationMaterial.content.x509CertificateChain.certificates, trustedRoot.certificateAuthorities); + // certificate in the bundle. Only the first certificate in the bundle's + // chain is used -- everything else must come from the trusted root. + const trustedChain = (0, chain_1.verifyChain)(bundle.verificationMaterial.content.x509CertificateChain.certificates[0], trustedRoot.certificateAuthorities); // Unless disabled, verify the SCTs in the signing certificate if (options.ctlogOptions.disable === false) { (0, sct_1.verifySCTs)(trustedChain, trustedRoot.ctlogs, options.ctlogOptions); diff --git a/node_modules/sigstore/dist/config.js b/node_modules/sigstore/dist/config.js index 7e6e42d9bf369..1a22c5fef313b 100644 --- a/node_modules/sigstore/dist/config.js +++ b/node_modules/sigstore/dist/config.js @@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.identityProviders = exports.artifactVerificationOptions = exports.createTLogClient = exports.createCAClient = exports.DEFAULT_REKOR_URL = exports.DEFAULT_FULCIO_URL = void 0; +exports.identityProviders = exports.artifactVerificationOptions = exports.createTSAClient = exports.createTLogClient = exports.createCAClient = exports.DEFAULT_TIMEOUT = exports.DEFAULT_RETRY = exports.DEFAULT_REKOR_URL = exports.DEFAULT_FULCIO_URL = void 0; /* Copyright 2023 The Sigstore Authors. @@ -45,21 +45,38 @@ limitations under the License. const ca_1 = require("./ca"); const identity_1 = __importDefault(require("./identity")); const tlog_1 = require("./tlog"); +const tsa_1 = require("./tsa"); const sigstore = __importStar(require("./types/sigstore")); exports.DEFAULT_FULCIO_URL = 'https://fulcio.sigstore.dev'; exports.DEFAULT_REKOR_URL = 'https://rekor.sigstore.dev'; +exports.DEFAULT_RETRY = { retries: 2 }; +exports.DEFAULT_TIMEOUT = 5000; function createCAClient(options) { return new ca_1.CAClient({ fulcioBaseURL: options.fulcioURL || exports.DEFAULT_FULCIO_URL, + retry: options.retry ?? exports.DEFAULT_RETRY, + timeout: options.timeout ?? exports.DEFAULT_TIMEOUT, }); } exports.createCAClient = createCAClient; function createTLogClient(options) { return new tlog_1.TLogClient({ rekorBaseURL: options.rekorURL || exports.DEFAULT_REKOR_URL, + retry: options.retry ?? exports.DEFAULT_RETRY, + timeout: options.timeout ?? exports.DEFAULT_TIMEOUT, }); } exports.createTLogClient = createTLogClient; +function createTSAClient(options) { + return options.tsaServerURL + ? new tsa_1.TSAClient({ + tsaBaseURL: options.tsaServerURL, + retry: options.retry ?? exports.DEFAULT_RETRY, + timeout: options.timeout ?? exports.DEFAULT_TIMEOUT, + }) + : undefined; +} +exports.createTSAClient = createTSAClient; // Assembles the AtifactVerificationOptions from the supplied VerifyOptions. function artifactVerificationOptions(options) { // The trusted signers are only used if the options contain a certificate diff --git a/node_modules/sigstore/dist/external/fulcio.js b/node_modules/sigstore/dist/external/fulcio.js index 288ca32caaea7..aeb48d58d8d83 100644 --- a/node_modules/sigstore/dist/external/fulcio.js +++ b/node_modules/sigstore/dist/external/fulcio.js @@ -28,8 +28,8 @@ const error_1 = require("./error"); class Fulcio { constructor(options) { this.fetch = make_fetch_happen_1.default.defaults({ - retry: { retries: 2 }, - timeout: 5000, + retry: options.retry, + timeout: options.timeout, headers: { 'Content-Type': 'application/json', 'User-Agent': util_1.ua.getUserAgent(), diff --git a/node_modules/sigstore/dist/external/index.js b/node_modules/sigstore/dist/external/index.js index da5f084001279..f40816e9b7ca4 100644 --- a/node_modules/sigstore/dist/external/index.js +++ b/node_modules/sigstore/dist/external/index.js @@ -1,6 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.Rekor = exports.Fulcio = exports.HTTPError = void 0; +exports.TimestampAuthority = exports.Rekor = exports.Fulcio = exports.HTTPError = void 0; /* Copyright 2022 The Sigstore Authors. @@ -22,3 +22,5 @@ var fulcio_1 = require("./fulcio"); Object.defineProperty(exports, "Fulcio", { enumerable: true, get: function () { return fulcio_1.Fulcio; } }); var rekor_1 = require("./rekor"); Object.defineProperty(exports, "Rekor", { enumerable: true, get: function () { return rekor_1.Rekor; } }); +var tsa_1 = require("./tsa"); +Object.defineProperty(exports, "TimestampAuthority", { enumerable: true, get: function () { return tsa_1.TimestampAuthority; } }); diff --git a/node_modules/sigstore/dist/external/rekor.js b/node_modules/sigstore/dist/external/rekor.js index 6bb085c44cecd..b6bbeb6f20793 100644 --- a/node_modules/sigstore/dist/external/rekor.js +++ b/node_modules/sigstore/dist/external/rekor.js @@ -28,8 +28,8 @@ const error_1 = require("./error"); class Rekor { constructor(options) { this.fetch = make_fetch_happen_1.default.defaults({ - retry: { retries: 2 }, - timeout: 5000, + retry: options.retry, + timeout: options.timeout, headers: { Accept: 'application/json', 'User-Agent': util_1.ua.getUserAgent(), @@ -39,7 +39,7 @@ class Rekor { } /** * Create a new entry in the Rekor log. - * @param propsedEntry {EntryKind} Data to create a new entry + * @param propsedEntry {ProposedEntry} Data to create a new entry * @returns {Promise} The created entry */ async createEntry(propsedEntry) { @@ -107,7 +107,7 @@ function entryFromResponse(data) { throw new Error('Received multiple entries in Rekor response'); } // Grab UUID and entry data from the response - const [uuid, entry] = Object.entries(data)[0]; + const [uuid, entry] = entries[0]; return { ...entry, uuid, diff --git a/node_modules/sigstore/dist/external/tsa.js b/node_modules/sigstore/dist/external/tsa.js new file mode 100644 index 0000000000000..5277d7d3f9707 --- /dev/null +++ b/node_modules/sigstore/dist/external/tsa.js @@ -0,0 +1,47 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.TimestampAuthority = void 0; +/* +Copyright 2023 The Sigstore Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +const make_fetch_happen_1 = __importDefault(require("make-fetch-happen")); +const util_1 = require("../util"); +const error_1 = require("./error"); +class TimestampAuthority { + constructor(options) { + this.fetch = make_fetch_happen_1.default.defaults({ + retry: options.retry, + timeout: options.timeout, + headers: { + 'Content-Type': 'application/json', + 'User-Agent': util_1.ua.getUserAgent(), + }, + }); + this.baseUrl = options.baseURL; + } + async createTimestamp(request) { + const url = `${this.baseUrl}/api/v1/timestamp`; + const response = await this.fetch(url, { + method: 'POST', + body: JSON.stringify(request), + }); + (0, error_1.checkStatus)(response); + return response.buffer(); + } +} +exports.TimestampAuthority = TimestampAuthority; diff --git a/node_modules/sigstore/dist/index.js b/node_modules/sigstore/dist/index.js index 502155e4d5f3f..126fce58e45bd 100644 --- a/node_modules/sigstore/dist/index.js +++ b/node_modules/sigstore/dist/index.js @@ -24,19 +24,4 @@ var __importStar = (this && this.__importStar) || function (mod) { }; Object.defineProperty(exports, "__esModule", { value: true }); exports.sigstore = void 0; -/* -Copyright 2022 The Sigstore Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ exports.sigstore = __importStar(require("./sigstore")); diff --git a/node_modules/sigstore/dist/sign.js b/node_modules/sigstore/dist/sign.js index 97c3da04b065b..96e6272750b49 100644 --- a/node_modules/sigstore/dist/sign.js +++ b/node_modules/sigstore/dist/sign.js @@ -1,13 +1,39 @@ "use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; Object.defineProperty(exports, "__esModule", { value: true }); exports.Signer = void 0; +const sigstore = __importStar(require("./types/sigstore")); const util_1 = require("./util"); class Signer { constructor(options) { this.identityProviders = []; this.ca = options.ca; this.tlog = options.tlog; + this.tsa = options.tsa; this.identityProviders = options.identityProviders; + this.tlogUpload = options.tlogUpload ?? true; this.signer = options.signer || this.signWithEphemeralKey.bind(this); } async signBlob(payload) { @@ -15,8 +41,18 @@ class Signer { const sigMaterial = await this.signer(payload); // Calculate artifact digest const digest = util_1.crypto.hash(payload); - // Create Rekor entry - return this.tlog.createMessageSignatureEntry(digest, sigMaterial); + // Create a Rekor entry (if tlogUpload is enabled) + const entry = this.tlogUpload + ? await this.tlog.createMessageSignatureEntry(digest, sigMaterial) + : undefined; + return sigstore.toMessageSignatureBundle({ + digest, + signature: sigMaterial, + tlogEntry: entry, + timestamp: this.tsa + ? await this.tsa.createTimestamp(sigMaterial.signature) + : undefined, + }); } async signAttestation(payload, payloadType) { // Pre-authentication encoding to be signed @@ -33,7 +69,18 @@ class Signer { }, ], }; - return this.tlog.createDSSEEntry(envelope, sigMaterial); + // Create a Rekor entry (if tlogUpload is enabled) + const entry = this.tlogUpload + ? await this.tlog.createDSSEEntry(envelope, sigMaterial) + : undefined; + return sigstore.toDSSEBundle({ + envelope, + signature: sigMaterial, + tlogEntry: entry, + timestamp: this.tsa + ? await this.tsa.createTimestamp(sigMaterial.signature) + : undefined, + }); } async signWithEphemeralKey(payload) { // Create emphemeral key pair diff --git a/node_modules/sigstore/dist/sigstore-utils.js b/node_modules/sigstore/dist/sigstore-utils.js index 79918a806b17d..1341052047229 100644 --- a/node_modules/sigstore/dist/sigstore-utils.js +++ b/node_modules/sigstore/dist/sigstore-utils.js @@ -67,9 +67,14 @@ async function createRekorEntry(dsseEnvelope, publicKey, options = {}) { const envelope = sigstore.Envelope.fromJSON(dsseEnvelope); const tlog = (0, config_1.createTLogClient)(options); const sigMaterial = (0, signature_1.extractSignatureMaterial)(envelope, publicKey); - const bundle = await tlog.createDSSEEntry(envelope, sigMaterial, { + const entry = await tlog.createDSSEEntry(envelope, sigMaterial, { fetchOnConflict: true, }); + const bundle = sigstore.toDSSEBundle({ + envelope, + signature: sigMaterial, + tlogEntry: entry, + }); return sigstore.Bundle.toJSON(bundle); } exports.createRekorEntry = createRekorEntry; diff --git a/node_modules/sigstore/dist/sigstore.js b/node_modules/sigstore/dist/sigstore.js index f45270217b017..a14c5957954d8 100644 --- a/node_modules/sigstore/dist/sigstore.js +++ b/node_modules/sigstore/dist/sigstore.js @@ -39,9 +39,9 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ +const tuf = __importStar(require("@sigstore/tuf")); const config = __importStar(require("./config")); const sign_1 = require("./sign"); -const tuf = __importStar(require("./tuf")); const sigstore = __importStar(require("./types/sigstore")); const verify_1 = require("./verify"); async function sign(payload, options = {}) { @@ -51,7 +51,10 @@ async function sign(payload, options = {}) { const signer = new sign_1.Signer({ ca, tlog, - identityProviders: idps, + identityProviders: options.identityProvider + ? [options.identityProvider] + : idps, + tlogUpload: options.tlogUpload, }); const bundle = await signer.signBlob(payload); return sigstore.Bundle.toJSON(bundle); @@ -60,11 +63,16 @@ exports.sign = sign; async function attest(payload, payloadType, options = {}) { const ca = config.createCAClient(options); const tlog = config.createTLogClient(options); + const tsa = config.createTSAClient(options); const idps = config.identityProviders(options); const signer = new sign_1.Signer({ ca, tlog, - identityProviders: idps, + tsa, + identityProviders: options.identityProvider + ? [options.identityProvider] + : idps, + tlogUpload: options.tlogUpload, }); const bundle = await signer.signAttestation(payload, payloadType); return sigstore.Bundle.toJSON(bundle); @@ -75,6 +83,8 @@ async function verify(bundle, payload, options = {}) { mirrorURL: options.tufMirrorURL, rootPath: options.tufRootPath, cachePath: options.tufCachePath, + retry: options.retry ?? config.DEFAULT_RETRY, + timeout: options.timeout ?? config.DEFAULT_TIMEOUT, }); const verifier = new verify_1.Verifier(trustedRoot, options.keySelector); const deserializedBundle = sigstore.bundleFromJSON(bundle); @@ -83,13 +93,29 @@ async function verify(bundle, payload, options = {}) { } exports.verify = verify; const tufUtils = { - getTarget: (path, options = {}) => { - return tuf.getTarget(path, { + client: (options = {}) => { + return tuf.initTUF({ mirrorURL: options.tufMirrorURL, rootPath: options.tufRootPath, cachePath: options.tufCachePath, + retry: options.retry, + timeout: options.timeout, }); }, + /* + * @deprecated Use tufUtils.client instead. + */ + getTarget: (path, options = {}) => { + return tuf + .initTUF({ + mirrorURL: options.tufMirrorURL, + rootPath: options.tufRootPath, + cachePath: options.tufCachePath, + retry: options.retry, + timeout: options.timeout, + }) + .then((t) => t.getTarget(path)); + }, }; exports.tuf = tufUtils; var error_1 = require("./error"); diff --git a/node_modules/sigstore/dist/tlog/format.js b/node_modules/sigstore/dist/tlog/format.js index 67077090455a1..b0eae95098af0 100644 --- a/node_modules/sigstore/dist/tlog/format.js +++ b/node_modules/sigstore/dist/tlog/format.js @@ -1,10 +1,22 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.toProposedIntotoEntry = exports.toProposedHashedRekordEntry = void 0; +exports.toProposedIntotoEntry = exports.toProposedHashedRekordEntry = exports.toProposedDSSEEntry = void 0; +const sigstore_1 = require("../types/sigstore"); const util_1 = require("../util"); -const types_1 = require("./types"); +const DEFAULT_DSSE_API_VERSION = '0.0.1'; const DEFAULT_HASHEDREKORD_API_VERSION = '0.0.1'; const DEFAULT_INTOTO_API_VERSION = '0.0.2'; +// Returns a properly formatted Rekor "dsse" entry for the given DSSE +// envelope and signature +function toProposedDSSEEntry(envelope, signature, apiVersion = DEFAULT_DSSE_API_VERSION) { + switch (apiVersion) { + case '0.0.1': + return toProposedDSSEV001Entry(envelope, signature); + default: + throw new Error(`Unsupported dsse kind API version: ${apiVersion}`); + } +} +exports.toProposedDSSEEntry = toProposedDSSEEntry; // Returns a properly formatted Rekor "hashedrekord" entry for the given digest // and signature function toProposedHashedRekordEntry(digest, signature) { @@ -13,7 +25,7 @@ function toProposedHashedRekordEntry(digest, signature) { const b64Key = util_1.encoding.base64Encode(toPublicKey(signature)); return { apiVersion: DEFAULT_HASHEDREKORD_API_VERSION, - kind: types_1.HASHEDREKORD_KIND, + kind: 'hashedrekord', spec: { data: { hash: { @@ -42,11 +54,23 @@ function toProposedIntotoEntry(envelope, signature, apiVersion = DEFAULT_INTOTO_ } } exports.toProposedIntotoEntry = toProposedIntotoEntry; +function toProposedDSSEV001Entry(envelope, signature) { + return { + apiVersion: '0.0.1', + kind: 'dsse', + spec: { + proposedContent: { + envelope: JSON.stringify(sigstore_1.Envelope.toJSON(envelope)), + verifiers: [util_1.encoding.base64Encode(toPublicKey(signature))], + }, + }, + }; +} function toProposedIntotoV002Entry(envelope, signature) { // Calculate the value for the payloadHash field in the Rekor entry const payloadHash = util_1.crypto.hash(envelope.payload).toString('hex'); // Calculate the value for the hash field in the Rekor entry - const envelopeHash = calculateDSSEHash(envelope); + const envelopeHash = calculateDSSEHash(envelope, signature); // Collect values for re-creating the DSSE envelope. // Double-encode payload and signature cause that's what Rekor expects const payload = util_1.encoding.base64Encode(envelope.payload.toString('base64')); @@ -56,7 +80,7 @@ function toProposedIntotoV002Entry(envelope, signature) { // Create the envelope portion of the entry. Note the inclusion of the // publicKey in the signature struct is not a standard part of a DSSE // envelope, but is required by Rekor. - const dsse = { + const dsseEnv = { payloadType: envelope.payloadType, payload: payload, signatures: [{ sig, publicKey }], @@ -65,14 +89,14 @@ function toProposedIntotoV002Entry(envelope, signature) { // need to do the same here so that we can properly recreate the entry for // verification. if (keyid.length > 0) { - dsse.signatures[0].keyid = keyid; + dsseEnv.signatures[0].keyid = keyid; } return { apiVersion: '0.0.2', - kind: types_1.INTOTO_KIND, + kind: 'intoto', spec: { content: { - envelope: dsse, + envelope: dsseEnv, hash: { algorithm: 'sha256', value: envelopeHash }, payloadHash: { algorithm: 'sha256', value: payloadHash }, }, @@ -86,17 +110,22 @@ function toProposedIntotoV002Entry(envelope, signature) { // * signature is base64 encoded (only the first signature is used) // * keyid is included ONLY if it is NOT an empty string // * The resulting JSON is canonicalized and hashed to a hex string -function calculateDSSEHash(envelope) { - const dsse = { +function calculateDSSEHash(envelope, signature) { + const dsseEnv = { payloadType: envelope.payloadType, payload: envelope.payload.toString('base64'), - signatures: [{ sig: envelope.signatures[0].sig.toString('base64') }], + signatures: [ + { + sig: envelope.signatures[0].sig.toString('base64'), + publicKey: toPublicKey(signature), + }, + ], }; // If the keyid is an empty string, Rekor seems to remove it altogether. if (envelope.signatures[0].keyid.length > 0) { - dsse.signatures[0].keyid = envelope.signatures[0].keyid; + dsseEnv.signatures[0].keyid = envelope.signatures[0].keyid; } - return util_1.crypto.hash(util_1.json.canonicalize(dsse)).toString('hex'); + return util_1.crypto.hash(util_1.json.canonicalize(dsseEnv)).toString('hex'); } function toPublicKey(signature) { return signature.certificates diff --git a/node_modules/sigstore/dist/tlog/index.js b/node_modules/sigstore/dist/tlog/index.js index 4193e55752ff0..7f5f531983b37 100644 --- a/node_modules/sigstore/dist/tlog/index.js +++ b/node_modules/sigstore/dist/tlog/index.js @@ -18,21 +18,22 @@ limitations under the License. */ const error_1 = require("../error"); const external_1 = require("../external"); -const sigstore_1 = require("../types/sigstore"); const format_1 = require("./format"); class TLogClient { constructor(options) { - this.rekor = new external_1.Rekor({ baseURL: options.rekorBaseURL }); + this.rekor = new external_1.Rekor({ + baseURL: options.rekorBaseURL, + retry: options.retry, + timeout: options.timeout, + }); } async createMessageSignatureEntry(digest, sigMaterial, options = {}) { const proposedEntry = (0, format_1.toProposedHashedRekordEntry)(digest, sigMaterial); - const entry = await this.createEntry(proposedEntry, options.fetchOnConflict); - return sigstore_1.bundle.toMessageSignatureBundle(digest, sigMaterial, entry); + return this.createEntry(proposedEntry, options.fetchOnConflict); } async createDSSEEntry(envelope, sigMaterial, options = {}) { const proposedEntry = (0, format_1.toProposedIntotoEntry)(envelope, sigMaterial); - const entry = await this.createEntry(proposedEntry, options.fetchOnConflict); - return sigstore_1.bundle.toDSSEBundle(envelope, sigMaterial, entry); + return this.createEntry(proposedEntry, options.fetchOnConflict); } async createEntry(proposedEntry, fetchOnConflict = false) { let entry; diff --git a/node_modules/sigstore/dist/tlog/types/__generated__/hashedrekord.js b/node_modules/sigstore/dist/tlog/types/__generated__/hashedrekord.js deleted file mode 100644 index 61923a61cd8de..0000000000000 --- a/node_modules/sigstore/dist/tlog/types/__generated__/hashedrekord.js +++ /dev/null @@ -1,8 +0,0 @@ -"use strict"; -/* eslint-disable */ -/** - * This file was automatically generated by json-schema-to-typescript. - * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, - * and run json-schema-to-typescript to regenerate this file. - */ -Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/node_modules/sigstore/dist/tlog/types/__generated__/intoto.js b/node_modules/sigstore/dist/tlog/types/__generated__/intoto.js deleted file mode 100644 index 61923a61cd8de..0000000000000 --- a/node_modules/sigstore/dist/tlog/types/__generated__/intoto.js +++ /dev/null @@ -1,8 +0,0 @@ -"use strict"; -/* eslint-disable */ -/** - * This file was automatically generated by json-schema-to-typescript. - * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, - * and run json-schema-to-typescript to regenerate this file. - */ -Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/node_modules/sigstore/dist/tlog/types/index.js b/node_modules/sigstore/dist/tlog/types/index.js deleted file mode 100644 index d6394a95c8397..0000000000000 --- a/node_modules/sigstore/dist/tlog/types/index.js +++ /dev/null @@ -1,5 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.HASHEDREKORD_KIND = exports.INTOTO_KIND = void 0; -exports.INTOTO_KIND = 'intoto'; -exports.HASHEDREKORD_KIND = 'hashedrekord'; diff --git a/node_modules/sigstore/dist/tlog/verify/body.js b/node_modules/sigstore/dist/tlog/verify/body.js index 086e068a30dcb..5a265e5190c12 100644 --- a/node_modules/sigstore/dist/tlog/verify/body.js +++ b/node_modules/sigstore/dist/tlog/verify/body.js @@ -28,6 +28,9 @@ function verifyTLogBody(entry, bundleContent) { throw new error_1.VerificationError(TLOG_MISMATCH_ERROR_MSG); } switch (body.kind) { + case 'dsse': + verifyDSSETLogBody(body, bundleContent); + break; case 'intoto': verifyIntotoTLogBody(body, bundleContent); break; @@ -45,6 +48,20 @@ function verifyTLogBody(entry, bundleContent) { } exports.verifyTLogBody = verifyTLogBody; // Compare the given intoto tlog entry to the given bundle +function verifyDSSETLogBody(tlogEntry, content) { + if (content?.$case !== 'dsseEnvelope') { + throw new error_1.VerificationError(`unsupported bundle content: ${content?.$case || 'unknown'}`); + } + const dsse = content.dsseEnvelope; + switch (tlogEntry.apiVersion) { + case '0.0.1': + verifyDSSE001TLogBody(tlogEntry, dsse); + break; + default: + throw new error_1.VerificationError(`unsupported dsse version: ${tlogEntry.apiVersion}`); + } +} +// Compare the given intoto tlog entry to the given bundle function verifyIntotoTLogBody(tlogEntry, content) { if (content?.$case !== 'dsseEnvelope') { throw new error_1.VerificationError(`unsupported bundle content: ${content?.$case || 'unknown'}`); @@ -72,6 +89,28 @@ function verifyHashedRekordTLogBody(tlogEntry, content) { throw new error_1.VerificationError(`unsupported hashedrekord version: ${tlogEntry.apiVersion}`); } } +// Compare the given dsse v0.0.1 tlog entry to the given DSSE envelope. +function verifyDSSE001TLogBody(tlogEntry, dsse) { + // Collect all of the signatures from the DSSE envelope + // Turns them into base64-encoded strings for comparison + const dsseSigs = dsse.signatures.map((signature) => signature.sig.toString('base64')); + // Collect all of the signatures from the tlog entry + const tlogSigs = tlogEntry.spec.signatures?.map((signature) => signature.signature); + // Ensure the bundle's DSSE and the tlog entry contain the same number of signatures + if (dsseSigs.length !== tlogSigs?.length) { + throw new error_1.VerificationError(TLOG_MISMATCH_ERROR_MSG); + } + // Ensure that every signature in the bundle's DSSE is present in the tlog entry + if (!dsseSigs.every((dsseSig) => tlogSigs.includes(dsseSig))) { + throw new error_1.VerificationError(TLOG_MISMATCH_ERROR_MSG); + } + // Ensure the digest of the bundle's DSSE payload matches the digest in the + // tlog entry + const dssePayloadHash = util_1.crypto.hash(dsse.payload).toString('hex'); + if (dssePayloadHash !== tlogEntry.spec.payloadHash?.value) { + throw new error_1.VerificationError(TLOG_MISMATCH_ERROR_MSG); + } +} // Compare the given intoto v0.0.2 tlog entry to the given DSSE envelope. function verifyIntoto002TLogBody(tlogEntry, dsse) { // Collect all of the signatures from the DSSE envelope diff --git a/node_modules/sigstore/dist/tsa/index.js b/node_modules/sigstore/dist/tsa/index.js new file mode 100644 index 0000000000000..4951b24a93f4f --- /dev/null +++ b/node_modules/sigstore/dist/tsa/index.js @@ -0,0 +1,47 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.TSAClient = void 0; +/* +Copyright 2022 The Sigstore Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +const error_1 = require("../error"); +const external_1 = require("../external"); +const util_1 = require("../util"); +class TSAClient { + constructor(options) { + this.tsa = new external_1.TimestampAuthority({ + baseURL: options.tsaBaseURL, + retry: options.retry, + timeout: options.timeout, + }); + } + async createTimestamp(signature) { + const request = { + artifactHash: util_1.crypto.hash(signature).toString('base64'), + hashAlgorithm: 'sha256', + }; + try { + return await this.tsa.createTimestamp(request); + } + catch (err) { + throw new error_1.InternalError({ + code: 'TSA_CREATE_TIMESTAMP_ERROR', + message: 'error creating timestamp', + cause: err, + }); + } + } +} +exports.TSAClient = TSAClient; diff --git a/node_modules/sigstore/dist/types/fetch.js b/node_modules/sigstore/dist/types/fetch.js new file mode 100644 index 0000000000000..c8ad2e549bdc6 --- /dev/null +++ b/node_modules/sigstore/dist/types/fetch.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/node_modules/sigstore/dist/types/sigstore/index.js b/node_modules/sigstore/dist/types/sigstore/index.js index 9fcdb42bdcf34..4d9f6003744da 100644 --- a/node_modules/sigstore/dist/types/sigstore/index.js +++ b/node_modules/sigstore/dist/types/sigstore/index.js @@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.signingCertificate = exports.bundle = exports.isVerifiableTransparencyLogEntry = exports.isCAVerificationOptions = exports.isBundleWithCertificateChain = exports.isBundleWithVerificationMaterial = exports.bundleFromJSON = void 0; +exports.signingCertificate = exports.toMessageSignatureBundle = exports.toDSSEBundle = exports.isVerifiableTransparencyLogEntry = exports.isCAVerificationOptions = exports.isBundleWithCertificateChain = exports.isBundleWithVerificationMaterial = exports.bundleFromJSON = void 0; /* Copyright 2023 The Sigstore Authors. @@ -69,16 +69,20 @@ function isVerifiableTransparencyLogEntry(entry) { entry.kindVersion !== undefined); } exports.isVerifiableTransparencyLogEntry = isVerifiableTransparencyLogEntry; -exports.bundle = { - toDSSEBundle: (envelope, signature, rekorEntry) => ({ +function toDSSEBundle({ envelope, signature, tlogEntry, timestamp, }) { + return { mediaType: BUNDLE_MEDIA_TYPE, - content: { - $case: 'dsseEnvelope', - dsseEnvelope: envelope, - }, - verificationMaterial: toVerificationMaterial(signature, rekorEntry), - }), - toMessageSignatureBundle: (digest, signature, rekorEntry) => ({ + content: { $case: 'dsseEnvelope', dsseEnvelope: envelope }, + verificationMaterial: toVerificationMaterial({ + signature, + tlogEntry, + timestamp, + }), + }; +} +exports.toDSSEBundle = toDSSEBundle; +function toMessageSignatureBundle({ digest, signature, tlogEntry, timestamp, }) { + return { mediaType: BUNDLE_MEDIA_TYPE, content: { $case: 'messageSignature', @@ -90,11 +94,17 @@ exports.bundle = { signature: signature.signature, }, }, - verificationMaterial: toVerificationMaterial(signature, rekorEntry), - }), -}; + verificationMaterial: toVerificationMaterial({ + signature, + tlogEntry, + timestamp, + }), + }; +} +exports.toMessageSignatureBundle = toMessageSignatureBundle; function toTransparencyLogEntry(entry) { - const set = Buffer.from(entry.verification.signedEntryTimestamp, 'base64'); + const b64SET = entry.verification?.signedEntryTimestamp || ''; + const set = Buffer.from(b64SET, 'base64'); const logID = Buffer.from(entry.logID, 'hex'); // Parse entry body so we can extract the kind and version. const bodyJSON = util_1.encoding.base64Decode(entry.body); @@ -116,13 +126,15 @@ function toTransparencyLogEntry(entry) { canonicalizedBody: Buffer.from(entry.body, 'base64'), }; } -function toVerificationMaterial(signature, entry) { +function toVerificationMaterial({ signature, tlogEntry, timestamp, }) { return { content: signature.certificates ? toVerificationMaterialx509CertificateChain(signature.certificates) : toVerificationMaterialPublicKey(signature.key.id || ''), - tlogEntries: [toTransparencyLogEntry(entry)], - timestampVerificationData: undefined, + tlogEntries: tlogEntry ? [toTransparencyLogEntry(tlogEntry)] : [], + timestampVerificationData: timestamp + ? toTimestampVerificationData(timestamp) + : undefined, }; } function toVerificationMaterialx509CertificateChain(certificates) { @@ -138,6 +150,11 @@ function toVerificationMaterialx509CertificateChain(certificates) { function toVerificationMaterialPublicKey(hint) { return { $case: 'publicKey', publicKey: { hint } }; } +function toTimestampVerificationData(timestamp) { + return { + rfc3161Timestamps: [{ signedTimestamp: timestamp }], + }; +} function signingCertificate(bundle) { if (!isBundleWithCertificateChain(bundle)) { return undefined; diff --git a/node_modules/sigstore/dist/x509/asn1/dump.js b/node_modules/sigstore/dist/util/asn1/dump.js similarity index 100% rename from node_modules/sigstore/dist/x509/asn1/dump.js rename to node_modules/sigstore/dist/util/asn1/dump.js diff --git a/node_modules/sigstore/dist/x509/asn1/error.js b/node_modules/sigstore/dist/util/asn1/error.js similarity index 100% rename from node_modules/sigstore/dist/x509/asn1/error.js rename to node_modules/sigstore/dist/util/asn1/error.js diff --git a/node_modules/sigstore/dist/util/asn1/index.js b/node_modules/sigstore/dist/util/asn1/index.js new file mode 100644 index 0000000000000..348b2ea4022e5 --- /dev/null +++ b/node_modules/sigstore/dist/util/asn1/index.js @@ -0,0 +1,20 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ASN1Obj = void 0; +/* +Copyright 2023 The Sigstore Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +var obj_1 = require("./obj"); +Object.defineProperty(exports, "ASN1Obj", { enumerable: true, get: function () { return obj_1.ASN1Obj; } }); diff --git a/node_modules/sigstore/dist/x509/asn1/length.js b/node_modules/sigstore/dist/util/asn1/length.js similarity index 100% rename from node_modules/sigstore/dist/x509/asn1/length.js rename to node_modules/sigstore/dist/util/asn1/length.js diff --git a/node_modules/sigstore/dist/x509/asn1/obj.js b/node_modules/sigstore/dist/util/asn1/obj.js similarity index 95% rename from node_modules/sigstore/dist/x509/asn1/obj.js rename to node_modules/sigstore/dist/util/asn1/obj.js index 712acf105adfc..5f9ac9cdbc493 100644 --- a/node_modules/sigstore/dist/x509/asn1/obj.js +++ b/node_modules/sigstore/dist/util/asn1/obj.js @@ -16,7 +16,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -const stream_1 = require("../../util/stream"); +const stream_1 = require("../stream"); const error_1 = require("./error"); const length_1 = require("./length"); const parse_1 = require("./parse"); @@ -132,7 +132,10 @@ function parseStream(stream) { function collectSubs(stream, len) { // Calculate end of object content const end = stream.position + len; - // Make sure there are enough bytes left in the stream + // Make sure there are enough bytes left in the stream. This should never + // happen, cause it'll get caught when the stream is sliced in parseStream. + // Leaving as an extra check just in case. + /* istanbul ignore if */ if (end > stream.length) { throw new error_1.ASN1ParseError('invalid length'); } diff --git a/node_modules/sigstore/dist/x509/asn1/parse.js b/node_modules/sigstore/dist/util/asn1/parse.js similarity index 100% rename from node_modules/sigstore/dist/x509/asn1/parse.js rename to node_modules/sigstore/dist/util/asn1/parse.js diff --git a/node_modules/sigstore/dist/x509/asn1/tag.js b/node_modules/sigstore/dist/util/asn1/tag.js similarity index 100% rename from node_modules/sigstore/dist/x509/asn1/tag.js rename to node_modules/sigstore/dist/util/asn1/tag.js diff --git a/node_modules/sigstore/dist/util/index.js b/node_modules/sigstore/dist/util/index.js index 74ef9c0b1121b..b7d6ce21aafd3 100644 --- a/node_modules/sigstore/dist/util/index.js +++ b/node_modules/sigstore/dist/util/index.js @@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) { return result; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.ua = exports.promise = exports.pem = exports.oidc = exports.json = exports.encoding = exports.dsse = exports.crypto = exports.appdata = void 0; +exports.ua = exports.promise = exports.pem = exports.oidc = exports.json = exports.encoding = exports.dsse = exports.crypto = exports.asn1 = void 0; /* Copyright 2022 The Sigstore Authors. @@ -39,7 +39,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -exports.appdata = __importStar(require("./appdata")); +exports.asn1 = __importStar(require("./asn1")); exports.crypto = __importStar(require("./crypto")); exports.dsse = __importStar(require("./dsse")); exports.encoding = __importStar(require("./encoding")); diff --git a/node_modules/sigstore/dist/util/stream.js b/node_modules/sigstore/dist/util/stream.js index d5c8236123cdf..b5c881bb388d4 100644 --- a/node_modules/sigstore/dist/util/stream.js +++ b/node_modules/sigstore/dist/util/stream.js @@ -112,5 +112,5 @@ class ByteStream { this.view = newView; } } -ByteStream.BLOCK_SIZE = 1024; exports.ByteStream = ByteStream; +ByteStream.BLOCK_SIZE = 1024; diff --git a/node_modules/sigstore/dist/verify.js b/node_modules/sigstore/dist/verify.js index 9d21b553ac523..49f63d93abb26 100644 --- a/node_modules/sigstore/dist/verify.js +++ b/node_modules/sigstore/dist/verify.js @@ -41,7 +41,9 @@ class Verifier { if (sigstore.isBundleWithCertificateChain(bundle)) { this.verifySigningCertificate(bundle, options); } - this.verifyTLogEntries(bundle, options); + if (options.tlogOptions.disable === false) { + this.verifyTLogEntries(bundle, options); + } } // Performs bundle signature verification. Determines the type of the bundle // content and delegates to the appropriate signature verification function. diff --git a/node_modules/sigstore/dist/x509/cert.js b/node_modules/sigstore/dist/x509/cert.js index 0b8ab54740a06..ec14b5f47369d 100644 --- a/node_modules/sigstore/dist/x509/cert.js +++ b/node_modules/sigstore/dist/x509/cert.js @@ -2,8 +2,8 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.x509Certificate = void 0; const util_1 = require("../util"); +const asn1_1 = require("../util/asn1"); const stream_1 = require("../util/stream"); -const obj_1 = require("./asn1/obj"); const ext_1 = require("./ext"); const EXTENSION_OID_SUBJECT_KEY_ID = '2.5.29.14'; const EXTENSION_OID_KEY_USAGE = '2.5.29.15'; @@ -33,7 +33,7 @@ class x509Certificate { } static parse(cert) { const der = typeof cert === 'string' ? util_1.pem.toDER(cert) : cert; - const asn1 = obj_1.ASN1Obj.parseBuffer(der); + const asn1 = asn1_1.ASN1Obj.parseBuffer(der); return new x509Certificate(asn1); } get tbsCertificate() { diff --git a/node_modules/sigstore/dist/x509/ext.js b/node_modules/sigstore/dist/x509/ext.js index c1743dce5556d..246aeb095802f 100644 --- a/node_modules/sigstore/dist/x509/ext.js +++ b/node_modules/sigstore/dist/x509/ext.js @@ -1,21 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.x509SCTExtension = exports.x509SubjectKeyIDExtension = exports.x509AuthorityKeyIDExtension = exports.x509SubjectAlternativeNameExtension = exports.x509KeyUsageExtension = exports.x509BasicConstraintsExtension = exports.x509Extension = void 0; -/* -Copyright 2023 The Sigstore Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ const stream_1 = require("../util/stream"); const sct_1 = require("./sct"); // https://www.rfc-editor.org/rfc/rfc5280#section-4.1 diff --git a/node_modules/sigstore/dist/x509/verify.js b/node_modules/sigstore/dist/x509/verify.js index cc34a9ea23abe..b4c7f39912a84 100644 --- a/node_modules/sigstore/dist/x509/verify.js +++ b/node_modules/sigstore/dist/x509/verify.js @@ -24,15 +24,15 @@ function verifyCertificateChain(opts) { exports.verifyCertificateChain = verifyCertificateChain; class CertificateChainVerifier { constructor(opts) { - this.certs = opts.certs; + this.untrustedCert = opts.untrustedCert; this.trustedCerts = opts.trustedCerts; - this.localCerts = dedupeCertificates([...opts.trustedCerts, ...opts.certs]); + this.localCerts = dedupeCertificates([ + ...opts.trustedCerts, + opts.untrustedCert, + ]); this.validAt = opts.validAt || new Date(); } verify() { - if (this.certs.length === 0) { - throw new error_1.VerificationError('No certificates provided'); - } // Construct certificate path from leaf to root const certificatePath = this.sort(); // Perform validation checks on each certificate in the path @@ -41,7 +41,7 @@ class CertificateChainVerifier { return certificatePath; } sort() { - const leafCert = this.localCerts[this.localCerts.length - 1]; + const leafCert = this.untrustedCert; // Construct all possible paths from the leaf let paths = this.buildPaths(leafCert); // Filter for paths which contain a trusted certificate @@ -52,7 +52,9 @@ class CertificateChainVerifier { // Find the shortest of possible paths const path = paths.reduce((prev, curr) => prev.length < curr.length ? prev : curr); // Construct chain from shortest path - return [leafCert, ...path]; + // Removes the last certificate in the path, which will be a second copy + // of the root certificate given that the root is self-signed. + return [leafCert, ...path].slice(0, -1); } // Recursively build all possible paths from the leaf to the root buildPaths(certificate) { @@ -123,8 +125,8 @@ class CertificateChainVerifier { return issuers; } checkPath(path) { - if (path.length < 2) { - throw new error_1.VerificationError('Certificate chain must contain at least two certificates'); + if (path.length < 1) { + throw new error_1.VerificationError('Certificate chain must contain at least one certificate'); } // Check that all certificates are valid at the check date const validForDate = path.every((cert) => cert.validForDate(this.validAt)); @@ -143,6 +145,22 @@ class CertificateChainVerifier { throw new error_1.VerificationError('Incorrect certificate name chaining'); } } + // Check pathlength constraints + for (let i = 0; i < path.length; i++) { + const cert = path[i]; + // If the certificate is a CA, check the path length + if (cert.extBasicConstraints?.isCA) { + const pathLength = cert.extBasicConstraints.pathLenConstraint; + // The path length, if set, indicates how many intermediate + // certificates (NOT including the leaf) are allowed to follow. The + // pathLength constraint of any intermediate CA certificate MUST be + // greater than or equal to it's own depth in the chain (with an + // adjustment for the leaf certificate) + if (pathLength !== undefined && pathLength < i - 1) { + throw new error_1.VerificationError('Path length constraint exceeded'); + } + } + } } } // Remove duplicate certificates from the array diff --git a/node_modules/sigstore/package.json b/node_modules/sigstore/package.json index 2df3467186765..b7dc6e30f0dcd 100644 --- a/node_modules/sigstore/package.json +++ b/node_modules/sigstore/package.json @@ -1,62 +1,49 @@ { "name": "sigstore", - "version": "1.4.0", + "version": "1.6.0", "description": "code-signing for npm packages", "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { - "build": "tsc", - "test": "jest", - "test:watch": "jest --watch", - "test:ci": "jest --maxWorkers=2 --coverage", - "lint": "eslint --fix --ext .ts src/**", - "lint:check": "eslint --max-warnings 0 --ext .ts src/**", - "format": "prettier --write \"src/**/*\"", - "release": "npm run build && changeset publish", - "codegen:rekor": "./hack/generate-rekor-types" + "clean": "shx rm -rf dist *.tsbuildinfo", + "build": "tsc --build", + "test": "jest" }, "bin": { "sigstore": "bin/sigstore.js" }, - "repository": { - "type": "git", - "url": "git+https://github.com/sigstore/sigstore-js.git" - }, - "publishConfig": { - "provenance": true - }, "files": [ "dist", "store" ], "author": "bdehamer@github.com", "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "git+https://github.com/sigstore/sigstore-js.git" + }, "bugs": { "url": "https://github.com/sigstore/sigstore-js/issues" }, - "homepage": "https://github.com/sigstore/sigstore-js#readme", + "homepage": "https://github.com/sigstore/sigstore-js/tree/main/packages/client#readme", + "publishConfig": { + "provenance": true + }, "devDependencies": { - "@changesets/cli": "^2.26.0", + "@sigstore/rekor-types": "^1.0.0", "@total-typescript/shoehorn": "^0.1.0", - "@tsconfig/node14": "^1.0.3", "@tufjs/repo-mock": "^1.1.0", - "@types/jest": "^29.4.0", "@types/make-fetch-happen": "^10.0.0", - "@types/node": "^18.6.5", - "@typescript-eslint/eslint-plugin": "^5.26.0", - "@typescript-eslint/parser": "^5.26.0", - "eslint": "^8.16.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-prettier": "^4.0.0", - "jest": "^29.4.1", - "json-schema-to-typescript": "^12.0.0", + "@types/sigstore-jest-extended": "^0.0.0", + "@types/node": "^20.2.5", + "json-schema-to-typescript": "^13.0.0", "nock": "^13.2.4", - "prettier": "^2.6.2", - "ts-jest": "^29.0.5", - "typescript": "^5.0.2" + "shx": "^0.3.3", + "typescript": "^5.1.3" }, "dependencies": { "@sigstore/protobuf-specs": "^0.1.0", + "@sigstore/tuf": "^1.0.0", "make-fetch-happen": "^11.0.1", "tuf-js": "^1.1.3" }, diff --git a/node_modules/sigstore/store/public-good-instance-root.json b/node_modules/sigstore/store/public-good-instance-root.json index 38f80f940473a..e95c7e88cdf09 100644 --- a/node_modules/sigstore/store/public-good-instance-root.json +++ b/node_modules/sigstore/store/public-good-instance-root.json @@ -1,156 +1 @@ -{ - "signed": { - "_type": "root", - "spec_version": "1.0", - "version": 5, - "expires": "2023-04-18T18:13:43Z", - "keys": { - "25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99": { - "keytype": "ecdsa-sha2-nistp256", - "scheme": "ecdsa-sha2-nistp256", - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keyval": { - "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEXsz3SZXFb8jMV42j6pJlyjbjR8K\nN3Bwocexq6LMIb5qsWKOQvLN16NUefLc4HswOoumRsVVaajSpQS6fobkRw==\n-----END PUBLIC KEY-----\n" - } - }, - "2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de": { - "keytype": "ecdsa-sha2-nistp256", - "scheme": "ecdsa-sha2-nistp256", - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keyval": { - "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0ghrh92Lw1Yr3idGV5WqCtMDB8Cx\n+D8hdC4w2ZLNIplVRoVGLskYa3gheMyOjiJ8kPi15aQ2//7P+oj7UvJPGw==\n-----END PUBLIC KEY-----\n" - } - }, - "45b283825eb184cabd582eb17b74fc8ed404f68cf452acabdad2ed6f90ce216b": { - "keytype": "ecdsa-sha2-nistp256", - "scheme": "ecdsa-sha2-nistp256", - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keyval": { - "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAELrWvNt94v4R085ELeeCMxHp7PldF\n0/T1GxukUh2ODuggLGJE0pc1e8CSBf6CS91Fwo9FUOuRsjBUld+VqSyCdQ==\n-----END PUBLIC KEY-----\n" - } - }, - "7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b": { - "keytype": "ecdsa-sha2-nistp256", - "scheme": "ecdsa-sha2-nistp256", - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keyval": { - "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEinikSsAQmYkNeH5eYq/CnIzLaacO\nxlSaawQDOwqKy/tCqxq5xxPSJc21K4WIhs9GyOkKfzueY3GILzcMJZ4cWw==\n-----END PUBLIC KEY-----\n" - } - }, - "e1863ba02070322ebc626dcecf9d881a3a38c35c3b41a83765b6ad6c37eaec2a": { - "keytype": "ecdsa-sha2-nistp256", - "scheme": "ecdsa-sha2-nistp256", - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keyval": { - "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWRiGr5+j+3J5SsH+Ztr5nE2H2wO7\nBV+nO3s93gLca18qTOzHY1oWyAGDykMSsGTUBSt9D+An0KfKsD2mfSM42Q==\n-----END PUBLIC KEY-----\n" - } - }, - "f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f": { - "keytype": "ecdsa-sha2-nistp256", - "scheme": "ecdsa-sha2-nistp256", - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keyval": { - "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEzBzVOmHCPojMVLSI364WiiV8NPrD\n6IgRxVliskz/v+y3JER5mcVGcONliDcWMC5J2lfHmjPNPhb4H7xm8LzfSA==\n-----END PUBLIC KEY-----\n" - } - }, - "ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c": { - "keytype": "ecdsa-sha2-nistp256", - "scheme": "ecdsa-sha2-nistp256", - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keyval": { - "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEy8XKsmhBYDI8Jc0GwzBxeKax0cm5\nSTKEU65HPFunUn41sT8pi0FjM4IkHz/YUmwmLUO0Wt7lxhj6BkLIK4qYAw==\n-----END PUBLIC KEY-----\n" - } - } - }, - "roles": { - "root": { - "keyids": [ - "ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c", - "25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99", - "f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f", - "7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b", - "2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de" - ], - "threshold": 3 - }, - "snapshot": { - "keyids": [ - "45b283825eb184cabd582eb17b74fc8ed404f68cf452acabdad2ed6f90ce216b" - ], - "threshold": 1 - }, - "targets": { - "keyids": [ - "ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c", - "25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99", - "f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f", - "7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b", - "2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de" - ], - "threshold": 3 - }, - "timestamp": { - "keyids": [ - "e1863ba02070322ebc626dcecf9d881a3a38c35c3b41a83765b6ad6c37eaec2a" - ], - "threshold": 1 - } - }, - "consistent_snapshot": true - }, - "signatures": [ - { - "keyid": "ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c", - "sig": "3045022100fc1c2be509ce50ea917bbad1d9efe9d96c8c2ebea04af2717aa3d9c6fe617a75022012eef282a19f2d8bd4818aa333ef48a06489f49d4d34a20b8fe8fc867bb25a7a" - }, - { - "keyid": "25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99", - "sig": "30450221008a4392ae5057fc00778b651e61fea244766a4ae58db84d9f1d3810720ab0f3b702207c49e59e8031318caf02252ecea1281cecc1e5986c309a9cef61f455ecf7165d" - }, - { - "keyid": "7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b", - "sig": "3046022100da1b8dc5d53aaffbbfac98de3e23ee2d2ad3446a7bed09fac0f88bae19be2587022100b681c046afc3919097dfe794e0d819be891e2e850aade315bec06b0c4dea221b" - }, - { - "keyid": "2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de", - "sig": "3046022100b534e0030e1b271133ecfbdf3ba9fbf3becb3689abea079a2150afbb63cdb7c70221008c39a718fd9495f249b4ab8788d5b9dc269f0868dbe38b272f48207359d3ded9" - }, - { - "keyid": "2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97", - "sig": "3045022100fc1c2be509ce50ea917bbad1d9efe9d96c8c2ebea04af2717aa3d9c6fe617a75022012eef282a19f2d8bd4818aa333ef48a06489f49d4d34a20b8fe8fc867bb25a7a" - }, - { - "keyid": "eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b", - "sig": "30450221008a4392ae5057fc00778b651e61fea244766a4ae58db84d9f1d3810720ab0f3b702207c49e59e8031318caf02252ecea1281cecc1e5986c309a9cef61f455ecf7165d" - }, - { - "keyid": "f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209", - "sig": "3046022100da1b8dc5d53aaffbbfac98de3e23ee2d2ad3446a7bed09fac0f88bae19be2587022100b681c046afc3919097dfe794e0d819be891e2e850aade315bec06b0c4dea221b" - }, - { - "keyid": "75e867ab10e121fdef32094af634707f43ddd79c6bab8ad6c5ab9f03f4ea8c90", - "sig": "3046022100b534e0030e1b271133ecfbdf3ba9fbf3becb3689abea079a2150afbb63cdb7c70221008c39a718fd9495f249b4ab8788d5b9dc269f0868dbe38b272f48207359d3ded9" - } - ] -} \ No newline at end of file +{"signed":{"_type":"root","spec_version":"1.0","version":7,"expires":"2023-10-04T13:08:11Z","keys":{"25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEXsz3SZXFb8jMV42j6pJlyjbjR8K\nN3Bwocexq6LMIb5qsWKOQvLN16NUefLc4HswOoumRsVVaajSpQS6fobkRw==\n-----END PUBLIC KEY-----\n"}},"2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0ghrh92Lw1Yr3idGV5WqCtMDB8Cx\n+D8hdC4w2ZLNIplVRoVGLskYa3gheMyOjiJ8kPi15aQ2//7P+oj7UvJPGw==\n-----END PUBLIC KEY-----\n"}},"45b283825eb184cabd582eb17b74fc8ed404f68cf452acabdad2ed6f90ce216b":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAELrWvNt94v4R085ELeeCMxHp7PldF\n0/T1GxukUh2ODuggLGJE0pc1e8CSBf6CS91Fwo9FUOuRsjBUld+VqSyCdQ==\n-----END PUBLIC KEY-----\n"}},"7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEinikSsAQmYkNeH5eYq/CnIzLaacO\nxlSaawQDOwqKy/tCqxq5xxPSJc21K4WIhs9GyOkKfzueY3GILzcMJZ4cWw==\n-----END PUBLIC KEY-----\n"}},"e1863ba02070322ebc626dcecf9d881a3a38c35c3b41a83765b6ad6c37eaec2a":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWRiGr5+j+3J5SsH+Ztr5nE2H2wO7\nBV+nO3s93gLca18qTOzHY1oWyAGDykMSsGTUBSt9D+An0KfKsD2mfSM42Q==\n-----END PUBLIC KEY-----\n"}},"f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEzBzVOmHCPojMVLSI364WiiV8NPrD\n6IgRxVliskz/v+y3JER5mcVGcONliDcWMC5J2lfHmjPNPhb4H7xm8LzfSA==\n-----END PUBLIC KEY-----\n"}},"ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEy8XKsmhBYDI8Jc0GwzBxeKax0cm5\nSTKEU65HPFunUn41sT8pi0FjM4IkHz/YUmwmLUO0Wt7lxhj6BkLIK4qYAw==\n-----END PUBLIC KEY-----\n"}}},"roles":{"root":{"keyids":["ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c","25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99","f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f","7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b","2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de"],"threshold":3},"snapshot":{"keyids":["45b283825eb184cabd582eb17b74fc8ed404f68cf452acabdad2ed6f90ce216b"],"threshold":1},"targets":{"keyids":["ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c","25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99","f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f","7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b","2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de"],"threshold":3},"timestamp":{"keyids":["e1863ba02070322ebc626dcecf9d881a3a38c35c3b41a83765b6ad6c37eaec2a"],"threshold":1}},"consistent_snapshot":true},"signatures":[{"keyid":"25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99","sig":"3046022100c0610c0055ce5c4a52d054d7322e7b514d55baf44423d63aa4daa077cc60fd1f022100a097f2803f090fb66c42ead915a2c46ebe7db53a32bf18f2188275cc936f8bdd"},{"keyid":"f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f","sig":"304502203134f0468810299d5493a867c40630b341296b92e59c29821311d353343bb3a4022100e667ae3d304e7e3da0894c7425f6b9ecd917106841280e5cf6f3496ad5f8f68e"},{"keyid":"7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b","sig":"3045022037fe5f45426f21eaaf4730d2136f2b1611d6379688f79b9d1e3f61719997135c022100b63b022d7b79d4694b96f416d88aa4d7b1a3bff8a01f4fb51e0f42137c7d2d06"},{"keyid":"2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de","sig":"3044022007cc8fcc4940809f2751ad5b535f4c5f53f5b4952f5b5696b09668e743306ac1022006dfcdf94e94c92163eeb1b47796db62cedaa730aa13aa61b573fe23714730f2"}]} diff --git a/node_modules/string_decoder/package.json b/node_modules/string_decoder/package.json index 518c3eb9fb1ff..b2bb141160cad 100644 --- a/node_modules/string_decoder/package.json +++ b/node_modules/string_decoder/package.json @@ -1,10 +1,13 @@ { "name": "string_decoder", - "version": "1.1.1", + "version": "1.3.0", "description": "The string_decoder module from Node core", "main": "lib/string_decoder.js", + "files": [ + "lib" + ], "dependencies": { - "safe-buffer": "~5.1.0" + "safe-buffer": "~5.2.0" }, "devDependencies": { "babel-polyfill": "^6.23.0", diff --git a/node_modules/supports-color/browser.js b/node_modules/supports-color/browser.js index 62afa3a7425dc..1ffde642ae2ea 100644 --- a/node_modules/supports-color/browser.js +++ b/node_modules/supports-color/browser.js @@ -1,5 +1,30 @@ -'use strict'; -module.exports = { - stdout: false, - stderr: false +/* eslint-env browser */ + +const level = (() => { + if (navigator.userAgentData) { + const brand = navigator.userAgentData.brands.find(({brand}) => brand === 'Chromium'); + if (brand?.version > 93) { + return 3; + } + } + + if (/\b(Chrome|Chromium)\//.test(navigator.userAgent)) { + return 1; + } + + return 0; +})(); + +const colorSupport = level !== 0 && { + level, + hasBasic: true, + has256: level >= 2, + has16m: level >= 3, }; + +const supportsColor = { + stdout: colorSupport, + stderr: colorSupport, +}; + +export default supportsColor; diff --git a/node_modules/supports-color/index.js b/node_modules/supports-color/index.js index 6fada390fb88d..ca95e9f2202a6 100644 --- a/node_modules/supports-color/index.js +++ b/node_modules/supports-color/index.js @@ -1,30 +1,46 @@ -'use strict'; -const os = require('os'); -const tty = require('tty'); -const hasFlag = require('has-flag'); +import process from 'node:process'; +import os from 'node:os'; +import tty from 'node:tty'; + +// From: https://github.com/sindresorhus/has-flag/blob/main/index.js +/// function hasFlag(flag, argv = globalThis.Deno?.args ?? process.argv) { +function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process.argv) { + const prefix = flag.startsWith('-') ? '' : (flag.length === 1 ? '-' : '--'); + const position = argv.indexOf(prefix + flag); + const terminatorPosition = argv.indexOf('--'); + return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition); +} const {env} = process; -let forceColor; -if (hasFlag('no-color') || - hasFlag('no-colors') || - hasFlag('color=false') || - hasFlag('color=never')) { - forceColor = 0; -} else if (hasFlag('color') || - hasFlag('colors') || - hasFlag('color=true') || - hasFlag('color=always')) { - forceColor = 1; +let flagForceColor; +if ( + hasFlag('no-color') + || hasFlag('no-colors') + || hasFlag('color=false') + || hasFlag('color=never') +) { + flagForceColor = 0; +} else if ( + hasFlag('color') + || hasFlag('colors') + || hasFlag('color=true') + || hasFlag('color=always') +) { + flagForceColor = 1; } -if ('FORCE_COLOR' in env) { - if (env.FORCE_COLOR === 'true') { - forceColor = 1; - } else if (env.FORCE_COLOR === 'false') { - forceColor = 0; - } else { - forceColor = env.FORCE_COLOR.length === 0 ? 1 : Math.min(parseInt(env.FORCE_COLOR, 10), 3); +function envForceColor() { + if ('FORCE_COLOR' in env) { + if (env.FORCE_COLOR === 'true') { + return 1; + } + + if (env.FORCE_COLOR === 'false') { + return 0; + } + + return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3); } } @@ -37,23 +53,38 @@ function translateLevel(level) { level, hasBasic: true, has256: level >= 2, - has16m: level >= 3 + has16m: level >= 3, }; } -function supportsColor(haveStream, streamIsTTY) { +function _supportsColor(haveStream, {streamIsTTY, sniffFlags = true} = {}) { + const noFlagForceColor = envForceColor(); + if (noFlagForceColor !== undefined) { + flagForceColor = noFlagForceColor; + } + + const forceColor = sniffFlags ? flagForceColor : noFlagForceColor; + if (forceColor === 0) { return 0; } - if (hasFlag('color=16m') || - hasFlag('color=full') || - hasFlag('color=truecolor')) { - return 3; + if (sniffFlags) { + if (hasFlag('color=16m') + || hasFlag('color=full') + || hasFlag('color=truecolor')) { + return 3; + } + + if (hasFlag('color=256')) { + return 2; + } } - if (hasFlag('color=256')) { - return 2; + // Check for Azure DevOps pipelines. + // Has to be above the `!streamIsTTY` check. + if ('TF_BUILD' in env && 'AGENT_NAME' in env) { + return 1; } if (haveStream && !streamIsTTY && forceColor === undefined) { @@ -71,17 +102,21 @@ function supportsColor(haveStream, streamIsTTY) { // Windows 10 build 14931 is the first release that supports 16m/TrueColor. const osRelease = os.release().split('.'); if ( - Number(osRelease[0]) >= 10 && - Number(osRelease[2]) >= 10586 + Number(osRelease[0]) >= 10 + && Number(osRelease[2]) >= 10_586 ) { - return Number(osRelease[2]) >= 14931 ? 3 : 2; + return Number(osRelease[2]) >= 14_931 ? 3 : 2; } return 1; } if ('CI' in env) { - if (['TRAVIS', 'CIRCLECI', 'APPVEYOR', 'GITLAB_CI', 'GITHUB_ACTIONS', 'BUILDKITE'].some(sign => sign in env) || env.CI_NAME === 'codeship') { + if ('GITHUB_ACTIONS' in env) { + return 3; + } + + if (['TRAVIS', 'CIRCLECI', 'APPVEYOR', 'GITLAB_CI', 'BUILDKITE', 'DRONE'].some(sign => sign in env) || env.CI_NAME === 'codeship') { return 1; } @@ -96,14 +131,21 @@ function supportsColor(haveStream, streamIsTTY) { return 3; } + if (env.TERM === 'xterm-kitty') { + return 3; + } + if ('TERM_PROGRAM' in env) { - const version = parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10); + const version = Number.parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10); switch (env.TERM_PROGRAM) { - case 'iTerm.app': + case 'iTerm.app': { return version >= 3 ? 3 : 2; - case 'Apple_Terminal': + } + + case 'Apple_Terminal': { return 2; + } // No default } } @@ -123,13 +165,18 @@ function supportsColor(haveStream, streamIsTTY) { return min; } -function getSupportLevel(stream) { - const level = supportsColor(stream, stream && stream.isTTY); +export function createSupportsColor(stream, options = {}) { + const level = _supportsColor(stream, { + streamIsTTY: stream && stream.isTTY, + ...options, + }); + return translateLevel(level); } -module.exports = { - supportsColor: getSupportLevel, - stdout: translateLevel(supportsColor(true, tty.isatty(1))), - stderr: translateLevel(supportsColor(true, tty.isatty(2))) +const supportsColor = { + stdout: createSupportsColor({isTTY: tty.isatty(1)}), + stderr: createSupportsColor({isTTY: tty.isatty(2)}), }; + +export default supportsColor; diff --git a/node_modules/supports-color/license b/node_modules/supports-color/license index e7af2f77107d7..fa7ceba3eb4a9 100644 --- a/node_modules/supports-color/license +++ b/node_modules/supports-color/license @@ -1,6 +1,6 @@ MIT License -Copyright (c) Sindre Sorhus (sindresorhus.com) +Copyright (c) Sindre Sorhus (https://sindresorhus.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/node_modules/supports-color/package.json b/node_modules/supports-color/package.json index f7182edcea2ba..eb6011c6bcdc6 100644 --- a/node_modules/supports-color/package.json +++ b/node_modules/supports-color/package.json @@ -1,23 +1,32 @@ { "name": "supports-color", - "version": "7.2.0", + "version": "9.3.1", "description": "Detect whether a terminal supports color", "license": "MIT", "repository": "chalk/supports-color", + "funding": "https://github.com/chalk/supports-color?sponsor=1", "author": { "name": "Sindre Sorhus", "email": "sindresorhus@gmail.com", - "url": "sindresorhus.com" + "url": "https://sindresorhus.com" + }, + "type": "module", + "exports": { + "node": "./index.js", + "default": "./browser.js" }, "engines": { - "node": ">=8" + "node": ">=12" }, "scripts": { - "test": "xo && ava" + "//test": "xo && ava && tsd", + "test": "xo && tsd" }, "files": [ "index.js", - "browser.js" + "index.d.ts", + "browser.js", + "browser.d.ts" ], "keywords": [ "color", @@ -41,13 +50,12 @@ "truecolor", "16m" ], - "dependencies": { - "has-flag": "^4.0.0" - }, "devDependencies": { - "ava": "^1.4.1", - "import-fresh": "^3.0.0", - "xo": "^0.24.0" - }, - "browser": "browser.js" + "@types/node": "^16.11.7", + "ava": "^3.15.0", + "import-fresh": "^3.3.0", + "tsd": "^0.18.0", + "typescript": "^4.4.3", + "xo": "^0.49.0" + } } diff --git a/node_modules/tar/lib/normalize-unicode.js b/node_modules/tar/lib/normalize-unicode.js index 43dc406ecedb9..79e285ab30d57 100644 --- a/node_modules/tar/lib/normalize-unicode.js +++ b/node_modules/tar/lib/normalize-unicode.js @@ -6,7 +6,7 @@ const normalizeCache = Object.create(null) const { hasOwnProperty } = Object.prototype module.exports = s => { if (!hasOwnProperty.call(normalizeCache, s)) { - normalizeCache[s] = s.normalize('NFKD') + normalizeCache[s] = s.normalize('NFD') } return normalizeCache[s] } diff --git a/node_modules/tar/lib/path-reservations.js b/node_modules/tar/lib/path-reservations.js index ef380cab685e3..8d349d584513f 100644 --- a/node_modules/tar/lib/path-reservations.js +++ b/node_modules/tar/lib/path-reservations.js @@ -123,7 +123,7 @@ module.exports = () => { // effectively removing all parallelization on windows. paths = isWindows ? ['win32 parallelization disabled'] : paths.map(p => { // don't need normPath, because we skip this entirely for windows - return normalize(stripSlashes(join(p))).toLowerCase() + return stripSlashes(join(normalize(p))).toLowerCase() }) const dirs = new Set( diff --git a/node_modules/tar/lib/unpack.js b/node_modules/tar/lib/unpack.js index e341ad0c7239e..fa46611c0a19f 100644 --- a/node_modules/tar/lib/unpack.js +++ b/node_modules/tar/lib/unpack.js @@ -105,7 +105,7 @@ const uint32 = (a, b, c) => // Note that on windows, we always drop the entire cache whenever a // symbolic link is encountered, because 8.3 filenames are impossible // to reason about, and collisions are hazards rather than just failures. -const cacheKeyNormalize = path => normalize(stripSlash(normPath(path))) +const cacheKeyNormalize = path => stripSlash(normPath(normalize(path))) .toLowerCase() const pruneCache = (cache, abs) => { diff --git a/node_modules/tar/package.json b/node_modules/tar/package.json index 943c8b4d06b94..f59f54ae837bd 100644 --- a/node_modules/tar/package.json +++ b/node_modules/tar/package.json @@ -2,7 +2,7 @@ "author": "GitHub Inc.", "name": "tar", "description": "tar for node", - "version": "6.1.14", + "version": "6.1.15", "repository": { "type": "git", "url": "https://github.com/isaacs/node-tar.git" diff --git a/node_modules/tuf-js/dist/fetcher.js b/node_modules/tuf-js/dist/fetcher.js index 7a7405ac53e72..d3dcf53eeb869 100644 --- a/node_modules/tuf-js/dist/fetcher.js +++ b/node_modules/tuf-js/dist/fetcher.js @@ -4,11 +4,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) { }; Object.defineProperty(exports, "__esModule", { value: true }); exports.DefaultFetcher = exports.BaseFetcher = void 0; +const debug_1 = __importDefault(require("debug")); const fs_1 = __importDefault(require("fs")); const make_fetch_happen_1 = __importDefault(require("make-fetch-happen")); const util_1 = __importDefault(require("util")); const error_1 = require("./error"); const tmpfile_1 = require("./utils/tmpfile"); +const log = (0, debug_1.default)('tuf:fetch'); class BaseFetcher { // Download file from given URL. The file is downloaded to a temporary // location and then passed to the given handler. The handler is responsible @@ -58,6 +60,7 @@ class DefaultFetcher extends BaseFetcher { this.retries = options.retries; } async fetch(url) { + log('GET %s', url); const response = await (0, make_fetch_happen_1.default)(url, { timeout: this.timeout, retry: this.retries, diff --git a/node_modules/tuf-js/dist/updater.js b/node_modules/tuf-js/dist/updater.js index 68243e554facb..2aba48d24affd 100644 --- a/node_modules/tuf-js/dist/updater.js +++ b/node_modules/tuf-js/dist/updater.js @@ -22,9 +22,13 @@ var __importStar = (this && this.__importStar) || function (mod) { __setModuleDefault(result, mod); return result; }; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; Object.defineProperty(exports, "__esModule", { value: true }); exports.Updater = void 0; const models_1 = require("@tufjs/models"); +const debug_1 = __importDefault(require("debug")); const fs = __importStar(require("fs")); const path = __importStar(require("path")); const config_1 = require("./config"); @@ -32,6 +36,7 @@ const error_1 = require("./error"); const fetcher_1 = require("./fetcher"); const store_1 = require("./store"); const url = __importStar(require("./utils/url")); +const log = (0, debug_1.default)('tuf:cache'); class Updater { constructor(options) { const { metadataDir, metadataBaseUrl, targetDir, targetBaseUrl, fetcher, config, } = options; @@ -49,6 +54,8 @@ class Updater { retries: this.config.fetchRetries, }); } + // refresh and load the metadata before downloading the target + // refresh should be called once after the client is initialized async refresh() { await this.loadRoot(); await this.loadTimestamp(); @@ -86,6 +93,7 @@ class Updater { // Verify hashes and length of downloaded file await targetInfo.verify(fs.createReadStream(fileName)); // Copy file to target path + log('WRITE %s', targetPath); fs.copyFileSync(fileName, targetPath); }); return targetPath; @@ -96,7 +104,7 @@ class Updater { } try { if (fs.existsSync(filePath)) { - targetInfo.verify(fs.createReadStream(filePath)); + await targetInfo.verify(fs.createReadStream(filePath)); return filePath; } } @@ -107,6 +115,7 @@ class Updater { } loadLocalMetadata(fileName) { const filePath = path.join(this.dir, `${fileName}.json`); + log('READ %s', filePath); return fs.readFileSync(filePath); } // Sequentially load and persist on local disk every newer root metadata @@ -300,6 +309,7 @@ class Updater { async persistMetadata(metaDataName, bytesData) { try { const filePath = path.join(this.dir, `${metaDataName}.json`); + log('WRITE %s', filePath); fs.writeFileSync(filePath, bytesData.toString('utf8')); } catch (error) { diff --git a/node_modules/tuf-js/package.json b/node_modules/tuf-js/package.json index ab84004c49403..9187d88083272 100644 --- a/node_modules/tuf-js/package.json +++ b/node_modules/tuf-js/package.json @@ -1,6 +1,6 @@ { "name": "tuf-js", - "version": "1.1.5", + "version": "1.1.7", "description": "JavaScript implementation of The Update Framework (TUF)", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -29,14 +29,16 @@ "homepage": "https://github.com/theupdateframework/tuf-js/tree/main/packages/client#readme", "devDependencies": { "@tufjs/repo-mock": "1.3.1", + "@types/debug": "^4.1.8", "@types/make-fetch-happen": "^10.0.1", - "@types/node": "^18.16.3", + "@types/node": "^20.2.5", "nock": "^13.3.1", - "typescript": "^5.0.4" + "typescript": "^5.1.3" }, "dependencies": { - "make-fetch-happen": "^11.1.0", - "@tufjs/models": "1.0.4" + "@tufjs/models": "1.0.4", + "debug": "^4.3.4", + "make-fetch-happen": "^11.1.1" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" diff --git a/node_modules/wrap-ansi/node_modules/strip-ansi/index.js b/node_modules/wrap-ansi/node_modules/strip-ansi/index.js index ef3c095f5fd42..ba19750e64e06 100644 --- a/node_modules/wrap-ansi/node_modules/strip-ansi/index.js +++ b/node_modules/wrap-ansi/node_modules/strip-ansi/index.js @@ -1,9 +1,14 @@ import ansiRegex from 'ansi-regex'; +const regex = ansiRegex(); + export default function stripAnsi(string) { if (typeof string !== 'string') { throw new TypeError(`Expected a \`string\`, got \`${typeof string}\``); } - return string.replace(ansiRegex(), ''); + // Even though the regex is global, we don't need to reset the `.lastIndex` + // because unlike `.exec()` and `.test()`, `.replace()` does it automatically + // and doing it manually has a performance penalty. + return string.replace(regex, ''); } diff --git a/node_modules/wrap-ansi/node_modules/strip-ansi/package.json b/node_modules/wrap-ansi/node_modules/strip-ansi/package.json index 0de0586f7eef1..e1f455c325b00 100644 --- a/node_modules/wrap-ansi/node_modules/strip-ansi/package.json +++ b/node_modules/wrap-ansi/node_modules/strip-ansi/package.json @@ -1,6 +1,6 @@ { "name": "strip-ansi", - "version": "7.0.1", + "version": "7.1.0", "description": "Strip ANSI escape codes from a string", "license": "MIT", "repository": "chalk/strip-ansi", diff --git a/package-lock.json b/package-lock.json index e73fd43244d71..a165f8ad35955 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "npm", - "version": "9.6.6", + "version": "9.7.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "npm", - "version": "9.6.6", + "version": "9.7.2", "bundleDependencies": [ "@isaacs/string-locale-compare", "@npmcli/arborist", @@ -63,10 +63,10 @@ "proc-log", "qrcode-terminal", "read", - "read-package-json", - "read-package-json-fast", "semver", + "sigstore", "ssri", + "supports-color", "tar", "text-table", "tiny-relative-date", @@ -79,41 +79,42 @@ "workspaces": [ "docs", "smoke-tests", + "mock-globals", "mock-registry", "workspaces/*" ], "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^6.2.9", - "@npmcli/config": "^6.1.6", + "@npmcli/arborist": "^6.2.10", + "@npmcli/config": "^6.2.1", "@npmcli/map-workspaces": "^3.0.4", - "@npmcli/package-json": "^3.0.0", - "@npmcli/run-script": "^6.0.1", + "@npmcli/package-json": "^3.1.1", + "@npmcli/run-script": "^6.0.2", "abbrev": "^2.0.0", "archy": "~1.0.0", - "cacache": "^17.1.0", - "chalk": "^4.1.2", + "cacache": "^17.1.3", + "chalk": "^5.2.0", "ci-info": "^3.8.0", "cli-columns": "^4.0.0", "cli-table3": "^0.6.3", "columnify": "^1.6.0", "fastest-levenshtein": "^1.0.16", "fs-minipass": "^3.0.2", - "glob": "^10.2.2", + "glob": "^10.2.7", "graceful-fs": "^4.2.11", "hosted-git-info": "^6.1.1", - "ini": "^4.1.0", + "ini": "^4.1.1", "init-package-json": "^5.0.0", "is-cidr": "^4.0.2", "json-parse-even-better-errors": "^3.0.0", "libnpmaccess": "^7.0.2", - "libnpmdiff": "^5.0.17", - "libnpmexec": "^5.0.17", - "libnpmfund": "^4.0.17", + "libnpmdiff": "^5.0.18", + "libnpmexec": "^6.0.1", + "libnpmfund": "^4.0.18", "libnpmhook": "^9.0.3", "libnpmorg": "^5.0.4", - "libnpmpack": "^5.0.17", - "libnpmpublish": "^7.1.4", + "libnpmpack": "^5.0.18", + "libnpmpublish": "^7.4.0", "libnpmsearch": "^6.0.2", "libnpmteam": "^5.0.3", "libnpmversion": "^4.0.2", @@ -122,9 +123,9 @@ "minipass": "^5.0.0", "minipass-pipeline": "^1.2.4", "ms": "^2.1.2", - "node-gyp": "^9.3.1", - "nopt": "^7.1.0", - "npm-audit-report": "^4.0.0", + "node-gyp": "^9.4.0", + "nopt": "^7.2.0", + "npm-audit-report": "^5.0.0", "npm-install-checks": "^6.1.1", "npm-package-arg": "^10.1.0", "npm-pick-manifest": "^8.0.1", @@ -133,16 +134,16 @@ "npm-user-validate": "^2.0.0", "npmlog": "^7.0.1", "p-map": "^4.0.0", - "pacote": "^15.1.3", + "pacote": "^15.2.0", "parse-conflict-json": "^3.0.1", "proc-log": "^3.0.0", "qrcode-terminal": "^0.12.0", "read": "^2.1.0", - "read-package-json": "^6.0.3", - "read-package-json-fast": "^3.0.2", - "semver": "^7.5.0", + "semver": "^7.5.2", + "sigstore": "^1.6.0", "ssri": "^10.0.4", - "tar": "^6.1.14", + "supports-color": "^9.3.1", + "tar": "^6.1.15", "text-table": "~0.2.0", "tiny-relative-date": "^1.3.0", "treeverse": "^3.0.0", @@ -158,10 +159,13 @@ "@npmcli/docs": "^1.0.0", "@npmcli/eslint-config": "^4.0.0", "@npmcli/fs": "^3.1.0", - "@npmcli/git": "^4.0.4", + "@npmcli/git": "^4.1.0", + "@npmcli/mock-globals": "^1.0.0", "@npmcli/mock-registry": "^1.0.0", "@npmcli/promise-spawn": "^6.0.2", "@npmcli/template-oss": "4.14.1", + "@tufjs/repo-mock": "^1.3.1", + "diff": "^5.1.0", "licensee": "^10.0.0", "nock": "^13.3.0", "npm-packlist": "^7.0.4", @@ -181,6 +185,7 @@ "license": "ISC", "devDependencies": { "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/config": "^6.1.7", "@npmcli/eslint-config": "^4.0.0", "@npmcli/template-oss": "4.14.1", "front-matter": "^4.0.2", @@ -200,6 +205,19 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "mock-globals": { + "name": "@npmcli/mock-globals", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "@npmcli/eslint-config": "^4.0.1", + "@npmcli/template-oss": "4.14.1", + "tap": "^16.3.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "mock-registry": { "name": "@npmcli/mock-registry", "version": "1.0.0", @@ -208,6 +226,7 @@ "@npmcli/arborist": "^6.1.1", "@npmcli/eslint-config": "^4.0.1", "@npmcli/template-oss": "4.14.1", + "json-stringify-safe": "^5.0.1", "nock": "^13.3.0", "npm-package-arg": "^10.1.0", "pacote": "^15.0.8", @@ -756,6 +775,34 @@ "node": ">=v14" } }, + "node_modules/@commitlint/format/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@commitlint/format/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@commitlint/is-ignored": { "version": "17.4.4", "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-17.4.4.tgz", @@ -836,6 +883,34 @@ "node": ">=v14" } }, + "node_modules/@commitlint/load/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@commitlint/load/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@commitlint/message": { "version": "17.4.2", "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-17.4.2.tgz", @@ -941,6 +1016,34 @@ "node": ">=v14" } }, + "node_modules/@commitlint/types/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@commitlint/types/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@conventional-commits/parser": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@conventional-commits/parser/-/parser-0.4.1.tgz", @@ -1081,12 +1184,6 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@gar/promisify": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", - "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", - "inBundle": true - }, "node_modules/@google-automations/git-file-utils": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/@google-automations/git-file-utils/-/git-file-utils-1.2.6.tgz", @@ -1232,9 +1329,9 @@ } }, "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "inBundle": true, "dependencies": { "ansi-regex": "^6.0.1" @@ -1432,6 +1529,34 @@ "node": ">= 10.18.0" } }, + "node_modules/@lerna/child-process/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@lerna/child-process/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@lerna/collect-updates": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@lerna/collect-updates/-/collect-updates-4.0.0.tgz", @@ -1550,12 +1675,27 @@ "util-deprecate": "~1.0.1" } }, + "node_modules/@lerna/collect-updates/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, "node_modules/@lerna/collect-updates/node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "node_modules/@lerna/collect-updates/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/@lerna/collect-updates/node_modules/string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -1675,12 +1815,27 @@ "util-deprecate": "~1.0.1" } }, + "node_modules/@lerna/describe-ref/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, "node_modules/@lerna/describe-ref/node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "node_modules/@lerna/describe-ref/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/@lerna/describe-ref/node_modules/string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -1861,12 +2016,27 @@ "util-deprecate": "~1.0.1" } }, + "node_modules/@lerna/package-graph/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, "node_modules/@lerna/package-graph/node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "node_modules/@lerna/package-graph/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/@lerna/package-graph/node_modules/string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -2084,12 +2254,27 @@ "util-deprecate": "~1.0.1" } }, + "node_modules/@lerna/validation-error/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, "node_modules/@lerna/validation-error/node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "node_modules/@lerna/validation-error/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/@lerna/validation-error/node_modules/string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -2211,9 +2396,9 @@ } }, "node_modules/@npmcli/git": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-4.0.4.tgz", - "integrity": "sha512-5yZghx+u5M47LghaybLCkdSyFzV/w4OuH12d96HO389Ik9CDsLaDZJVynSGGVJOLn6gy/k7Dz5XYcplM3uxXRg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-4.1.0.tgz", + "integrity": "sha512-9hwoB3gStVfa0N31ymBmrX+GuDGdVA/QWShZVqE0HK2Af+7QGGrCTbZia/SW0ImUTjTne7SP91qxDmtXvDHRPQ==", "inBundle": true, "dependencies": { "@npmcli/promise-spawn": "^6.0.0", @@ -2274,24 +2459,14 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/@npmcli/mock-globals": { + "resolved": "mock-globals", + "link": true + }, "node_modules/@npmcli/mock-registry": { "resolved": "mock-registry", "link": true }, - "node_modules/@npmcli/move-file": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", - "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", - "deprecated": "This functionality has been moved to @npmcli/fs", - "inBundle": true, - "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/@npmcli/name-from-folder": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@npmcli/name-from-folder/-/name-from-folder-2.0.0.tgz", @@ -2311,12 +2486,17 @@ } }, "node_modules/@npmcli/package-json": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-3.0.0.tgz", - "integrity": "sha512-NnuPuM97xfiCpbTEJYtEuKz6CFbpUHtaT0+5via5pQeI25omvQDFbp1GcGJ/c4zvL/WX0qbde6YiLgfZbWFgvg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-3.1.1.tgz", + "integrity": "sha512-+UW0UWOYFKCkvszLoTwrYGrjNrT8tI5Ckeb/h+Z1y1fsNJEctl7HmerA5j2FgmoqFaLI2gsA1X9KgMFqx/bRmA==", "inBundle": true, "dependencies": { - "json-parse-even-better-errors": "^3.0.0" + "@npmcli/git": "^4.1.0", + "glob": "^10.2.2", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^5.0.0", + "npm-normalize-package-bin": "^3.0.1", + "proc-log": "^3.0.0" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -2346,9 +2526,9 @@ } }, "node_modules/@npmcli/run-script": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-6.0.1.tgz", - "integrity": "sha512-Yi04ZSold8jcbBJD/ahKMJSQCQifH8DAbMwkBvoLaTpGFxzHC3B/5ZyoVR69q/4xedz84tvi9DJOJjNe17h+LA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-6.0.2.tgz", + "integrity": "sha512-NCcr1uQo1k5U+SYlnIrbAh3cxy+OQT1VtqiAbxdymSlptbzBb62AjH2xXgjNCoP073hoa1CfCAcwoZ8k96C4nA==", "inBundle": true, "dependencies": { "@npmcli/node-gyp": "^3.0.0", @@ -2584,6 +2764,20 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/@sigstore/tuf": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-1.0.0.tgz", + "integrity": "sha512-bLzi9GeZgMCvjJeLUIfs8LJYCxrPRA8IXQkzUtaFKKVPTz0mucRyqFcV2U20yg9K+kYAD0YSitzGfRZCFLjdHQ==", + "inBundle": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.1.0", + "make-fetch-happen": "^11.0.1", + "tuf-js": "^1.1.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", @@ -2639,6 +2833,19 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/@tufjs/repo-mock": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@tufjs/repo-mock/-/repo-mock-1.3.1.tgz", + "integrity": "sha512-7IDezQbPGReWD3xmgR2pAfG61BZpvW51XnB87OfuiJOe5mkGnziCTTGITtUC3A6htQr9shkk5qIKrhpoMXBwpQ==", + "dev": true, + "dependencies": { + "@tufjs/models": "1.0.4", + "nock": "^13.3.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/@types/debug": { "version": "4.1.7", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", @@ -3285,9 +3492,9 @@ } }, "node_modules/cacache": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.1.0.tgz", - "integrity": "sha512-hXpFU+Z3AfVmNuiLve1qxWHMq0RSIt5gjCKAHi/M6DktwFwDdAXAtunl1i4WSKaaVcU9IsRvXFg42jTHigcC6Q==", + "version": "17.1.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.1.3.tgz", + "integrity": "sha512-jAdjGxmPxZh0IipMdR7fK/4sDSrHMLUV0+GvVUsjwyGNKHsh79kW/otg+GkbXwl6Uzvy9wsvHOX4nUoWldeZMg==", "inBundle": true, "dependencies": { "@npmcli/fs": "^3.1.0", @@ -3426,16 +3633,12 @@ } }, "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", + "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", "inBundle": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "engines": { - "node": ">=10" + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, "funding": { "url": "https://github.com/chalk/chalk?sponsor=1" @@ -5084,6 +5287,23 @@ "concat-map": "0.0.1" } }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/eslint/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -5104,6 +5324,19 @@ "node": "*" } }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/espree": { "version": "9.5.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", @@ -5238,6 +5471,12 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "node_modules/exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "inBundle": true + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -5730,15 +5969,15 @@ "dev": true }, "node_modules/glob": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.2.2.tgz", - "integrity": "sha512-Xsa0BcxIC6th9UwNjZkhrMtNo/MnyRL8jGCP+uEwhA5oFOCY1f2s1/oNKY47xQ0Bg5nkjsfAEIej1VeH62bDDQ==", + "version": "10.2.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.2.7.tgz", + "integrity": "sha512-jTKehsravOJo8IJxUGfZILnkvVJM/MOfHRs8QcXolVef2zNI9Tqyy5+SeuOAZd3upViEZQLyFpQhYiHLrMUNmA==", "inBundle": true, "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^2.0.3", - "minimatch": "^9.0.0", - "minipass": "^5.0.0", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2", "path-scurry": "^1.7.0" }, "bin": { @@ -5906,7 +6145,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "inBundle": true, + "dev": true, "engines": { "node": ">=8" } @@ -6367,12 +6606,6 @@ "node": ">=8" } }, - "node_modules/infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "inBundle": true - }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -6390,9 +6623,9 @@ "inBundle": true }, "node_modules/ini": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.0.tgz", - "integrity": "sha512-HLR38RSF2iulAzc3I/sma4CoYxQP844rPYCNfzGDOHqa/YqVlwuuZgBx6M50/X8dKgzk0cm1qRg3+47mK2N+cQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", "inBundle": true, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -6558,9 +6791,9 @@ } }, "node_modules/is-core-module": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz", - "integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==", + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", + "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", "inBundle": true, "dependencies": { "has": "^1.0.3" @@ -6936,6 +7169,18 @@ "node": ">=8" } }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/istanbul-lib-source-maps": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", @@ -6964,9 +7209,9 @@ } }, "node_modules/jackspeak": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.2.0.tgz", - "integrity": "sha512-r5XBrqIJfwRIjRt/Xr5fv9Wh09qyhHfKnYddDlpM+ibRR20qrYActpCAgU6U+d53EOEjzkvxPMVHSlgR7leXrQ==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.2.1.tgz", + "integrity": "sha512-MXbxovZ/Pm42f6cDIDkl3xpwv1AGwObKwfmjs2nQePiy85tP3fatofl3FC1aBsOtP/6fq5SbtgHwWcMsLP+bDw==", "inBundle": true, "dependencies": { "@isaacs/cliui": "^8.0.2" @@ -8718,9 +8963,9 @@ } }, "node_modules/minimatch": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.0.tgz", - "integrity": "sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", + "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", "inBundle": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -9036,15 +9281,16 @@ } }, "node_modules/node-gyp": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.3.1.tgz", - "integrity": "sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==", + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.0.tgz", + "integrity": "sha512-dMXsYP6gc9rRbejLXmTbVRYjAHw7ppswsKyMxuxJxxOHzluIO1rGp9TOQgjFJ+2MCqcOcQTOPB/8Xwhr+7s4Eg==", "inBundle": true, "dependencies": { "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", "glob": "^7.1.4", "graceful-fs": "^4.2.6", - "make-fetch-happen": "^10.0.3", + "make-fetch-happen": "^11.0.3", "nopt": "^6.0.0", "npmlog": "^6.0.0", "rimraf": "^3.0.2", @@ -9059,19 +9305,6 @@ "node": "^12.13 || ^14.13 || >=16" } }, - "node_modules/node-gyp/node_modules/@npmcli/fs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", - "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", - "inBundle": true, - "dependencies": { - "@gar/promisify": "^1.1.3", - "semver": "^7.3.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/node-gyp/node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -9101,87 +9334,6 @@ "concat-map": "0.0.1" } }, - "node_modules/node-gyp/node_modules/cacache": { - "version": "16.1.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", - "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", - "inBundle": true, - "dependencies": { - "@npmcli/fs": "^2.1.0", - "@npmcli/move-file": "^2.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "glob": "^8.0.1", - "infer-owner": "^1.0.4", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "mkdirp": "^1.0.4", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", - "tar": "^6.1.11", - "unique-filename": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/node-gyp/node_modules/cacache/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "inBundle": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/node-gyp/node_modules/cacache/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "inBundle": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/node-gyp/node_modules/cacache/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "inBundle": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-gyp/node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "inBundle": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/node-gyp/node_modules/gauge": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", @@ -9221,33 +9373,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/node-gyp/node_modules/make-fetch-happen": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", - "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", - "inBundle": true, - "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^16.1.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^2.0.3", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^9.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/node-gyp/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -9260,35 +9385,6 @@ "node": "*" } }, - "node_modules/node-gyp/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "inBundle": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/node-gyp/node_modules/minipass-fetch": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", - "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", - "inBundle": true, - "dependencies": { - "minipass": "^3.1.6", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, "node_modules/node-gyp/node_modules/nopt": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", @@ -9339,42 +9435,6 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "inBundle": true }, - "node_modules/node-gyp/node_modules/ssri": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", - "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", - "inBundle": true, - "dependencies": { - "minipass": "^3.1.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/node-gyp/node_modules/unique-filename": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", - "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", - "inBundle": true, - "dependencies": { - "unique-slug": "^3.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/node-gyp/node_modules/unique-slug": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", - "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", - "inBundle": true, - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/node-gyp/node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -9419,9 +9479,9 @@ "dev": true }, "node_modules/nopt": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.1.0.tgz", - "integrity": "sha512-ZFPLe9Iu0tnx7oWhFxAo4s7QTn8+NNDDxYNaKLjE7Dp0tbakQ3M1QhQzsnzXHQBTUO3K9BmwaxnyO8Ayn2I95Q==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz", + "integrity": "sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==", "inBundle": true, "dependencies": { "abbrev": "^2.0.0" @@ -9458,13 +9518,10 @@ } }, "node_modules/npm-audit-report": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/npm-audit-report/-/npm-audit-report-4.0.0.tgz", - "integrity": "sha512-k2o5476sLrp94b6Gl819YzlS7LAdb8lgE6yQCysBEji5E3WoUdRve6tiVMLKAPPdLfItU4kOSUycWS5HFTrbug==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/npm-audit-report/-/npm-audit-report-5.0.0.tgz", + "integrity": "sha512-EkXrzat7zERmUhHaoren1YhTxFwsOu5jypE84k6632SXTHcQE1z8V51GC6GVZt8LxkC+tbBcKMUBZAgk8SUSbw==", "inBundle": true, - "dependencies": { - "chalk": "^4.0.0" - }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -10115,9 +10172,9 @@ } }, "node_modules/pacote": { - "version": "15.1.3", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.1.3.tgz", - "integrity": "sha512-aRts8cZqxiJVDitmAh+3z+FxuO3tLNWEmwDRPEpDDiZJaRz06clP4XX112ynMT5uF0QNoMPajBBHnaStUEPJXA==", + "version": "15.2.0", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.2.0.tgz", + "integrity": "sha512-rJVZeIwHTUta23sIZgEIM62WYwbmGbThdbnkt81ravBplQv+HjyroqnLRNH2+sLJHcGZmLRmhPwACqhfTcOmnA==", "inBundle": true, "dependencies": { "@npmcli/git": "^4.0.0", @@ -10266,13 +10323,13 @@ "dev": true }, "node_modules/path-scurry": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.7.0.tgz", - "integrity": "sha512-UkZUeDjczjYRE495+9thsgcVgsaCPkaw80slmfVFgllxY+IO8ubTsOpFVjDPROBqJdHfVPUFRHPBV/WciOVfWg==", + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.9.2.tgz", + "integrity": "sha512-qSDLy2aGFPm8i4rsbHd4MNyTcrzHFsLQykrtbuGRknZZCBBVXSv2tSCDN2Cg6Rt/GFRw8GoW9y9Ecw5rIPG1sg==", "inBundle": true, "dependencies": { - "lru-cache": "^9.0.0", - "minipass": "^5.0.0" + "lru-cache": "^9.1.1", + "minipass": "^5.0.0 || ^6.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -10397,9 +10454,9 @@ "dev": true }, "node_modules/postcss-selector-parser": { - "version": "6.0.12", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.12.tgz", - "integrity": "sha512-NdxGCAZdRrwVI1sy59+Wzrh+pMMHxapGnpfenDVlMEXoOcvt4pGE0JLK9YY2F5dLxcFYA/YbVQKhcGU+FtSYQg==", + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", + "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -10617,9 +10674,9 @@ } }, "node_modules/read-package-json": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.3.tgz", - "integrity": "sha512-4QbpReW4kxFgeBQ0vPAqh2y8sXEB3D4t3jsXbJKIhBiF80KT6XRo45reqwtftju5J6ru1ax06A2Gb/wM1qCOEQ==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.4.tgz", + "integrity": "sha512-AEtWXYfopBj2z5N5PbkAOeNHRPUg5q+Nen7QLxV8M2zJq1ym6/lCz3fYNTCXe19puu2d06jfHhrP7v/S2PtMMw==", "inBundle": true, "dependencies": { "glob": "^10.2.2", @@ -10774,9 +10831,9 @@ } }, "node_modules/readable-stream": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.3.0.tgz", - "integrity": "sha512-MuEnA0lbSi7JS8XM+WNJlWZkHAAdm7gETHdFK//Q/mChGyj2akEFtdLZh32jSdkWGbRwCW9pn6g3LWDdDeZnBQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.4.0.tgz", + "integrity": "sha512-kDMOq0qLtxV9f/SQv522h8cxZBqNZXuXNyjyezmfAAuribMyVXziljpQ/uQhfE1XLg2/TLTW2DsnoE4VAi/krg==", "inBundle": true, "dependencies": { "abort-controller": "^3.0.0", @@ -10906,6 +10963,34 @@ "node": ">=14.0.0" } }, + "node_modules/release-please/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/release-please/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/release-please/node_modules/type-fest": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", @@ -11315,9 +11400,23 @@ } }, "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "inBundle": true }, "node_modules/safe-regex-test": { @@ -11355,9 +11454,9 @@ } }, "node_modules/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz", + "integrity": "sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==", "inBundle": true, "dependencies": { "lru-cache": "^6.0.0" @@ -11424,9 +11523,9 @@ } }, "node_modules/signal-exit": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.0.1.tgz", - "integrity": "sha512-uUWsN4aOxJAS8KOuf3QMyFtgm1pkb6I+KRZbRF/ghdf5T7sM+B1lLLzPDxswUjkmHyxQAVzEgG35E3NzDM9GVw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.0.2.tgz", + "integrity": "sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==", "inBundle": true, "engines": { "node": ">=14" @@ -11436,12 +11535,13 @@ } }, "node_modules/sigstore": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-1.4.0.tgz", - "integrity": "sha512-N7TRpSbFjY/TrFDg6yGAQSYBrQ5s6qmPiq4pD6fkv1LoyfMsLG0NwZWG2s5q+uttLHgyVyTa0Rogx2P78rN8kQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-1.6.0.tgz", + "integrity": "sha512-QODKff/qW/TXOZI6V/Clqu74xnInAS6it05mufj4/fSewexLtfEntgLZZcBtUK44CDQyUE5TUXYy1ARYzlfG9g==", "inBundle": true, "dependencies": { "@sigstore/protobuf-specs": "^0.1.0", + "@sigstore/tuf": "^1.0.0", "make-fetch-happen": "^11.0.1", "tuf-js": "^1.1.3" }, @@ -11768,12 +11868,12 @@ } }, "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "inBundle": true, "dependencies": { - "safe-buffer": "~5.1.0" + "safe-buffer": "~5.2.0" } }, "node_modules/string-width": { @@ -11953,15 +12053,15 @@ } }, "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.3.1.tgz", + "integrity": "sha512-knBY82pjmnIzK3NifMo3RxEIRD9E0kIzV4BKcyTZ9+9kWgLMxd4PrsTSMoFQUabgRBbF8KOLRDCyKgNV+iK44Q==", "inBundle": true, - "dependencies": { - "has-flag": "^4.0.0" - }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, "node_modules/supports-preserve-symlinks-flag": { @@ -14150,9 +14250,9 @@ } }, "node_modules/tar": { - "version": "6.1.14", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.14.tgz", - "integrity": "sha512-piERznXu0U7/pW7cdSn7hjqySIVTYT6F76icmFk7ptU7dDYlXTm5r9A6K04R2vU3olYgoKeo1Cg3eeu5nhftAw==", + "version": "6.1.15", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz", + "integrity": "sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==", "inBundle": true, "dependencies": { "chownr": "^2.0.0", @@ -14515,13 +14615,14 @@ } }, "node_modules/tuf-js": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-1.1.5.tgz", - "integrity": "sha512-inqodgxdsmuxrtQVbu6tPNgRKWD1Boy3VB6GO7KczJZpAHiTukwhSzXUSzvDcw5pE2Jo8ua+e1ykpHv7VdPVlQ==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-1.1.7.tgz", + "integrity": "sha512-i3P9Kgw3ytjELUfpuKVDNBJvk4u5bXL6gskv572mcevPbSKCV3zt3djhmlEQ65yERjIbOSncy7U4cQJaB1CBCg==", "inBundle": true, "dependencies": { "@tufjs/models": "1.0.4", - "make-fetch-happen": "^11.1.0" + "debug": "^4.3.4", + "make-fetch-happen": "^11.1.1" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -15204,9 +15305,9 @@ } }, "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "inBundle": true, "dependencies": { "ansi-regex": "^6.0.1" @@ -15463,7 +15564,7 @@ }, "smoke-tests": { "name": "@npmcli/smoke-tests", - "version": "1.0.0", + "version": "1.0.1", "license": "ISC", "devDependencies": { "@npmcli/eslint-config": "^4.0.0", @@ -15471,8 +15572,6 @@ "@npmcli/promise-spawn": "^6.0.2", "@npmcli/template-oss": "4.14.1", "http-proxy": "^1.18.1", - "just-extend": "^6.2.0", - "just-safe-set": "^4.2.1", "tap": "^16.3.4", "which": "^3.0.0" }, @@ -15482,7 +15581,7 @@ }, "workspaces/arborist": { "name": "@npmcli/arborist", - "version": "6.2.9", + "version": "6.2.10", "license": "ISC", "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", @@ -15526,7 +15625,6 @@ "@npmcli/eslint-config": "^4.0.0", "@npmcli/template-oss": "4.14.1", "benchmark": "^2.1.4", - "chalk": "^4.1.0", "minify-registry-metadata": "^3.0.0", "nock": "^13.3.0", "tap": "^16.3.4", @@ -15539,10 +15637,11 @@ }, "workspaces/config": { "name": "@npmcli/config", - "version": "6.1.6", + "version": "6.2.1", "license": "ISC", "dependencies": { "@npmcli/map-workspaces": "^3.0.2", + "ci-info": "^3.8.0", "ini": "^4.1.0", "nopt": "^7.0.0", "proc-log": "^3.0.0", @@ -15552,6 +15651,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", + "@npmcli/mock-globals": "^1.0.0", "@npmcli/template-oss": "4.14.1", "tap": "^16.3.4" }, @@ -15578,10 +15678,10 @@ } }, "workspaces/libnpmdiff": { - "version": "5.0.17", + "version": "5.0.18", "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.2.9", + "@npmcli/arborist": "^6.2.10", "@npmcli/disparity-colors": "^3.0.0", "@npmcli/installed-package-contents": "^2.0.2", "binary-extensions": "^2.2.0", @@ -15601,12 +15701,11 @@ } }, "workspaces/libnpmexec": { - "version": "5.0.17", + "version": "6.0.1", "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.2.9", + "@npmcli/arborist": "^6.2.10", "@npmcli/run-script": "^6.0.0", - "chalk": "^4.1.0", "ci-info": "^3.7.1", "npm-package-arg": "^10.1.0", "npmlog": "^7.0.1", @@ -15622,9 +15721,9 @@ "@npmcli/mock-registry": "^1.0.0", "@npmcli/template-oss": "4.14.1", "bin-links": "^4.0.1", + "chalk": "^5.2.0", "just-extend": "^6.2.0", "just-safe-set": "^4.2.1", - "minify-registry-metadata": "^3.0.0", "tap": "^16.3.4" }, "engines": { @@ -15632,10 +15731,10 @@ } }, "workspaces/libnpmfund": { - "version": "4.0.17", + "version": "4.0.18", "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.2.9" + "@npmcli/arborist": "^6.2.10" }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", @@ -15682,10 +15781,10 @@ } }, "workspaces/libnpmpack": { - "version": "5.0.17", + "version": "5.0.18", "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.2.9", + "@npmcli/arborist": "^6.2.10", "@npmcli/run-script": "^6.0.0", "npm-package-arg": "^10.1.0", "pacote": "^15.0.8" @@ -15702,7 +15801,7 @@ } }, "workspaces/libnpmpublish": { - "version": "7.1.4", + "version": "7.4.0", "license": "ISC", "dependencies": { "ci-info": "^3.6.1", @@ -15716,6 +15815,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", + "@npmcli/mock-globals": "^1.0.0", "@npmcli/mock-registry": "^1.0.0", "@npmcli/template-oss": "4.14.1", "lodash.clonedeep": "^4.5.0", diff --git a/package.json b/package.json index 9486e8c6ef309..f345781248e43 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,11 @@ { - "version": "9.6.6", + "version": "9.7.2", "name": "npm", "description": "a package manager for JavaScript", "workspaces": [ "docs", "smoke-tests", + "mock-globals", "mock-registry", "workspaces/*" ], @@ -32,9 +33,7 @@ "url": "https://github.com/npm/cli/issues" }, "directories": { - "bin": "./bin", "doc": "./doc", - "lib": "./lib", "man": "./man" }, "main": "./index.js", @@ -53,36 +52,36 @@ }, "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^6.2.9", - "@npmcli/config": "^6.1.6", + "@npmcli/arborist": "^6.2.10", + "@npmcli/config": "^6.2.1", "@npmcli/map-workspaces": "^3.0.4", - "@npmcli/package-json": "^3.0.0", - "@npmcli/run-script": "^6.0.1", + "@npmcli/package-json": "^3.1.1", + "@npmcli/run-script": "^6.0.2", "abbrev": "^2.0.0", "archy": "~1.0.0", - "cacache": "^17.1.0", - "chalk": "^4.1.2", + "cacache": "^17.1.3", + "chalk": "^5.2.0", "ci-info": "^3.8.0", "cli-columns": "^4.0.0", "cli-table3": "^0.6.3", "columnify": "^1.6.0", "fastest-levenshtein": "^1.0.16", "fs-minipass": "^3.0.2", - "glob": "^10.2.2", + "glob": "^10.2.7", "graceful-fs": "^4.2.11", "hosted-git-info": "^6.1.1", - "ini": "^4.1.0", + "ini": "^4.1.1", "init-package-json": "^5.0.0", "is-cidr": "^4.0.2", "json-parse-even-better-errors": "^3.0.0", "libnpmaccess": "^7.0.2", - "libnpmdiff": "^5.0.17", - "libnpmexec": "^5.0.17", - "libnpmfund": "^4.0.17", + "libnpmdiff": "^5.0.18", + "libnpmexec": "^6.0.1", + "libnpmfund": "^4.0.18", "libnpmhook": "^9.0.3", "libnpmorg": "^5.0.4", - "libnpmpack": "^5.0.17", - "libnpmpublish": "^7.1.4", + "libnpmpack": "^5.0.18", + "libnpmpublish": "^7.4.0", "libnpmsearch": "^6.0.2", "libnpmteam": "^5.0.3", "libnpmversion": "^4.0.2", @@ -91,9 +90,9 @@ "minipass": "^5.0.0", "minipass-pipeline": "^1.2.4", "ms": "^2.1.2", - "node-gyp": "^9.3.1", - "nopt": "^7.1.0", - "npm-audit-report": "^4.0.0", + "node-gyp": "^9.4.0", + "nopt": "^7.2.0", + "npm-audit-report": "^5.0.0", "npm-install-checks": "^6.1.1", "npm-package-arg": "^10.1.0", "npm-pick-manifest": "^8.0.1", @@ -102,16 +101,16 @@ "npm-user-validate": "^2.0.0", "npmlog": "^7.0.1", "p-map": "^4.0.0", - "pacote": "^15.1.3", + "pacote": "^15.2.0", "parse-conflict-json": "^3.0.1", "proc-log": "^3.0.0", "qrcode-terminal": "^0.12.0", "read": "^2.1.0", - "read-package-json": "^6.0.3", - "read-package-json-fast": "^3.0.2", - "semver": "^7.5.0", + "semver": "^7.5.2", + "sigstore": "^1.6.0", "ssri": "^10.0.4", - "tar": "^6.1.14", + "supports-color": "^9.3.1", + "tar": "^6.1.15", "text-table": "~0.2.0", "tiny-relative-date": "^1.3.0", "treeverse": "^3.0.0", @@ -175,10 +174,10 @@ "proc-log", "qrcode-terminal", "read", - "read-package-json", - "read-package-json-fast", "semver", + "sigstore", "ssri", + "supports-color", "tar", "text-table", "tiny-relative-date", @@ -191,10 +190,13 @@ "@npmcli/docs": "^1.0.0", "@npmcli/eslint-config": "^4.0.0", "@npmcli/fs": "^3.1.0", - "@npmcli/git": "^4.0.4", + "@npmcli/git": "^4.1.0", + "@npmcli/mock-globals": "^1.0.0", "@npmcli/mock-registry": "^1.0.0", "@npmcli/promise-spawn": "^6.0.2", "@npmcli/template-oss": "4.14.1", + "@tufjs/repo-mock": "^1.3.1", + "diff": "^5.1.0", "licensee": "^10.0.0", "nock": "^13.3.0", "npm-packlist": "^7.0.4", @@ -209,17 +211,14 @@ "dumpconf": "env | grep npm | sort | uniq", "licenses": "licensee --production --errors-only", "test": "tap", + "test:nocolor": "CI=true tap -Rclassic", "test-all": "node . run test -ws -iwr --if-present", "snap": "tap", "prepack": "node . run build -w docs", - "test:nocleanup": "NO_TEST_CLEANUP=1 node . run test --", - "sudotest": "sudo node . run run test --", - "sudotest:nocleanup": "sudo NO_TEST_CLEANUP=1 node . run test --", "posttest": "node . run lint", "lint": "eslint \"**/*.js\"", "lintfix": "node . run lint -- --fix", "lint-all": "node . run lint -ws -iwr --if-present", - "prelint": "rimraf test/npm_cache*", "resetdeps": "node scripts/resetdeps.js", "rp-pull-request": "node scripts/update-authors.js", "postlint": "template-oss-check", @@ -229,8 +228,6 @@ "test-env": [ "LC_ALL=sk" ], - "color": 1, - "files": "test/{lib,bin,index.js}", "timeout": 600, "nyc-arg": [ "--exclude", @@ -238,13 +235,15 @@ "--exclude", "smoke-tests/**", "--exclude", + "mock-globals/**", + "--exclude", "mock-registry/**", "--exclude", "workspaces/**", "--exclude", "tap-snapshots/**" ], - "test-ignore": "^(docs|smoke-tests|mock-registry|workspaces)/" + "test-ignore": "^(docs|smoke-tests|mock-globals|mock-registry|workspaces)/" }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", diff --git a/scripts/fish-completion.js b/scripts/fish-completion.js index 6357c1032fe56..4686befd8ba7f 100644 --- a/scripts/fish-completion.js +++ b/scripts/fish-completion.js @@ -3,7 +3,7 @@ const fs = require('fs/promises') const { resolve } = require('path') const { commands, aliases } = require('../lib/utils/cmd-list.js') -const { definitions } = require('../lib/utils/config/index.js') +const { definitions } = require('@npmcli/config/lib/definitions') async function main () { const file = resolve(__dirname, '..', 'lib', 'utils', 'completion.fish') diff --git a/scripts/remove-files.js b/scripts/remove-files.js deleted file mode 100644 index 75b4385229178..0000000000000 --- a/scripts/remove-files.js +++ /dev/null @@ -1,11 +0,0 @@ -const { join } = require('path') -const { CWD, run, pkg, fs, git } = require('./util.js') - -const main = async () => { - await git.dirty() - for (const p of pkg.files) { - await fs.rimraf(join(CWD, p)) - } -} - -run(main) diff --git a/scripts/template-oss/ci-release.yml b/scripts/template-oss/ci-release.yml index 44b184db8ae81..5170c6e399981 100644 --- a/scripts/template-oss/ci-release.yml +++ b/scripts/template-oss/ci-release.yml @@ -1,6 +1,10 @@ {{> ciRelease}} smoke-publish: + # This cant be tested on Windows because our node_modules directory + # checks in symlinks which are not supported there. This should be + # fixed somehow, because this means some forms of local development + # are likely broken on Windows as well. {{> jobMatrix jobName="Smoke Publish" jobCheck=(obj sha="inputs.check-sha") @@ -14,10 +18,18 @@ NPM_VERSION="$({{ rootNpmPath }} --version)-$GITHUB_SHA.0" {{ rootNpmPath }} version $NPM_VERSION --ignore-scripts node scripts/publish.js --pack-destination=$RUNNER_TEMP - {{ rootNpmPath }} install --global $RUNNER_TEMP/npm-$NPM_VERSION.tgz + export SMOKE_PUBLISH_TARBALL="$RUNNER_TEMP/npm-$NPM_VERSION.tgz" + {{ rootNpmPath }} install --global $SMOKE_PUBLISH_TARBALL {{ rootNpmPath }} install -w smoke-tests --ignore-scripts --no-audit --no-fund - node scripts/remove-files.js # call installed npm instead of local source since we are testing # the packed tarball that we just installed globally - npm test -w smoke-tests --ignore-scripts + NPM_GLOBAL_VERSION="$(npm --version)" + npm help + if [ "$NPM_GLOBAL_VERSION" == "$NPM_VERSION" ]; then + npm test -w smoke-tests --ignore-scripts + else + echo "global npm is not the correct version for smoke-publish" + echo "found: $NPM_GLOBAL_VERSION, expected: $NPM_VERSION" + exit 1 + fi {{> stepChecks jobCheck=true }} diff --git a/scripts/template-oss/node-integration.yml b/scripts/template-oss/node-integration.yml index 0edf91eb0d51f..4513ab0e43d72 100644 --- a/scripts/template-oss/node-integration.yml +++ b/scripts/template-oss/node-integration.yml @@ -487,7 +487,7 @@ jobs: env: $\{{ matrix.env }} run: | EXIT=1 - if [[ "$\{{ steps.command.outcome }}" == "success" || "$\{{ matrix.flaky }}" == "true" || "$\{{ matrix.knownFailure }}" == "true" || $NODE_VERSION == "nightly"]]; then + if [[ "$\{{ steps.command.outcome }}" == "success" || "$\{{ matrix.flaky }}" == "true" || "$\{{ matrix.knownFailure }}" == "true" || $NODE_VERSION == "nightly" ]]; then EXIT=0 fi exit $EXIT diff --git a/smoke-tests/package.json b/smoke-tests/package.json index 0cf40e107d3e5..6bd9cee3e3152 100644 --- a/smoke-tests/package.json +++ b/smoke-tests/package.json @@ -1,7 +1,7 @@ { "name": "@npmcli/smoke-tests", "description": "The npm cli smoke tests", - "version": "1.0.0", + "version": "1.0.1", "private": true, "scripts": { "lint": "eslint \"**/*.js\"", @@ -23,8 +23,6 @@ "@npmcli/promise-spawn": "^6.0.2", "@npmcli/template-oss": "4.14.1", "http-proxy": "^1.18.1", - "just-extend": "^6.2.0", - "just-safe-set": "^4.2.1", "tap": "^16.3.4", "which": "^3.0.0" }, diff --git a/smoke-tests/tap-snapshots/test/index.js.test.cjs b/smoke-tests/tap-snapshots/test/index.js.test.cjs index d0ca4de117ee7..5ba8778109226 100644 --- a/smoke-tests/tap-snapshots/test/index.js.test.cjs +++ b/smoke-tests/tap-snapshots/test/index.js.test.cjs @@ -33,7 +33,7 @@ All commands: whoami Specify configs in the ini-formatted file: - {NPM}/{TESTDIR}/project/.npmrc + {NPM}/{TESTDIR}/home/.npmrc or on the command line via: npm --key=value More configuration info: npm help config @@ -57,8 +57,8 @@ npm ERR! npm ERR! Options: npm ERR! [--install-strategy ] [--legacy-bundling] npm ERR! [--global-style] [--omit [--omit ...]] -npm ERR! [--strict-peer-deps] [--no-package-lock] [--foreground-scripts] -npm ERR! [--ignore-scripts] [--no-audit] [--no-bin-links] [--no-fund] [--dry-run] +npm ERR! [--strict-peer-deps] [--foreground-scripts] [--ignore-scripts] [--no-audit] +npm ERR! [--no-bin-links] [--no-fund] [--dry-run] npm ERR! [-w|--workspace [-w|--workspace ...]] npm ERR! [-ws|--workspaces] [--include-workspace-root] [--install-links] npm ERR! diff --git a/smoke-tests/test/fixtures/setup.js b/smoke-tests/test/fixtures/setup.js index 180fe02a15383..89a036cb39aeb 100644 --- a/smoke-tests/test/fixtures/setup.js +++ b/smoke-tests/test/fixtures/setup.js @@ -3,19 +3,31 @@ const { existsSync } = require('fs') const { join, resolve, sep, extname, relative, delimiter } = require('path') const which = require('which') const spawn = require('@npmcli/promise-spawn') -const justExtend = require('just-extend') -const justSet = require('just-safe-set') const MockRegistry = require('@npmcli/mock-registry') -const { Blob } = require('buffer') const http = require('http') const httpProxy = require('http-proxy') -const { SMOKE_PUBLISH_NPM, CI, PATH, Path, TAP_CHILD_ID = '0' } = process.env -const PORT = 12345 + (+TAP_CHILD_ID) +const { SMOKE_PUBLISH_NPM, SMOKE_PUBLISH_TARBALL, CI, PATH, Path, TAP_CHILD_ID = '0' } = process.env +const PROXY_PORT = 12345 + (+TAP_CHILD_ID) +const HTTP_PROXY = `http://localhost:${PROXY_PORT}/` + +const NODE_PATH = process.execPath const CLI_ROOT = resolve(process.cwd(), '..') +const CLI_JS_BIN = join('bin', 'npm-cli.js') +const NPM_PATH = join(CLI_ROOT, CLI_JS_BIN) + +const WINDOWS = process.platform === 'win32' +const GLOBAL_BIN = WINDOWS ? '' : 'bin' +const GLOBAL_NODE_MODULES = join(WINDOWS ? '' : 'lib', 'node_modules') + +const getOpts = (...a) => { + const [opts, args] = a.reduce((acc, arg) => { + acc[typeof arg === 'object' ? 0 : 1].push(arg) + return acc + }, [[], []]) + return [Object.assign({}, ...opts), args] +} -const set = (obj, ...args) => justSet(obj, ...args) && obj -const merge = (...args) => justExtend(true, ...args) const normalizePath = path => path.replace(/[A-Z]:/, '').replace(/\\/g, '/') const testdirHelper = (obj) => { @@ -31,76 +43,84 @@ const testdirHelper = (obj) => { return obj } -const getSpawnArgs = async () => { +const getNpmRoot = (helpText) => { + return helpText + .split('\n') + .slice(-1)[0] + .match(/^npm@.*?\s(.*)$/) + ?.[1] +} + +const getCleanPaths = async () => { const cliBin = join('bin', 'npm') - const cliJsBin = join('bin', 'npm-cli.js') const npmLinks = await which('npm', { all: true }) const npmPaths = await Promise.all(npmLinks.map(npm => fs.realpath(npm))) const cleanNpmPaths = [...new Set([ CLI_ROOT, join(CLI_ROOT, cliBin), - join(CLI_ROOT, cliJsBin), + join(CLI_ROOT, CLI_JS_BIN), ...npmLinks, ...npmPaths, ...npmPaths.map(n => n.replace(sep + cliBin, '')), - ...npmPaths.map(n => n.replace(sep + cliJsBin, '')), + ...npmPaths.map(n => n.replace(sep + CLI_JS_BIN, '')), ])] - if (SMOKE_PUBLISH_NPM) { - return { - command: ['npm'], - NPM: cleanNpmPaths, - } - } - - return { - command: [process.execPath, join(CLI_ROOT, cliJsBin)], - NODE: process.execPath, + return Object.entries({ + NODE: NODE_PATH, NPM: cleanNpmPaths, - } + }) +} + +const createRegistry = async (t, { debug, ...opts } = {}) => { + const registry = new MockRegistry({ + tap: t, + registry: 'http://smoke-test-registry.club/', + debug, + strict: true, + ...opts, + }) + + const proxy = httpProxy.createProxyServer({}) + const server = http.createServer((req, res) => proxy.web(req, res, { target: registry.origin })) + await new Promise(res => server.listen(PROXY_PORT, res)) + + t.teardown(() => server.close()) + + return registry } -module.exports = async (t, { testdir = {}, debug } = {}) => { +module.exports = async (t, { testdir = {}, debug, registry: _registry = {} } = {}) => { + const debugLog = debug || CI ? (...a) => console.error(...a) : () => {} + const cleanPaths = await getCleanPaths() + // setup fixtures const root = t.testdir({ cache: {}, project: { '.npmrc': '' }, - bin: {}, global: { '.npmrc': '' }, + home: { '.npmrc': '' }, ...testdirHelper(testdir), }) const paths = { root, project: join(root, 'project'), global: join(root, 'global'), - userConfig: join(root, 'project', '.npmrc'), + home: join(root, 'home'), + userConfig: join(root, 'home', '.npmrc'), globalConfig: join(root, 'global', '.npmrc'), cache: join(root, 'cache'), - bin: join(root, 'bin'), + globalBin: join(root, 'global', GLOBAL_BIN), + globalNodeModules: join(root, 'global', GLOBAL_NODE_MODULES), } - const registry = new MockRegistry({ - tap: t, - registry: 'http://smoke-test-registry.club/', - debug, - strict: true, - }) - const httpProxyRegistry = `http://localhost:${PORT}` - const proxy = httpProxy.createProxyServer({}) - const server = http.createServer((req, res) => proxy.web(req, res, { target: registry.origin })) - await new Promise(res => server.listen(PORT, res)) - t.teardown(() => server.close()) + const registry = await createRegistry(t, { ..._registry, debug }) // update notifier should never be written t.afterEach((t) => { t.equal(existsSync(join(paths.cache, '_update-notifier-last-checked')), false) }) - const debugLog = debug || CI ? (...a) => console.error(...a) : () => {} - const { command, ...spawnPaths } = await getSpawnArgs({ log: debugLog }) - const cleanPaths = Object.entries(spawnPaths) - const cleanOutput = s => { // sometimes we print normalized paths in snapshots regardless of // platform so replace those first then replace platform style paths @@ -118,7 +138,7 @@ module.exports = async (t, { testdir = {}, debug } = {}) => { } return s .split(relative(CLI_ROOT, t.testdirName)).join('{TESTDIR}') - .split(httpProxyRegistry).join('{REGISTRY}') + .split(HTTP_PROXY).join('{PROXY_REGISTRY}') .split(registry.origin).join('{REGISTRY}') .replace(/\\+/g, '/') .replace(/\r\n/g, '\n') @@ -130,41 +150,23 @@ module.exports = async (t, { testdir = {}, debug } = {}) => { const log = (...a) => debugLog(cleanOutput(a.join(' '))) t.cleanSnapshot = cleanOutput - const npm = async (...args) => { - const defaultFlags = [ - `--registry=${httpProxyRegistry}`, - `--cache=${paths.cache}`, - `--prefix=${paths.project}`, - `--userconfig=${paths.userConfig}`, - `--globalconfig=${paths.globalConfig}`, - '--no-audit', - '--no-update-notifier', - '--loglevel=silly', - '--fetch-retries=0', - ] - const [positionals, flags] = args.reduce((acc, arg) => { - if (arg.startsWith('-')) { - acc[1].push(arg) - } else { - acc[0].push(arg) - } - return acc - }, [[], defaultFlags]) - - const spawnCmd = command[0] - const spawnArgs = [...command.slice(1), ...positionals, ...flags] + const getPath = () => `${paths.globalBin}${delimiter}${Path || PATH}` + const getEnvPath = () => ({ [Path ? 'Path' : 'PATH']: getPath() }) - log(`${spawnCmd} ${spawnArgs.filter(a => !defaultFlags.includes(a)).join(' ')}`) + const baseSpawn = async (spawnCmd, spawnArgs, { cwd = paths.project, env, ...opts } = {}) => { + log(`CWD: ${cwd}`) + log(`${spawnCmd} ${spawnArgs.join(' ')}`) log('-'.repeat(40)) const { stderr, stdout } = await spawn(spawnCmd, spawnArgs, { - cwd: paths.project, + cwd, env: { - HTTP_PROXY: httpProxyRegistry, + ...getEnvPath(), HOME: paths.root, - [Path ? 'Path' : 'PATH']: `${Path || PATH}${delimiter}${paths.bin}`, - COMSPEC: process.env.COMSPEC, + ComSpec: process.env.ComSpec, + ...env, }, + ...opts, }) log(stderr) @@ -172,46 +174,91 @@ module.exports = async (t, { testdir = {}, debug } = {}) => { log(stdout) log('='.repeat(40)) - return cleanOutput(stdout) + return stdout } - // helpers for reading/writing files and their source - const readFile = async (f) => { - const file = await fs.readFile(join(paths.project, f), 'utf-8') - return extname(f) === '.json' ? JSON.parse(file) : file - } + const baseNpm = async (...a) => { + const [{ cwd, cmd, argv = [], proxy = true, ...opts }, args] = getOpts(...a) - // Returns a recurisve list of relative file paths in the testdir root - // will also follow symlinks and print their relative paths - const tree = async (rootDir = paths.project, dir = rootDir) => { - const results = {} - for (const item of await fs.readdir(dir)) { - const itemPath = join(dir, item) - const relPath = relative(rootDir, itemPath) - const stat = await fs.lstat(itemPath) - - if (stat.isSymbolicLink()) { - const realpath = await fs.realpath(itemPath) - merge(results, await tree(rootDir, realpath)) - } else if (stat.isDirectory()) { - merge(results, await tree(rootDir, itemPath)) + const isGlobal = args.some(arg => ['-g', '--global', '--global=true'].includes(arg)) + + const defaultFlags = [ + proxy ? `--registry=${HTTP_PROXY}` : null, + `--cache=${paths.cache}`, + `--prefix=${isGlobal ? paths.global : cwd}`, + `--userconfig=${paths.userConfig}`, + `--globalconfig=${paths.globalConfig}`, + '--no-audit', + '--no-update-notifier', + '--loglevel=silly', + '--fetch-retries=0', + ].filter(Boolean) + + const cliArgv = args.reduce((acc, arg) => { + if (arg.startsWith('-')) { + acc[1].push(arg) } else { - const raw = await readFile(relPath) - const content = typeof raw === 'string' ? `${new Blob([raw]).size} bytes` : raw - merge(results, set({}, relPath.split(sep), content)) + acc[0].push(arg) } + return acc + }, [[], defaultFlags]).reduce((acc, i) => acc.concat(i), []) + + return baseSpawn(cmd, [...argv, ...cliArgv], { + cwd, + env: proxy ? { HTTP_PROXY } : {}, + ...opts, + }) + } + + const npmLocal = async (...args) => { + const [{ force = false }] = getOpts(...args) + if (SMOKE_PUBLISH_NPM && !force) { + throw new Error('npmLocal cannot be called during smoke-publish') } - return results + return baseNpm({ + cwd: CLI_ROOT, + cmd: process.execPath, + argv: ['.'], + proxy: false, + }, ...args) + } + + const npmPath = async (...args) => baseNpm({ + cwd: paths.project, + cmd: 'npm', + shell: true, + }, ...args) + + const npm = async (...args) => baseNpm({ + cwd: paths.project, + cmd: process.execPath, + argv: [NPM_PATH], + }, ...args) + + // helpers for reading/writing files and their source + const readFile = async (f) => { + const file = await fs.readFile(join(paths.project, f), 'utf-8') + return extname(f) === '.json' ? JSON.parse(file) : file } return { - npm, + npmPath, + npmLocal, + npm: SMOKE_PUBLISH_NPM ? npmPath : npm, + spawn: baseSpawn, readFile, - tree, + getPath, paths, registry, - isSmokePublish: !!SMOKE_PUBLISH_NPM, + npmLocalTarball: async () => SMOKE_PUBLISH_TARBALL ?? + npmLocal('pack', `--pack-destination=${root}`).then(r => join(root, r)), } } module.exports.testdir = testdirHelper +module.exports.getNpmRoot = getNpmRoot +module.exports.CLI_ROOT = CLI_ROOT +module.exports.WINDOWS = WINDOWS +module.exports.SMOKE_PUBLISH = !!SMOKE_PUBLISH_NPM +module.exports.SMOKE_PUBLISH_TARBALL = SMOKE_PUBLISH_TARBALL +module.exports.HTTP_PROXY = HTTP_PROXY diff --git a/smoke-tests/test/index.js b/smoke-tests/test/index.js index 152bab15666f2..fc005dc7cd8f2 100644 --- a/smoke-tests/test/index.js +++ b/smoke-tests/test/index.js @@ -3,7 +3,7 @@ const t = require('tap') const setup = require('./fixtures/setup.js') t.test('basic', async t => { - const { registry, npm, isSmokePublish, readFile, paths } = await setup(t, { + const { registry, npm, npmPath, npmLocal, readFile, paths } = await setup(t, { testdir: { packages: { 'abbrev-1.0.4': { @@ -43,10 +43,32 @@ t.test('basic', async t => { t.equal(pkg.version, '1.0.0', 'should have expected generated version') }) + await t.test('npm root', async t => { + const npmRoot = await npm('help').then(setup.getNpmRoot) + + if (setup.SMOKE_PUBLISH) { + const globalNpmRoot = await npmPath('help').then(setup.getNpmRoot) + t.rejects(npmLocal('help'), 'npm local rejects during smoke publish') + t.not(npmRoot, setup.CLI_ROOT, 'npm root is not the local source dir') + t.equal( + npmRoot, + globalNpmRoot, + 'during smoke publish, npm root and global root are equal' + ) + } else { + t.equal( + await npmLocal('help').then(setup.getNpmRoot), + setup.CLI_ROOT, + 'npm local root is the local source dir' + ) + t.equal(npmRoot, setup.CLI_ROOT, 'npm root is the local source dir') + } + }) + await t.test('npm --version', async t => { const v = await npm('--version') - if (isSmokePublish) { + if (setup.SMOKE_PUBLISH) { t.match(v.trim(), /-[0-9a-f]{40}\.\d$/, 'must have a git version') } else { t.match(v.trim(), /^\d+\.\d+\.\d+/, 'has a version') diff --git a/smoke-tests/test/npm-replace-global.js b/smoke-tests/test/npm-replace-global.js new file mode 100644 index 0000000000000..4e6b78b881312 --- /dev/null +++ b/smoke-tests/test/npm-replace-global.js @@ -0,0 +1,164 @@ + +const t = require('tap') +const { join, dirname, basename, extname } = require('path') +const fs = require('fs/promises') +const _which = require('which') +const setup = require('./fixtures/setup.js') + +const which = async (cmd, opts) => { + const path = await _which(cmd, { nothrow: true, ...opts }) + return path ? join(dirname(path), basename(path, extname(path))) : null +} + +const setupNpmGlobal = async (t, opts) => { + const mock = await setup(t, opts) + + return { + ...mock, + getPaths: async () => { + const binContents = await fs.readdir(mock.paths.globalBin) + .then(r => r.filter(p => p !== '.npmrc' && p !== 'node_modules')) + .catch(() => null) + + const nodeModulesContents = await fs.readdir(join(mock.paths.globalNodeModules, 'npm')) + .catch(() => null) + + return { + npmRoot: await mock.npmPath('help').then(setup.getNpmRoot), + pathNpm: await which('npm', { path: mock.getPath(), nothrow: true }), + globalNpm: await which('npm', { nothrow: true }), + pathNpx: await which('npx', { path: mock.getPath(), nothrow: true }), + globalNpx: await which('npx', { nothrow: true }), + binContents, + nodeModulesContents, + } + }, + } +} + +t.test('pack and replace global self', async t => { + const { + npm, + npmLocalTarball, + npmPath, + getPaths, + paths: { globalBin, globalNodeModules }, + } = await setupNpmGlobal(t, { + testdir: { + project: { + 'package.json': { name: 'npm', version: '999.999.999' }, + }, + }, + }) + + const tarball = await npmLocalTarball() + + await npm('install', tarball, '--global') + + t.equal( + await fs.realpath(join(globalBin, 'npm')), + setup.WINDOWS ? join(globalBin, 'npm') : join(globalNodeModules, 'npm/bin/npm-cli.js'), + 'npm realpath is in the testdir' + ) + t.equal( + await fs.realpath(join(globalBin, 'npx')), + setup.WINDOWS ? join(globalBin, 'npx') : join(globalNodeModules, 'npm/bin/npx-cli.js'), + 'npx realpath is in the testdir' + ) + + const prePaths = await getPaths() + t.equal(prePaths.npmRoot, join(globalNodeModules, 'npm'), 'npm root is in the testdir') + t.equal(prePaths.pathNpm, join(globalBin, 'npm'), 'npm bin is in the testdir') + t.equal(prePaths.pathNpx, join(globalBin, 'npx'), 'npx bin is in the testdir') + t.not(prePaths.pathNpm, prePaths.globalNpm, 'npm bin is not the same as the global one') + t.not(prePaths.pathNpx, prePaths.globalNpx, 'npm bin is not the same as the global one') + t.ok(prePaths.nodeModulesContents.length > 1, 'node modules has npm contents') + t.ok(prePaths.nodeModulesContents.includes('node_modules'), 'npm has its node_modules') + + t.strictSame( + prePaths.binContents, + ['npm', 'npx'].flatMap(p => setup.WINDOWS ? [p, `${p}.cmd`, `${p}.ps1`] : p), + 'bin has npm and npx' + ) + + await npmPath('pack') + await npmPath('install', 'npm-999.999.999.tgz', '--global') + + const postPaths = await getPaths() + t.not(prePaths.npmRoot, postPaths.npmRoot, 'npm roots are different') + t.equal(postPaths.pathNpm, postPaths.globalNpm, 'npm bin is the same as the global one') + t.equal(postPaths.pathNpx, postPaths.globalNpx, 'npx bin is the same as the global one') + t.equal(postPaths.pathNpm, prePaths.globalNpm, 'after install npm bin is same as previous global') + t.equal(postPaths.pathNpx, prePaths.globalNpx, 'after install npx bin is same as previous global') + t.strictSame(postPaths.binContents, [], 'bin is empty') + t.strictSame(postPaths.nodeModulesContents, ['package.json'], 'contents is only package.json') +}) + +t.test('publish and replace global self', async t => { + let publishedPackument = null + const pkg = require('../../package.json') + const { name, version } = pkg + + const { + npm, + npmPath, + registry, + npmLocal, + npmLocalTarball, + getPaths, + paths: { globalBin, globalNodeModules, cache }, + } = await setupNpmGlobal(t, { + testdir: { + home: { + '.npmrc': `${setup.HTTP_PROXY.slice(5)}:_authToken = test-token`, + }, + }, + }) + + const npmPackage = async ({ manifest, ...opts } = {}) => { + await registry.package({ + manifest: registry.manifest({ name, ...manifest }), + ...opts, + }) + } + + const npmInstall = async (useNpm) => { + await npmPackage({ + manifest: { packuments: [publishedPackument] }, + tarballs: { [version]: tarball }, + times: 2, + }) + await fs.rm(cache, { recursive: true, force: true }) + await useNpm('install', 'npm@latest', '--global') + return getPaths() + } + + const tarball = await npmLocalTarball() + + if (setup.SMOKE_PUBLISH) { + await npmPackage() + } + registry.nock.put('/npm', body => { + if (body._id === 'npm' && body.versions[version]) { + publishedPackument = body.versions[version] + return true + } + return false + }).reply(201, {}) + await npmLocal('publish', { proxy: true, force: true }) + + const paths = await npmInstall(npm) + t.equal(paths.npmRoot, join(globalNodeModules, 'npm'), 'npm root is in the testdir') + t.equal(paths.pathNpm, join(globalBin, 'npm'), 'npm bin is in the testdir') + t.equal(paths.pathNpx, join(globalBin, 'npx'), 'npx bin is in the testdir') + t.ok(paths.nodeModulesContents.length > 1, 'node modules has npm contents') + t.ok(paths.nodeModulesContents.includes('node_modules'), 'npm has its node_modules') + + t.strictSame( + paths.binContents, + ['npm', 'npx'].flatMap(p => setup.WINDOWS ? [p, `${p}.cmd`, `${p}.ps1`] : p), + 'bin has npm and npx' + ) + + t.strictSame(await npmInstall(npmPath), paths) +}) diff --git a/tap-snapshots/test/lib/commands/audit.js.test.cjs b/tap-snapshots/test/lib/commands/audit.js.test.cjs index 4fec8f86c5baa..7611191688268 100644 --- a/tap-snapshots/test/lib/commands/audit.js.test.cjs +++ b/tap-snapshots/test/lib/commands/audit.js.test.cjs @@ -175,6 +175,20 @@ audited 1 package in xxx ` +exports[`test/lib/commands/audit.js TAP audit signatures third-party registry with sub-path (trailing slash) > must match snapshot 1`] = ` +audited 1 package in xxx + +1 package has a verified registry signature + +` + +exports[`test/lib/commands/audit.js TAP audit signatures third-party registry with sub-path > must match snapshot 1`] = ` +audited 1 package in xxx + +1 package has a verified registry signature + +` + exports[`test/lib/commands/audit.js TAP audit signatures with both invalid and missing signatures > must match snapshot 1`] = ` audited 2 packages in xxx @@ -230,6 +244,13 @@ Someone might have tampered with this package since it was published on the regi ` +exports[`test/lib/commands/audit.js TAP audit signatures with key fallback to legacy API > must match snapshot 1`] = ` +audited 1 package in xxx + +1 package has a verified registry signature + +` + exports[`test/lib/commands/audit.js TAP audit signatures with keys but missing signature > must match snapshot 1`] = ` audited 1 package in xxx diff --git a/tap-snapshots/test/lib/commands/config.js.test.cjs b/tap-snapshots/test/lib/commands/config.js.test.cjs index eee1dd569dc40..7c590b1cf3fb4 100644 --- a/tap-snapshots/test/lib/commands/config.js.test.cjs +++ b/tap-snapshots/test/lib/commands/config.js.test.cjs @@ -111,12 +111,14 @@ exports[`test/lib/commands/config.js TAP config list --json > output matches sna "package-lock-only": false, "pack-destination": ".", "parseable": false, + "prefer-dedupe": false, "prefer-offline": false, "prefer-online": false, "preid": "", "production": null, "progress": true, "provenance": false, + "provenance-file": null, "proxy": null, "read-only": false, "rebuild-bundle": true, @@ -159,6 +161,7 @@ exports[`test/lib/commands/config.js TAP config list --json > output matches sna "workspaces": null, "workspaces-update": true, "yes": null, + "npm-version": "{NPM-VERSION}", "metrics-registry": "https://registry.npmjs.org/" } ` @@ -254,6 +257,7 @@ message = "%s" metrics-registry = "https://registry.npmjs.org/" node-options = null noproxy = [""] +npm-version = "{NPM-VERSION}" offline = false omit = [] omit-lockfile-registry-resolved = false @@ -265,6 +269,7 @@ package = [] package-lock = true package-lock-only = false parseable = false +prefer-dedupe = false prefer-offline = false prefer-online = false ; prefix = "{REALGLOBALREFIX}" ; overridden by cli @@ -272,6 +277,7 @@ preid = "" production = null progress = true provenance = false +provenance-file = null proxy = null read-only = false rebuild-bundle = true @@ -337,6 +343,18 @@ userconfig = "{HOME}/.npmrc" ` exports[`test/lib/commands/config.js TAP config list > output matches snapshot 1`] = ` +; "global" config from {GLOBALPREFIX}/npmrc + +globalloaded = "yes" + +; "user" config from {HOME}/.npmrc + +userloaded = "yes" + +; "project" config from {LOCALPREFIX}/.npmrc + +projectloaded = "yes" + ; "cli" config from command line options cache = "{NPMDIR}/test/lib/commands/tap-testdir-config-config-list-sandbox/cache" @@ -379,6 +397,7 @@ global-prefix = "{LOCALPREFIX}" globalconfig = "{GLOBALPREFIX}/npmrc" init-module = "{HOME}/.npm-init.js" local-prefix = "{LOCALPREFIX}" +npm-version = "{NPM-VERSION}" ; prefix = "{LOCALPREFIX}" ; overridden by cli user-agent = "npm/{NPM-VERSION} node/{NODE-VERSION} {PLATFORM} {ARCH} workspaces/false" ; userconfig = "{HOME}/.npmrc" ; overridden by cli diff --git a/tap-snapshots/test/lib/commands/diff.js.test.cjs b/tap-snapshots/test/lib/commands/diff.js.test.cjs index 533b4f196e661..e87086d7d9b8f 100644 --- a/tap-snapshots/test/lib/commands/diff.js.test.cjs +++ b/tap-snapshots/test/lib/commands/diff.js.test.cjs @@ -33,7 +33,7 @@ index v0.1.0..v1.0.0 100644 +++ b/package.json @@ -1,4 +1,4 @@ { - "name": "foo", + "name": "@npmcli/foo", - "version": "0.1.0" + "version": "1.0.0" } diff --git a/tap-snapshots/test/lib/commands/doctor.js.test.cjs b/tap-snapshots/test/lib/commands/doctor.js.test.cjs index a9f58b8854569..0cf7133bdc4bf 100644 --- a/tap-snapshots/test/lib/commands/doctor.js.test.cjs +++ b/tap-snapshots/test/lib/commands/doctor.js.test.cjs @@ -53,35 +53,35 @@ Object { ` exports[`test/lib/commands/doctor.js TAP all clear > output 1`] = ` -Check  Value  Recommendation/Notes -npm ping  ok   -npm -v  ok  current: v1.0.0, latest: v1.0.0 -node -v  ok  current: v1.0.0, recommended: v1.0.0 -npm config get registry  ok  using default registry (https://registry.npmjs.org/) -git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/global/bin -Perms check on cached files  ok   -Perms check on local node_modules  ok   -Perms check on global node_modules ok   -Perms check on local bin folder  ok   -Perms check on global bin folder  ok   -Verify cache contents  ok  verified 0 tarballs +Check Value Recommendation/Notes +npm ping ok +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +git executable in PATH ok /path/to/git +global bin folder in PATH ok {CWD}/global/bin +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 0 tarballs ` exports[`test/lib/commands/doctor.js TAP all clear in color > everything is ok in color 1`] = ` -Check  Value  Recommendation/Notes -npm ping  ok   -npm -v  ok  current: v1.0.0, latest: v1.0.0 -node -v  ok  current: v1.0.0, recommended: v1.0.0 -npm config get registry  ok  using default registry (https://registry.npmjs.org/) -git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/global/bin -Perms check on cached files  ok   -Perms check on local node_modules  ok   -Perms check on global node_modules ok   -Perms check on local bin folder  ok   -Perms check on global bin folder  ok   -Verify cache contents  ok  verified 0 tarballs +Check Value Recommendation/Notes +npm ping ok +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +git executable in PATH ok /path/to/git +global bin folder in PATH ok {CWD}/global/bin +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 0 tarballs ` exports[`test/lib/commands/doctor.js TAP all clear in color > logs 1`] = ` @@ -179,35 +179,35 @@ Object { ` exports[`test/lib/commands/doctor.js TAP bad proxy > output 1`] = ` -Check  Value  Recommendation/Notes -npm ping  not ok unsupported proxy protocol: 'ssh:' -npm -v  not ok Error: unsupported proxy protocol: 'ssh:' -node -v  not ok Error: unsupported proxy protocol: 'ssh:' -npm config get registry  ok  using default registry (https://registry.npmjs.org/) -git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/global/bin -Perms check on cached files  ok   -Perms check on local node_modules  ok   -Perms check on global node_modules ok   -Perms check on local bin folder  ok   -Perms check on global bin folder  ok   -Verify cache contents  ok  verified 0 tarballs +Check Value Recommendation/Notes +npm ping not ok unsupported proxy protocol: 'ssh:' +npm -v not ok Error: unsupported proxy protocol: 'ssh:' +node -v not ok Error: unsupported proxy protocol: 'ssh:' +npm config get registry ok using default registry (https://registry.npmjs.org/) +git executable in PATH ok /path/to/git +global bin folder in PATH ok {CWD}/global/bin +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 0 tarballs ` exports[`test/lib/commands/doctor.js TAP cacache badContent > corrupted cache content 1`] = ` -Check  Value  Recommendation/Notes -npm ping  ok   -npm -v  ok  current: v1.0.0, latest: v1.0.0 -node -v  ok  current: v1.0.0, recommended: v1.0.0 -npm config get registry  ok  using default registry (https://registry.npmjs.org/) -git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/global/bin -Perms check on cached files  ok   -Perms check on local node_modules  ok   -Perms check on global node_modules ok   -Perms check on local bin folder  ok   -Perms check on global bin folder  ok   -Verify cache contents  ok  verified 2 tarballs +Check Value Recommendation/Notes +npm ping ok +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +git executable in PATH ok /path/to/git +global bin folder in PATH ok {CWD}/global/bin +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 2 tarballs ` exports[`test/lib/commands/doctor.js TAP cacache badContent > logs 1`] = ` @@ -323,35 +323,35 @@ Object { ` exports[`test/lib/commands/doctor.js TAP cacache missingContent > missing content 1`] = ` -Check  Value  Recommendation/Notes -npm ping  ok   -npm -v  ok  current: v1.0.0, latest: v1.0.0 -node -v  ok  current: v1.0.0, recommended: v1.0.0 -npm config get registry  ok  using default registry (https://registry.npmjs.org/) -git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/global/bin -Perms check on cached files  ok   -Perms check on local node_modules  ok   -Perms check on global node_modules ok   -Perms check on local bin folder  ok   -Perms check on global bin folder  ok   -Verify cache contents  ok  verified 2 tarballs +Check Value Recommendation/Notes +npm ping ok +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +git executable in PATH ok /path/to/git +global bin folder in PATH ok {CWD}/global/bin +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 2 tarballs ` exports[`test/lib/commands/doctor.js TAP cacache reclaimedCount > content garbage collected 1`] = ` -Check  Value  Recommendation/Notes -npm ping  ok   -npm -v  ok  current: v1.0.0, latest: v1.0.0 -node -v  ok  current: v1.0.0, recommended: v1.0.0 -npm config get registry  ok  using default registry (https://registry.npmjs.org/) -git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/global/bin -Perms check on cached files  ok   -Perms check on local node_modules  ok   -Perms check on global node_modules ok   -Perms check on local bin folder  ok   -Perms check on global bin folder  ok   -Verify cache contents  ok  verified 2 tarballs +Check Value Recommendation/Notes +npm ping ok +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +git executable in PATH ok /path/to/git +global bin folder in PATH ok {CWD}/global/bin +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 2 tarballs ` exports[`test/lib/commands/doctor.js TAP cacache reclaimedCount > logs 1`] = ` @@ -438,9 +438,9 @@ Object { ` exports[`test/lib/commands/doctor.js TAP discrete checks cache > output 1`] = ` -Check  Value  Recommendation/Notes -Perms check on cached files ok   -Verify cache contents  ok  verified 0 tarballs +Check Value Recommendation/Notes +Perms check on cached files ok +Verify cache contents ok verified 0 tarballs ` exports[`test/lib/commands/doctor.js TAP discrete checks git > logs 1`] = ` @@ -456,7 +456,7 @@ Object { ` exports[`test/lib/commands/doctor.js TAP discrete checks git > output 1`] = ` -Check Value  Recommendation/Notes +Check Value Recommendation/Notes ` exports[`test/lib/commands/doctor.js TAP discrete checks invalid environment > logs 1`] = ` @@ -480,9 +480,9 @@ Object { ` exports[`test/lib/commands/doctor.js TAP discrete checks invalid environment > output 1`] = ` -Check  Value  Recommendation/Notes -git executable in PATH  ok  /path/to/git -global bin folder in PATH not ok Error: Add {CWD}/global/bin to your $PATH +Check Value Recommendation/Notes +git executable in PATH ok /path/to/git +global bin folder in PATH not ok Error: Add {CWD}/global/bin to your $PATH ` exports[`test/lib/commands/doctor.js TAP discrete checks permissions - not windows > logs 1`] = ` @@ -498,12 +498,12 @@ Object { ` exports[`test/lib/commands/doctor.js TAP discrete checks permissions - not windows > output 1`] = ` -Check  Value  Recommendation/Notes -Perms check on cached files  ok   -Perms check on local node_modules  ok   -Perms check on global node_modules ok   -Perms check on local bin folder  ok   -Perms check on global bin folder  ok   +Check Value Recommendation/Notes +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok ` exports[`test/lib/commands/doctor.js TAP discrete checks permissions - windows > logs 1`] = ` @@ -519,7 +519,7 @@ Object { ` exports[`test/lib/commands/doctor.js TAP discrete checks permissions - windows > output 1`] = ` -Check Value  Recommendation/Notes +Check Value Recommendation/Notes ` exports[`test/lib/commands/doctor.js TAP discrete checks ping > logs 1`] = ` @@ -539,8 +539,8 @@ Object { ` exports[`test/lib/commands/doctor.js TAP discrete checks ping > output 1`] = ` -Check  Value  Recommendation/Notes -npm ping ok   +Check Value Recommendation/Notes +npm ping ok ` exports[`test/lib/commands/doctor.js TAP discrete checks registry > logs 1`] = ` @@ -560,9 +560,9 @@ Object { ` exports[`test/lib/commands/doctor.js TAP discrete checks registry > output 1`] = ` -Check  Value  Recommendation/Notes -npm ping  ok   -npm config get registry ok  using default registry (https://registry.npmjs.org/) +Check Value Recommendation/Notes +npm ping ok +npm config get registry ok using default registry (https://registry.npmjs.org/) ` exports[`test/lib/commands/doctor.js TAP discrete checks versions > logs 1`] = ` @@ -586,9 +586,9 @@ Object { ` exports[`test/lib/commands/doctor.js TAP discrete checks versions > output 1`] = ` -Check  Value  Recommendation/Notes -npm -v  ok  current: v1.0.0, latest: v1.0.0 -node -v ok  current: v1.0.0, recommended: v1.0.0 +Check Value Recommendation/Notes +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 ` exports[`test/lib/commands/doctor.js TAP error reading directory > logs 1`] = ` @@ -660,35 +660,35 @@ Object { ` exports[`test/lib/commands/doctor.js TAP error reading directory > readdir error 1`] = ` -Check  Value  Recommendation/Notes -npm ping  ok   -npm -v  ok  current: v1.0.0, latest: v1.0.0 -node -v  ok  current: v1.0.0, recommended: v1.0.0 -npm config get registry  ok  using default registry (https://registry.npmjs.org/) -git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/global/bin -Perms check on cached files  not ok Check the permissions of files in {CWD}/cache (should be owned by current user) -Perms check on local node_modules  not ok Check the permissions of files in {CWD}/prefix/node_modules (should be owned by current user) -Perms check on global node_modules not ok Check the permissions of files in {CWD}/global/node_modules -Perms check on local bin folder  not ok Check the permissions of files in {CWD}/prefix/node_modules/.bin -Perms check on global bin folder  not ok Check the permissions of files in {CWD}/global/bin -Verify cache contents  ok  verified 0 tarballs +Check Value Recommendation/Notes +npm ping ok +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +git executable in PATH ok /path/to/git +global bin folder in PATH ok {CWD}/global/bin +Perms check on cached files not ok Check the permissions of files in {CWD}/cache (should be owned by current user) +Perms check on local node_modules not ok Check the permissions of files in {CWD}/prefix/node_modules (should be owned by current user) +Perms check on global node_modules not ok Check the permissions of files in {CWD}/global/node_modules +Perms check on local bin folder not ok Check the permissions of files in {CWD}/prefix/node_modules/.bin +Perms check on global bin folder not ok Check the permissions of files in {CWD}/global/bin +Verify cache contents ok verified 0 tarballs ` exports[`test/lib/commands/doctor.js TAP incorrect owner > incorrect owner 1`] = ` -Check  Value  Recommendation/Notes -npm ping  ok   -npm -v  ok  current: v1.0.0, latest: v1.0.0 -node -v  ok  current: v1.0.0, recommended: v1.0.0 -npm config get registry  ok  using default registry (https://registry.npmjs.org/) -git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/global/bin -Perms check on cached files  not ok Check the permissions of files in {CWD}/cache (should be owned by current user) -Perms check on local node_modules  ok   -Perms check on global node_modules ok   -Perms check on local bin folder  ok   -Perms check on global bin folder  ok   -Verify cache contents  ok  verified 0 tarballs +Check Value Recommendation/Notes +npm ping ok +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +git executable in PATH ok /path/to/git +global bin folder in PATH ok {CWD}/global/bin +Perms check on cached files not ok Check the permissions of files in {CWD}/cache (should be owned by current user) +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 0 tarballs ` exports[`test/lib/commands/doctor.js TAP incorrect owner > logs 1`] = ` @@ -744,19 +744,19 @@ Object { ` exports[`test/lib/commands/doctor.js TAP incorrect permissions > incorrect owner 1`] = ` -Check  Value  Recommendation/Notes -npm ping  ok   -npm -v  ok  current: v1.0.0, latest: v1.0.0 -node -v  ok  current: v1.0.0, recommended: v1.0.0 -npm config get registry  ok  using default registry (https://registry.npmjs.org/) -git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/global/bin -Perms check on cached files  not ok Check the permissions of files in {CWD}/cache (should be owned by current user) -Perms check on local node_modules  not ok Check the permissions of files in {CWD}/prefix/node_modules (should be owned by current user) -Perms check on global node_modules not ok Check the permissions of files in {CWD}/global/node_modules -Perms check on local bin folder  not ok Check the permissions of files in {CWD}/prefix/node_modules/.bin -Perms check on global bin folder  not ok Check the permissions of files in {CWD}/global/bin -Verify cache contents  ok  verified 0 tarballs +Check Value Recommendation/Notes +npm ping ok +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +git executable in PATH ok /path/to/git +global bin folder in PATH ok {CWD}/global/bin +Perms check on cached files not ok Check the permissions of files in {CWD}/cache (should be owned by current user) +Perms check on local node_modules not ok Check the permissions of files in {CWD}/prefix/node_modules (should be owned by current user) +Perms check on global node_modules not ok Check the permissions of files in {CWD}/global/node_modules +Perms check on local bin folder not ok Check the permissions of files in {CWD}/prefix/node_modules/.bin +Perms check on global bin folder not ok Check the permissions of files in {CWD}/global/bin +Verify cache contents ok verified 0 tarballs ` exports[`test/lib/commands/doctor.js TAP incorrect permissions > logs 1`] = ` @@ -879,19 +879,19 @@ Object { ` exports[`test/lib/commands/doctor.js TAP missing git > missing git 1`] = ` -Check  Value  Recommendation/Notes -npm ping  ok   -npm -v  ok  current: v1.0.0, latest: v1.0.0 -node -v  ok  current: v1.0.0, recommended: v1.0.0 -npm config get registry  ok  using default registry (https://registry.npmjs.org/) -git executable in PATH  not ok Error: Install git and ensure it's in your PATH. -global bin folder in PATH  ok  {CWD}/global/bin -Perms check on cached files  ok   -Perms check on local node_modules  ok   -Perms check on global node_modules ok   -Perms check on local bin folder  ok   -Perms check on global bin folder  ok   -Verify cache contents  ok  verified 0 tarballs +Check Value Recommendation/Notes +npm ping ok +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +git executable in PATH not ok Error: Install git and ensure it's in your PATH. +global bin folder in PATH ok {CWD}/global/bin +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 0 tarballs ` exports[`test/lib/commands/doctor.js TAP missing global directories > logs 1`] = ` @@ -951,19 +951,19 @@ Object { ` exports[`test/lib/commands/doctor.js TAP missing global directories > missing global directories 1`] = ` -Check  Value  Recommendation/Notes -npm ping  ok   -npm -v  ok  current: v1.0.0, latest: v1.0.0 -node -v  ok  current: v1.0.0, recommended: v1.0.0 -npm config get registry  ok  using default registry (https://registry.npmjs.org/) -git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/global/bin -Perms check on cached files  ok   -Perms check on local node_modules  ok   -Perms check on global node_modules not ok Check the permissions of files in {CWD}/global/node_modules -Perms check on local bin folder  ok   -Perms check on global bin folder  not ok Check the permissions of files in {CWD}/global/bin -Verify cache contents  ok  verified 0 tarballs +Check Value Recommendation/Notes +npm ping ok +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +git executable in PATH ok /path/to/git +global bin folder in PATH ok {CWD}/global/bin +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules not ok Check the permissions of files in {CWD}/global/node_modules +Perms check on local bin folder ok +Perms check on global bin folder not ok Check the permissions of files in {CWD}/global/bin +Verify cache contents ok verified 0 tarballs ` exports[`test/lib/commands/doctor.js TAP missing local node_modules > logs 1`] = ` @@ -1014,19 +1014,19 @@ Object { ` exports[`test/lib/commands/doctor.js TAP missing local node_modules > missing local node_modules 1`] = ` -Check  Value  Recommendation/Notes -npm ping  ok   -npm -v  ok  current: v1.0.0, latest: v1.0.0 -node -v  ok  current: v1.0.0, recommended: v1.0.0 -npm config get registry  ok  using default registry (https://registry.npmjs.org/) -git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/global/bin -Perms check on cached files  ok   -Perms check on local node_modules  ok   -Perms check on global node_modules ok   -Perms check on local bin folder  ok   -Perms check on global bin folder  ok   -Verify cache contents  ok  verified 0 tarballs +Check Value Recommendation/Notes +npm ping ok +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +git executable in PATH ok /path/to/git +global bin folder in PATH ok {CWD}/global/bin +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 0 tarballs ` exports[`test/lib/commands/doctor.js TAP node out of date - current > logs 1`] = ` @@ -1077,19 +1077,19 @@ Object { ` exports[`test/lib/commands/doctor.js TAP node out of date - current > node is out of date 1`] = ` -Check  Value  Recommendation/Notes -npm ping  ok   -npm -v  ok  current: v1.0.0, latest: v1.0.0 -node -v  not ok Use node v2.0.1 (current: v2.0.0) -npm config get registry  ok  using default registry (https://registry.npmjs.org/) -git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/global/bin -Perms check on cached files  ok   -Perms check on local node_modules  ok   -Perms check on global node_modules ok   -Perms check on local bin folder  ok   -Perms check on global bin folder  ok   -Verify cache contents  ok  verified 0 tarballs +Check Value Recommendation/Notes +npm ping ok +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v not ok Use node v2.0.1 (current: v2.0.0) +npm config get registry ok using default registry (https://registry.npmjs.org/) +git executable in PATH ok /path/to/git +global bin folder in PATH ok {CWD}/global/bin +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 0 tarballs ` exports[`test/lib/commands/doctor.js TAP node out of date - lts > logs 1`] = ` @@ -1140,19 +1140,19 @@ Object { ` exports[`test/lib/commands/doctor.js TAP node out of date - lts > node is out of date 1`] = ` -Check  Value  Recommendation/Notes -npm ping  ok   -npm -v  ok  current: v1.0.0, latest: v1.0.0 -node -v  not ok Use node v1.0.0 (current: v0.0.1) -npm config get registry  ok  using default registry (https://registry.npmjs.org/) -git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/global/bin -Perms check on cached files  ok   -Perms check on local node_modules  ok   -Perms check on global node_modules ok   -Perms check on local bin folder  ok   -Perms check on global bin folder  ok   -Verify cache contents  ok  verified 0 tarballs +Check Value Recommendation/Notes +npm ping ok +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v not ok Use node v1.0.0 (current: v0.0.1) +npm config get registry ok using default registry (https://registry.npmjs.org/) +git executable in PATH ok /path/to/git +global bin folder in PATH ok {CWD}/global/bin +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 0 tarballs ` exports[`test/lib/commands/doctor.js TAP non-default registry > logs 1`] = ` @@ -1203,19 +1203,19 @@ Object { ` exports[`test/lib/commands/doctor.js TAP non-default registry > non default registry 1`] = ` -Check  Value  Recommendation/Notes -npm ping  ok   -npm -v  ok  current: v1.0.0, latest: v1.0.0 -node -v  ok  current: v1.0.0, recommended: v1.0.0 -npm config get registry  not ok Try \`npm config set registry=https://registry.npmjs.org/\` -git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/global/bin -Perms check on cached files  ok   -Perms check on local node_modules  ok   -Perms check on global node_modules ok   -Perms check on local bin folder  ok   -Perms check on global bin folder  ok   -Verify cache contents  ok  verified 0 tarballs +Check Value Recommendation/Notes +npm ping ok +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry not ok Try \`npm config set registry=https://registry.npmjs.org/\` +git executable in PATH ok /path/to/git +global bin folder in PATH ok {CWD}/global/bin +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 0 tarballs ` exports[`test/lib/commands/doctor.js TAP npm out of date > logs 1`] = ` @@ -1266,19 +1266,19 @@ Object { ` exports[`test/lib/commands/doctor.js TAP npm out of date > npm is out of date 1`] = ` -Check  Value  Recommendation/Notes -npm ping  ok   -npm -v  not ok Use npm v2.0.0 -node -v  ok  current: v1.0.0, recommended: v1.0.0 -npm config get registry  ok  using default registry (https://registry.npmjs.org/) -git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/global/bin -Perms check on cached files  ok   -Perms check on local node_modules  ok   -Perms check on global node_modules ok   -Perms check on local bin folder  ok   -Perms check on global bin folder  ok   -Verify cache contents  ok  verified 0 tarballs +Check Value Recommendation/Notes +npm ping ok +npm -v not ok Use npm v2.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +git executable in PATH ok /path/to/git +global bin folder in PATH ok {CWD}/global/bin +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 0 tarballs ` exports[`test/lib/commands/doctor.js TAP ping 404 > logs 1`] = ` @@ -1329,19 +1329,19 @@ Object { ` exports[`test/lib/commands/doctor.js TAP ping 404 > ping 404 1`] = ` -Check  Value  Recommendation/Notes -npm ping  not ok 404 404 Not Found - GET https://registry.npmjs.org/-/ping?write=true -npm -v  ok  current: v1.0.0, latest: v1.0.0 -node -v  ok  current: v1.0.0, recommended: v1.0.0 -npm config get registry  ok  using default registry (https://registry.npmjs.org/) -git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/global/bin -Perms check on cached files  ok   -Perms check on local node_modules  ok   -Perms check on global node_modules ok   -Perms check on local bin folder  ok   -Perms check on global bin folder  ok   -Verify cache contents  ok  verified 0 tarballs +Check Value Recommendation/Notes +npm ping not ok 404 404 Not Found - GET https://registry.npmjs.org/-/ping?write=true +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +git executable in PATH ok /path/to/git +global bin folder in PATH ok {CWD}/global/bin +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 0 tarballs ` exports[`test/lib/commands/doctor.js TAP ping 404 in color > logs 1`] = ` @@ -1392,19 +1392,19 @@ Object { ` exports[`test/lib/commands/doctor.js TAP ping 404 in color > ping 404 in color 1`] = ` -Check  Value  Recommendation/Notes -npm ping  not ok 404 404 Not Found - GET https://registry.npmjs.org/-/ping?write=true -npm -v  ok  current: v1.0.0, latest: v1.0.0 -node -v  ok  current: v1.0.0, recommended: v1.0.0 -npm config get registry  ok  using default registry (https://registry.npmjs.org/) -git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/global/bin -Perms check on cached files  ok   -Perms check on local node_modules  ok   -Perms check on global node_modules ok   -Perms check on local bin folder  ok   -Perms check on global bin folder  ok   -Verify cache contents  ok  verified 0 tarballs +Check Value Recommendation/Notes +npm ping not ok 404 404 Not Found - GET https://registry.npmjs.org/-/ping?write=true +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +git executable in PATH ok /path/to/git +global bin folder in PATH ok {CWD}/global/bin +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 0 tarballs ` exports[`test/lib/commands/doctor.js TAP ping exception with code > logs 1`] = ` @@ -1455,19 +1455,19 @@ Object { ` exports[`test/lib/commands/doctor.js TAP ping exception with code > ping failure 1`] = ` -Check  Value  Recommendation/Notes -npm ping  not ok request to https://registry.npmjs.org/-/ping?write=true failed, reason: Test Error -npm -v  ok  current: v1.0.0, latest: v1.0.0 -node -v  ok  current: v1.0.0, recommended: v1.0.0 -npm config get registry  ok  using default registry (https://registry.npmjs.org/) -git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/global/bin -Perms check on cached files  ok   -Perms check on local node_modules  ok   -Perms check on global node_modules ok   -Perms check on local bin folder  ok   -Perms check on global bin folder  ok   -Verify cache contents  ok  verified 0 tarballs +Check Value Recommendation/Notes +npm ping not ok request to https://registry.npmjs.org/-/ping?write=true failed, reason: Test Error +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +git executable in PATH ok /path/to/git +global bin folder in PATH ok {CWD}/global/bin +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 0 tarballs ` exports[`test/lib/commands/doctor.js TAP ping exception without code > logs 1`] = ` @@ -1518,19 +1518,19 @@ Object { ` exports[`test/lib/commands/doctor.js TAP ping exception without code > ping failure 1`] = ` -Check  Value  Recommendation/Notes -npm ping  not ok request to https://registry.npmjs.org/-/ping?write=true failed, reason: Test Error -npm -v  ok  current: v1.0.0, latest: v1.0.0 -node -v  ok  current: v1.0.0, recommended: v1.0.0 -npm config get registry  ok  using default registry (https://registry.npmjs.org/) -git executable in PATH  ok  /path/to/git -global bin folder in PATH  ok  {CWD}/global/bin -Perms check on cached files  ok   -Perms check on local node_modules  ok   -Perms check on global node_modules ok   -Perms check on local bin folder  ok   -Perms check on global bin folder  ok   -Verify cache contents  ok  verified 0 tarballs +Check Value Recommendation/Notes +npm ping not ok request to https://registry.npmjs.org/-/ping?write=true failed, reason: Test Error +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +git executable in PATH ok /path/to/git +global bin folder in PATH ok {CWD}/global/bin +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 0 tarballs ` exports[`test/lib/commands/doctor.js TAP silent errors > logs 1`] = ` @@ -1637,11 +1637,11 @@ Object { ` exports[`test/lib/commands/doctor.js TAP windows skips permissions checks > no permissions checks 1`] = ` -Check  Value  Recommendation/Notes -npm ping  ok   -npm -v  ok  current: v1.0.0, latest: v1.0.0 -node -v  ok  current: v1.0.0, recommended: v1.0.0 -npm config get registry  ok  using default registry (https://registry.npmjs.org/) -git executable in PATH  ok  /path/to/git -global bin folder in PATH ok  {CWD}/global +Check Value Recommendation/Notes +npm ping ok +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +git executable in PATH ok /path/to/git +global bin folder in PATH ok {CWD}/global ` diff --git a/tap-snapshots/test/lib/commands/publish.js.test.cjs b/tap-snapshots/test/lib/commands/publish.js.test.cjs index fd9fd74624070..f421a2dbd8add 100644 --- a/tap-snapshots/test/lib/commands/publish.js.test.cjs +++ b/tap-snapshots/test/lib/commands/publish.js.test.cjs @@ -99,6 +99,146 @@ exports[`test/lib/commands/publish.js TAP json > new package json 1`] = ` } ` +exports[`test/lib/commands/publish.js TAP manifest > manifest 1`] = ` +Object { + "_id": "npm@{VERSION}", + "author": Object { + "name": "GitHub Inc.", + }, + "bin": Object { + "npm": "bin/npm-cli.js", + "npx": "bin/npx-cli.js", + }, + "bugs": Object { + "url": "https://github.com/npm/cli/issues", + }, + "description": "a package manager for JavaScript", + "directories": Object { + "doc": "./doc", + "man": "./man", + }, + "exports": Object { + ".": Array [ + Object { + "default": "./index.js", + }, + "./index.js", + ], + "./package.json": "./package.json", + }, + "files": Array [ + "bin/", + "lib/", + "index.js", + "docs/content/", + "docs/output/", + "man/", + ], + "homepage": "https://docs.npmjs.com/", + "keywords": Array [ + "install", + "modules", + "package manager", + "package.json", + ], + "license": "Artistic-2.0", + "main": "./index.js", + "man": Array [ + "man/man1/npm-access.1", + "man/man1/npm-adduser.1", + "man/man1/npm-audit.1", + "man/man1/npm-bugs.1", + "man/man1/npm-cache.1", + "man/man1/npm-ci.1", + "man/man1/npm-completion.1", + "man/man1/npm-config.1", + "man/man1/npm-dedupe.1", + "man/man1/npm-deprecate.1", + "man/man1/npm-diff.1", + "man/man1/npm-dist-tag.1", + "man/man1/npm-docs.1", + "man/man1/npm-doctor.1", + "man/man1/npm-edit.1", + "man/man1/npm-exec.1", + "man/man1/npm-explain.1", + "man/man1/npm-explore.1", + "man/man1/npm-find-dupes.1", + "man/man1/npm-fund.1", + "man/man1/npm-help-search.1", + "man/man1/npm-help.1", + "man/man1/npm-hook.1", + "man/man1/npm-init.1", + "man/man1/npm-install-ci-test.1", + "man/man1/npm-install-test.1", + "man/man1/npm-install.1", + "man/man1/npm-link.1", + "man/man1/npm-login.1", + "man/man1/npm-logout.1", + "man/man1/npm-ls.1", + "man/man1/npm-org.1", + "man/man1/npm-outdated.1", + "man/man1/npm-owner.1", + "man/man1/npm-pack.1", + "man/man1/npm-ping.1", + "man/man1/npm-pkg.1", + "man/man1/npm-prefix.1", + "man/man1/npm-profile.1", + "man/man1/npm-prune.1", + "man/man1/npm-publish.1", + "man/man1/npm-query.1", + "man/man1/npm-rebuild.1", + "man/man1/npm-repo.1", + "man/man1/npm-restart.1", + "man/man1/npm-root.1", + "man/man1/npm-run-script.1", + "man/man1/npm-search.1", + "man/man1/npm-shrinkwrap.1", + "man/man1/npm-star.1", + "man/man1/npm-stars.1", + "man/man1/npm-start.1", + "man/man1/npm-stop.1", + "man/man1/npm-team.1", + "man/man1/npm-test.1", + "man/man1/npm-token.1", + "man/man1/npm-uninstall.1", + "man/man1/npm-unpublish.1", + "man/man1/npm-unstar.1", + "man/man1/npm-update.1", + "man/man1/npm-version.1", + "man/man1/npm-view.1", + "man/man1/npm-whoami.1", + "man/man1/npm.1", + "man/man1/npx.1", + "man/man5/folders.5", + "man/man5/install.5", + "man/man5/npm-global.5", + "man/man5/npm-json.5", + "man/man5/npm-shrinkwrap-json.5", + "man/man5/npmrc.5", + "man/man5/package-json.5", + "man/man5/package-lock-json.5", + "man/man7/config.7", + "man/man7/dependency-selectors.7", + "man/man7/developers.7", + "man/man7/logging.7", + "man/man7/orgs.7", + "man/man7/package-spec.7", + "man/man7/registry.7", + "man/man7/removal.7", + "man/man7/scope.7", + "man/man7/scripts.7", + "man/man7/workspaces.7", + ], + "name": "npm", + "readmeFilename": "README.md", + "repository": Object { + "type": "git", + "url": "git+https://github.com/npm/cli.git", + }, + "version": "{VERSION}", +} +` + exports[`test/lib/commands/publish.js TAP no auth dry-run > must match snapshot 1`] = ` + test-package@1.0.0 ` diff --git a/tap-snapshots/test/lib/docs.js.test.cjs b/tap-snapshots/test/lib/docs.js.test.cjs index a6dc3d3189ac8..d89d5840b7825 100644 --- a/tap-snapshots/test/lib/docs.js.test.cjs +++ b/tap-snapshots/test/lib/docs.js.test.cjs @@ -24,7 +24,7 @@ All commands: Specify configs in the ini-formatted file: - /some/config/file/.npmrc + {USERCONFIG} or on the command line via: npm --key=value More configuration info: npm help config @@ -165,6 +165,10 @@ Array [ ] ` +exports[`test/lib/docs.js TAP command list > deref 1`] = ` +Function deref(c) +` + exports[`test/lib/docs.js TAP config > all definitions 1`] = ` #### \`_auth\` @@ -179,6 +183,8 @@ Warning: This should generally not be set via a command-line option. It is safer to use a registry-provided authentication bearer token stored in the ~/.npmrc file by running \`npm login\`. + + #### \`access\` * Default: 'public' for new packages, existing packages it will not change the @@ -195,6 +201,8 @@ packages. Specifying a value of \`restricted\` or \`public\` during publish will change the access for an existing package the same way that \`npm access set status\` would. + + #### \`all\` * Default: false @@ -204,6 +212,8 @@ When running \`npm outdated\` and \`npm ls\`, setting \`--all\` will show all outdated or installed packages, rather than only those directly depended upon by the current project. + + #### \`allow-same-version\` * Default: false @@ -212,6 +222,8 @@ upon by the current project. Prevents throwing an error when \`npm version\` is used to set the new version to the same value as the current version. + + #### \`audit\` * Default: true @@ -222,6 +234,8 @@ default registry and all registries configured for scopes. See the documentation for [\`npm audit\`](/commands/npm-audit) for details on what is submitted. + + #### \`audit-level\` * Default: null @@ -230,6 +244,8 @@ submitted. The minimum level of vulnerability for \`npm audit\` to exit with a non-zero exit code. + + #### \`auth-type\` * Default: "web" @@ -238,6 +254,8 @@ exit code. What authentication strategy to use with \`login\`. Note that if an \`otp\` config is given, this value will always be set to \`legacy\`. + + #### \`before\` * Default: null @@ -253,6 +271,8 @@ If the requested version is a \`dist-tag\` and the given tag does not pass the will be used. For example, \`foo@latest\` might install \`foo@1.2\` even though \`latest\` is \`2.0\`. + + #### \`bin-links\` * Default: true @@ -265,6 +285,8 @@ Set to false to have it not do this. This can be used to work around the fact that some file systems don't support symlinks, even on ostensibly Unix systems. + + #### \`browser\` * Default: OS X: \`"open"\`, Windows: \`"start"\`, Others: \`"xdg-open"\` @@ -277,6 +299,8 @@ terminal. Set to \`true\` to use default system URL opener. + + #### \`ca\` * Default: null @@ -303,6 +327,8 @@ ca[]="..." See also the \`strict-ssl\` config. + + #### \`cache\` * Default: Windows: \`%LocalAppData%\\npm-cache\`, Posix: \`~/.npm\` @@ -310,6 +336,8 @@ See also the \`strict-ssl\` config. The location of npm's cache directory. + + #### \`cafile\` * Default: null @@ -319,6 +347,8 @@ A path to a file containing one or multiple Certificate Authority signing certificates. Similar to the \`ca\` setting, but allows for multiple CA's, as well as for the CA information to be stored in a file on disk. + + #### \`call\` * Default: "" @@ -332,15 +362,6 @@ npm exec --package yo --package generator-node --call "yo node" \`\`\` -#### \`ci-name\` - -* Default: The name of the current CI system, or \`null\` when not on a known CI - platform. -* Type: null or String - -The name of a continuous integration system. If not set explicitly, npm will -detect the current CI environment using the -[\`ci-info\`](http://npm.im/ci-info) module. #### \`cidr\` @@ -350,6 +371,8 @@ detect the current CI environment using the This is a list of CIDR address to be used when configuring limited access tokens with the \`npm token create\` command. + + #### \`color\` * Default: true unless the NO_COLOR environ is set to something other than '0' @@ -358,6 +381,8 @@ tokens with the \`npm token create\` command. If false, never shows colors. If \`"always"\` then always shows colors. If true, then only prints color codes for tty file descriptors. + + #### \`commit-hooks\` * Default: true @@ -365,6 +390,8 @@ true, then only prints color codes for tty file descriptors. Run git commit hooks when using the \`npm version\` command. + + #### \`depth\` * Default: \`Infinity\` if \`--all\` is set, otherwise \`1\` @@ -375,6 +402,8 @@ The depth to go when recursing packages for \`npm ls\`. If not set, \`npm ls\` will show only the immediate dependencies of the root project. If \`--all\` is set, then npm will show all dependencies by default. + + #### \`description\` * Default: true @@ -382,6 +411,8 @@ project. If \`--all\` is set, then npm will show all dependencies by default. Show the description in \`npm search\` + + #### \`diff\` * Default: @@ -389,6 +420,8 @@ Show the description in \`npm search\` Define arguments to compare in \`npm diff\`. + + #### \`diff-dst-prefix\` * Default: "b/" @@ -396,6 +429,8 @@ Define arguments to compare in \`npm diff\`. Destination prefix to be used in \`npm diff\` output. + + #### \`diff-ignore-all-space\` * Default: false @@ -403,6 +438,8 @@ Destination prefix to be used in \`npm diff\` output. Ignore whitespace when comparing lines in \`npm diff\`. + + #### \`diff-name-only\` * Default: false @@ -410,6 +447,8 @@ Ignore whitespace when comparing lines in \`npm diff\`. Prints only filenames when using \`npm diff\`. + + #### \`diff-no-prefix\` * Default: false @@ -420,6 +459,8 @@ Do not show any source or destination prefix in \`npm diff\` output. Note: this causes \`npm diff\` to ignore the \`--diff-src-prefix\` and \`--diff-dst-prefix\` configs. + + #### \`diff-src-prefix\` * Default: "a/" @@ -427,6 +468,8 @@ Note: this causes \`npm diff\` to ignore the \`--diff-src-prefix\` and Source prefix to be used in \`npm diff\` output. + + #### \`diff-text\` * Default: false @@ -434,6 +477,8 @@ Source prefix to be used in \`npm diff\` output. Treat all files as text in \`npm diff\`. + + #### \`diff-unified\` * Default: 3 @@ -441,6 +486,8 @@ Treat all files as text in \`npm diff\`. The number of lines of context to print in \`npm diff\`. + + #### \`dry-run\` * Default: false @@ -454,6 +501,8 @@ commands that modify your local installation, eg, \`install\`, \`update\`, Note: This is NOT honored by other network related commands, eg \`dist-tags\`, \`owner\`, etc. + + #### \`editor\` * Default: The EDITOR or VISUAL environment variables, or @@ -462,6 +511,8 @@ Note: This is NOT honored by other network related commands, eg \`dist-tags\`, The command to run for \`npm edit\` and \`npm config edit\`. + + #### \`engine-strict\` * Default: false @@ -473,6 +524,8 @@ Node.js version. This can be overridden by setting the \`--force\` flag. + + #### \`fetch-retries\` * Default: 2 @@ -484,6 +537,8 @@ from the registry. npm will retry idempotent read requests to the registry in the case of network failures or 5xx HTTP errors. + + #### \`fetch-retry-factor\` * Default: 10 @@ -491,6 +546,8 @@ network failures or 5xx HTTP errors. The "factor" config for the \`retry\` module to use when fetching packages. + + #### \`fetch-retry-maxtimeout\` * Default: 60000 (1 minute) @@ -499,6 +556,8 @@ The "factor" config for the \`retry\` module to use when fetching packages. The "maxTimeout" config for the \`retry\` module to use when fetching packages. + + #### \`fetch-retry-mintimeout\` * Default: 10000 (10 seconds) @@ -507,6 +566,8 @@ packages. The "minTimeout" config for the \`retry\` module to use when fetching packages. + + #### \`fetch-timeout\` * Default: 300000 (5 minutes) @@ -514,6 +575,8 @@ packages. The maximum amount of time to wait for HTTP requests to complete. + + #### \`force\` * Default: false @@ -540,6 +603,8 @@ mistakes, unnecessary performance degradation, and malicious input. If you don't have a clear idea of what you want to do, it is strongly recommended that you do not use this option! + + #### \`foreground-scripts\` * Default: false @@ -552,6 +617,8 @@ input, output, and error with the main npm process. Note that this will generally make installs run slower, and be much noisier, but can be useful for debugging. + + #### \`format-package-lock\` * Default: true @@ -560,6 +627,8 @@ but can be useful for debugging. Format \`package-lock.json\` or \`npm-shrinkwrap.json\` as a human readable file. + + #### \`fund\` * Default: true @@ -569,6 +638,8 @@ When "true" displays the message at the end of each \`npm install\` acknowledging the number of dependencies looking for funding. See [\`npm fund\`](/commands/npm-fund) for details. + + #### \`git\` * Default: "git" @@ -577,6 +648,8 @@ fund\`](/commands/npm-fund) for details. The command to use for git commands. If git is installed on the computer, but is not in the \`PATH\`, then set this to the full path to the git binary. + + #### \`git-tag-version\` * Default: true @@ -585,6 +658,8 @@ but is not in the \`PATH\`, then set this to the full path to the git binary. Tag the commit when using the \`npm version\` command. Setting this to false results in no commit being made at all. + + #### \`global\` * Default: false @@ -599,6 +674,8 @@ folder instead of the current working directory. See * bin files are linked to \`{prefix}/bin\` * man pages are linked to \`{prefix}/share/man\` + + #### \`globalconfig\` * Default: The global --prefix setting plus 'etc/npmrc'. For example, @@ -607,6 +684,8 @@ folder instead of the current working directory. See The config file to read for global config options. + + #### \`heading\` * Default: "npm" @@ -614,6 +693,8 @@ The config file to read for global config options. The string that starts all the debugging log output. + + #### \`https-proxy\` * Default: null @@ -624,6 +705,8 @@ A proxy to use for outgoing https requests. If the \`HTTPS_PROXY\` or proxy settings will be honored by the underlying \`make-fetch-happen\` library. + + #### \`if-present\` * Default: false @@ -650,6 +733,8 @@ Note that commands explicitly intended to run a particular script, such as will still run their intended script if \`ignore-scripts\` is set, but they will *not* run any pre- or post-scripts. + + #### \`include\` * Default: @@ -662,6 +747,8 @@ This is the inverse of \`--omit=\`. Dependency types specified in \`--include\` will not be omitted, regardless of the order in which omit/include are specified on the command-line. + + #### \`include-staged\` * Default: false @@ -672,6 +759,8 @@ Allow installing "staged" published packages, as defined by [npm RFC PR This is experimental, and not implemented by the npm public registry. + + #### \`include-workspace-root\` * Default: false @@ -692,6 +781,8 @@ This value is not exported to the environment for child processes. The value \`npm init\` should use by default for the package author's email. + + #### \`init-author-name\` * Default: "" @@ -699,6 +790,8 @@ The value \`npm init\` should use by default for the package author's email. The value \`npm init\` should use by default for the package author's name. + + #### \`init-author-url\` * Default: "" @@ -707,6 +800,8 @@ The value \`npm init\` should use by default for the package author's name. The value \`npm init\` should use by default for the package author's homepage. + + #### \`init-license\` * Default: "ISC" @@ -714,6 +809,8 @@ homepage. The value \`npm init\` should use by default for the package license. + + #### \`init-module\` * Default: "~/.npm-init.js" @@ -724,6 +821,8 @@ documentation for the [init-package-json](https://github.com/npm/init-package-json) module for more information, or [npm init](/commands/npm-init). + + #### \`init-version\` * Default: "1.0.0" @@ -732,6 +831,8 @@ more information, or [npm init](/commands/npm-init). The value that \`npm init\` should use by default for the package version number, if not already set in package.json. + + #### \`install-links\` * Default: false @@ -741,6 +842,8 @@ When set file: protocol dependencies will be packed and installed as regular dependencies instead of creating a symlink. This option has no effect on workspaces. + + #### \`install-strategy\` * Default: "hoisted" @@ -753,6 +856,8 @@ place, no hoisting. shallow (formerly --global-style) only install direct deps at top-level. linked: (experimental) install in node_modules/.store, link in place, unhoisted. + + #### \`json\` * Default: false @@ -765,6 +870,8 @@ Whether or not to output JSON data, rather than the normal output. Not supported by all npm commands. + + #### \`legacy-peer-deps\` * Default: false @@ -783,6 +890,8 @@ This differs from \`--omit=peer\`, in that \`--omit=peer\` will avoid unpacking Use of \`legacy-peer-deps\` is not recommended, as it will not enforce the \`peerDependencies\` contract that meta-dependencies may rely on. + + #### \`link\` * Default: false @@ -790,6 +899,8 @@ Use of \`legacy-peer-deps\` is not recommended, as it will not enforce the Used with \`npm ls\`, limiting output to only those packages that are linked. + + #### \`local-address\` * Default: null @@ -798,6 +909,8 @@ Used with \`npm ls\`, limiting output to only those packages that are linked. The IP address of the local interface to use when making connections to the npm registry. Must be IPv4 in versions of Node prior to 0.12. + + #### \`location\` * Default: "user" unless \`--global\` is passed, which will also set this value @@ -815,6 +928,8 @@ instead of the current working directory. See * bin files are linked to \`{prefix}/bin\` * man pages are linked to \`{prefix}/share/man\` + + #### \`lockfile-version\` * Default: Version 3 if no lockfile, auto-converting v1 lockfiles to v3, @@ -837,6 +952,8 @@ determinism and interoperability, at the expense of more bytes on disk. disk than lockfile version 2, but not interoperable with older npm versions. Ideal if all users are on npm version 7 and higher. + + #### \`loglevel\` * Default: "notice" @@ -851,6 +968,8 @@ Any logs of a higher level than the setting are shown. The default is See also the \`foreground-scripts\` config. + + #### \`logs-dir\` * Default: A directory named \`_logs\` inside the cache @@ -859,6 +978,8 @@ See also the \`foreground-scripts\` config. The location of npm's log directory. See [\`npm logging\`](/using-npm/logging) for more information. + + #### \`logs-max\` * Default: 10 @@ -868,6 +989,8 @@ The maximum number of log files to store. If set to 0, no log files will be written for the current run. + + #### \`long\` * Default: false @@ -875,6 +998,8 @@ If set to 0, no log files will be written for the current run. Show extended information in \`ls\`, \`search\`, and \`help-search\`. + + #### \`maxsockets\` * Default: 15 @@ -883,6 +1008,8 @@ Show extended information in \`ls\`, \`search\`, and \`help-search\`. The maximum number of connections to use per origin (protocol/host/port combination). + + #### \`message\` * Default: "%s" @@ -892,6 +1019,8 @@ Commit message which is used by \`npm version\` when creating version commit. Any "%s" in the message will be replaced with the version number. + + #### \`node-options\` * Default: null @@ -901,6 +1030,8 @@ Options to pass through to Node.js via the \`NODE_OPTIONS\` environment variable. This does not impact how npm itself is executed but it does impact how lifecycle scripts are called. + + #### \`noproxy\` * Default: The value of the NO_PROXY environment variable @@ -910,6 +1041,8 @@ Domain extensions that should bypass any proxies. Also accepts a comma-delimited string. + + #### \`offline\` * Default: false @@ -918,6 +1051,8 @@ Also accepts a comma-delimited string. Force offline mode: no network requests will be done during install. To allow the CLI to fill in missing cache data, see \`--prefer-offline\`. + + #### \`omit\` * Default: 'dev' if the \`NODE_ENV\` environment variable is set to @@ -936,6 +1071,8 @@ it will be included. If the resulting omit list includes \`'dev'\`, then the \`NODE_ENV\` environment variable will be set to \`'production'\` for all lifecycle scripts. + + #### \`omit-lockfile-registry-resolved\` * Default: false @@ -946,6 +1083,8 @@ registry dependencies. Subsequent installs will need to resolve tarball endpoints with the configured registry, likely resulting in a longer install time. + + #### \`otp\` * Default: null @@ -957,6 +1096,8 @@ when publishing or changing package permissions with \`npm access\`. If not set, and a registry response fails with a challenge for a one-time password, npm will prompt on the command line for one. + + #### \`pack-destination\` * Default: "." @@ -964,6 +1105,8 @@ password, npm will prompt on the command line for one. Directory in which \`npm pack\` will save tarballs. + + #### \`package\` * Default: @@ -971,6 +1114,8 @@ Directory in which \`npm pack\` will save tarballs. The package or packages to install for [\`npm exec\`](/commands/npm-exec) + + #### \`package-lock\` * Default: true @@ -979,7 +1124,7 @@ The package or packages to install for [\`npm exec\`](/commands/npm-exec) If set to false, then ignore \`package-lock.json\` files when installing. This will also prevent _writing_ \`package-lock.json\` if \`save\` is true. -This configuration does not affect \`npm ci\`. + #### \`package-lock-only\` @@ -995,6 +1140,8 @@ instead of checking \`node_modules\` and downloading dependencies. For \`list\` this means the output will be based on the tree described by the \`package-lock.json\`, rather than the contents of \`node_modules\`. + + #### \`parseable\` * Default: false @@ -1003,6 +1150,18 @@ For \`list\` this means the output will be based on the tree described by the Output parseable results from commands that write to standard output. For \`npm search\`, this will be tab-separated table format. + + +#### \`prefer-dedupe\` + +* Default: false +* Type: Boolean + +Prefer to deduplicate packages if possible, rather than choosing a newer +version of a dependency. + + + #### \`prefer-offline\` * Default: false @@ -1012,6 +1171,8 @@ If true, staleness checks for cached data will be bypassed, but missing data will be requested from the server. To force full offline mode, use \`--offline\`. + + #### \`prefer-online\` * Default: false @@ -1020,6 +1181,8 @@ will be requested from the server. To force full offline mode, use If true, staleness checks for cached data will be forced, making the CLI look for updates immediately even for fresh package data. + + #### \`prefix\` * Default: In global mode, the folder where the node executable is installed. @@ -1030,6 +1193,8 @@ look for updates immediately even for fresh package data. The location to install global items. If set on the command line, then it forces non-global commands to run in the specified folder. + + #### \`preid\` * Default: "" @@ -1038,6 +1203,8 @@ forces non-global commands to run in the specified folder. The "prerelease identifier" to use as a prefix for the "prerelease" part of a semver. Like the \`rc\` in \`1.2.0-rc.8\`. + + #### \`progress\` * Default: \`true\` unless running in a known CI system @@ -1048,6 +1215,8 @@ operations, if \`process.stderr\` is a TTY. Set to \`false\` to suppress the progress bar. + + #### \`provenance\` * Default: false @@ -1056,6 +1225,17 @@ Set to \`false\` to suppress the progress bar. When publishing from a supported cloud CI/CD system, the package will be publicly linked to where it was built and published from. +This config can not be used with: \`provenance-file\` + +#### \`provenance-file\` + +* Default: null +* Type: Path + +When publishing, the provenance bundle at the given path will be used. + +This config can not be used with: \`provenance\` + #### \`proxy\` * Default: null @@ -1065,6 +1245,8 @@ A proxy to use for outgoing http requests. If the \`HTTP_PROXY\` or \`http_proxy\` environment variables are set, proxy settings will be honored by the underlying \`request\` library. + + #### \`read-only\` * Default: false @@ -1073,6 +1255,8 @@ by the underlying \`request\` library. This is used to mark a token as unable to publish when configuring limited access tokens with the \`npm token create\` command. + + #### \`rebuild-bundle\` * Default: true @@ -1080,6 +1264,8 @@ access tokens with the \`npm token create\` command. Rebuild bundled dependencies after installation. + + #### \`registry\` * Default: "https://registry.npmjs.org/" @@ -1087,6 +1273,8 @@ Rebuild bundled dependencies after installation. The base URL of the npm registry. + + #### \`replace-registry-host\` * Default: "npmjs" @@ -1102,6 +1290,8 @@ registry host with the configured host every time. You may also specify a bare hostname (e.g., "registry.npmjs.org"). + + #### \`save\` * Default: \`true\` unless when using \`npm update\` where it defaults to \`false\` @@ -1114,6 +1304,8 @@ When used with the \`npm rm\` command, removes the dependency from Will also prevent writing to \`package-lock.json\` if set to \`false\`. + + #### \`save-bundle\` * Default: false @@ -1125,6 +1317,8 @@ If a package would be saved at install time by the use of \`--save\`, Ignored if \`--save-peer\` is set, since peerDependencies cannot be bundled. + + #### \`save-dev\` * Default: false @@ -1132,6 +1326,8 @@ Ignored if \`--save-peer\` is set, since peerDependencies cannot be bundled. Save installed packages to a package.json file as \`devDependencies\`. + + #### \`save-exact\` * Default: false @@ -1140,6 +1336,8 @@ Save installed packages to a package.json file as \`devDependencies\`. Dependencies saved to package.json will be configured with an exact version rather than using npm's default semver range operator. + + #### \`save-optional\` * Default: false @@ -1147,6 +1345,8 @@ rather than using npm's default semver range operator. Save installed packages to a package.json file as \`optionalDependencies\`. + + #### \`save-peer\` * Default: false @@ -1154,6 +1354,8 @@ Save installed packages to a package.json file as \`optionalDependencies\`. Save installed packages to a package.json file as \`peerDependencies\` + + #### \`save-prefix\` * Default: "^" @@ -1167,6 +1369,8 @@ to \`^1.2.3\` which allows minor upgrades for that package, but after \`npm config set save-prefix='~'\` it would be set to \`~1.2.3\` which only allows patch upgrades. + + #### \`save-prod\` * Default: false @@ -1179,6 +1383,8 @@ you want to move it to be a non-optional production dependency. This is the default behavior if \`--save\` is true, and neither \`--save-dev\` or \`--save-optional\` are true. + + #### \`scope\` * Default: the scope of the current project, if any, or "" @@ -1209,6 +1415,7 @@ npm init --scope=@foo --yes \`\`\` + #### \`script-shell\` * Default: '/bin/sh' on POSIX systems, 'cmd.exe' on Windows @@ -1217,6 +1424,8 @@ npm init --scope=@foo --yes The shell to use for scripts run with the \`npm exec\`, \`npm run\` and \`npm init \` commands. + + #### \`searchexclude\` * Default: "" @@ -1224,6 +1433,8 @@ init \` commands. Space-separated options that limit the results from search. + + #### \`searchlimit\` * Default: 20 @@ -1232,6 +1443,8 @@ Space-separated options that limit the results from search. Number of items to limit search results to. Will not apply at all to legacy searches. + + #### \`searchopts\` * Default: "" @@ -1239,6 +1452,8 @@ searches. Space-separated options that are always passed to search. + + #### \`searchstaleness\` * Default: 900 @@ -1247,6 +1462,8 @@ Space-separated options that are always passed to search. The age of the cache, in seconds, before another registry request is made if using legacy search endpoint. + + #### \`shell\` * Default: SHELL environment variable, or "bash" on Posix, or "cmd.exe" on @@ -1255,6 +1472,8 @@ using legacy search endpoint. The shell to run for the \`npm explore\` command. + + #### \`sign-git-commit\` * Default: false @@ -1266,6 +1485,8 @@ version using \`-S\` to add a signature. Note that git requires you to have set up GPG keys in your git configs for this to work properly. + + #### \`sign-git-tag\` * Default: false @@ -1277,6 +1498,8 @@ If set to true, then the \`npm version\` command will tag the version using Note that git requires you to have set up GPG keys in your git configs for this to work properly. + + #### \`strict-peer-deps\` * Default: false @@ -1296,6 +1519,8 @@ When such an override is performed, a warning is printed, explaining the conflict and the packages involved. If \`--strict-peer-deps\` is set, then this warning is treated as a failure. + + #### \`strict-ssl\` * Default: true @@ -1306,6 +1531,8 @@ via https. See also the \`ca\` config. + + #### \`tag\` * Default: "latest" @@ -1320,6 +1547,8 @@ command, if no explicit tag is given. When used by the \`npm diff\` command, this is the tag used to fetch the tarball that will be compared with the local files by default. + + #### \`tag-version-prefix\` * Default: "v" @@ -1333,6 +1562,8 @@ Because other tools may rely on the convention that npm version tags look like \`v1.0.0\`, _only use this property if it is absolutely necessary_. In particular, use care when overriding this setting for public packages. + + #### \`timing\` * Default: false @@ -1347,6 +1578,8 @@ You can quickly view it with this [json](https://npm.im/json) command line: Timing information will also be reported in the terminal. To suppress this while still writing the timing file, use \`--silent\`. + + #### \`umask\` * Default: 0 @@ -1367,6 +1600,8 @@ Thus, the effective default umask value on most POSIX systems is 0o22, meaning that folders and executables are created with a mode of 0o755 and other files are created with a mode of 0o644. + + #### \`unicode\` * Default: false on windows, true on mac/unix systems with a unicode locale, @@ -1376,6 +1611,8 @@ other files are created with a mode of 0o644. When set to true, npm uses unicode characters in the tree output. When false, it uses ascii characters instead of unicode glyphs. + + #### \`update-notifier\` * Default: true @@ -1384,6 +1621,8 @@ false, it uses ascii characters instead of unicode glyphs. Set to false to suppress the update notification when using an older version of npm than the latest. + + #### \`usage\` * Default: false @@ -1391,6 +1630,8 @@ of npm than the latest. Show short usage output about the command specified. + + #### \`user-agent\` * Default: "npm/{npm-version} node/{node-version} {platform} {arch} @@ -1409,6 +1650,8 @@ their actual counterparts: * \`{ci}\` - The value of the \`ci-name\` config, if set, prefixed with \`ci/\`, or an empty string if \`ci-name\` is empty. + + #### \`userconfig\` * Default: "~/.npmrc" @@ -1420,6 +1663,8 @@ This may be overridden by the \`npm_config_userconfig\` environment variable or the \`--userconfig\` command line option, but may _not_ be overridden by settings in the \`globalconfig\` file. + + #### \`version\` * Default: false @@ -1429,6 +1674,8 @@ If true, output the npm version and exit successfully. Only relevant when specified explicitly on the command line. + + #### \`versions\` * Default: false @@ -1440,6 +1687,8 @@ exists, and exit successfully. Only relevant when specified explicitly on the command line. + + #### \`viewer\` * Default: "man" on Posix, "browser" on Windows @@ -1449,6 +1698,8 @@ The program to use to view help content. Set to \`"browser"\` to view html help content in the default web browser. + + #### \`which\` * Default: null @@ -1456,6 +1707,8 @@ Set to \`"browser"\` to view html help content in the default web browser. If there are multiple funding sources, which 1-indexed source URL to open. + + #### \`workspace\` * Default: @@ -1504,6 +1757,8 @@ This value is not exported to the environment for child processes. If set to true, the npm cli will run an update after operations that may possibly change the workspaces installed to the \`node_modules\` folder. + + #### \`yes\` * Default: null @@ -1512,6 +1767,8 @@ possibly change the workspaces installed to the \`node_modules\` folder. Automatically answer "yes" to any prompts that npm might print on the command line. + + #### \`also\` * Default: null @@ -1520,6 +1777,8 @@ command line. When set to \`dev\` or \`development\`, this is an alias for \`--include=dev\`. + + #### \`cache-max\` * Default: Infinity @@ -1528,6 +1787,8 @@ When set to \`dev\` or \`development\`, this is an alias for \`--include=dev\`. \`--cache-max=0\` is an alias for \`--prefer-online\` + + #### \`cache-min\` * Default: 0 @@ -1536,6 +1797,8 @@ When set to \`dev\` or \`development\`, this is an alias for \`--include=dev\`. \`--cache-min=9999 (or bigger)\` is an alias for \`--prefer-offline\`. + + #### \`cert\` * Default: null @@ -1557,6 +1820,22 @@ It is _not_ the path to a certificate file, though you can set a registry-scoped "certfile" path like "//other-registry.tld/:certfile=/path/to/cert.pem". + + +#### \`ci-name\` + +* Default: The name of the current CI system, or \`null\` when not on a known CI + platform. +* Type: null or String +* DEPRECATED: This config is deprecated and will not be changeable in future + version of npm. + +The name of a continuous integration system. If not set explicitly, npm will +detect the current CI environment using the +[\`ci-info\`](http://npm.im/ci-info) module. + + + #### \`dev\` * Default: false @@ -1565,6 +1844,8 @@ registry-scoped "certfile" path like Alias for \`--include=dev\`. + + #### \`global-style\` * Default: false @@ -1575,6 +1856,8 @@ Alias for \`--include=dev\`. Only install direct dependencies in the top level \`node_modules\`, but hoist on deeper dependencies. Sets \`--install-strategy=shallow\`. + + #### \`init.author.email\` * Default: "" @@ -1583,6 +1866,8 @@ on deeper dependencies. Sets \`--install-strategy=shallow\`. Alias for \`--init-author-email\` + + #### \`init.author.name\` * Default: "" @@ -1591,6 +1876,8 @@ Alias for \`--init-author-email\` Alias for \`--init-author-name\` + + #### \`init.author.url\` * Default: "" @@ -1599,6 +1886,8 @@ Alias for \`--init-author-name\` Alias for \`--init-author-url\` + + #### \`init.license\` * Default: "ISC" @@ -1607,6 +1896,8 @@ Alias for \`--init-author-url\` Alias for \`--init-license\` + + #### \`init.module\` * Default: "~/.npm-init.js" @@ -1615,6 +1906,8 @@ Alias for \`--init-license\` Alias for \`--init-module\` + + #### \`init.version\` * Default: "1.0.0" @@ -1623,6 +1916,8 @@ Alias for \`--init-module\` Alias for \`--init-version\` + + #### \`key\` * Default: null @@ -1642,6 +1937,8 @@ key="-----BEGIN PRIVATE KEY-----\\nXXXX\\nXXXX\\n-----END PRIVATE KEY-----" It is _not_ the path to a key file, though you can set a registry-scoped "keyfile" path like "//other-registry.tld/:keyfile=/path/to/key.pem". + + #### \`legacy-bundling\` * Default: false @@ -1654,6 +1951,8 @@ the same manner that they are depended on. This may cause very deep directory structures and duplicate package installs as there is no de-duplicating. Sets \`--install-strategy=nested\`. + + #### \`only\` * Default: null @@ -1662,6 +1961,8 @@ de-duplicating. Sets \`--install-strategy=nested\`. When set to \`prod\` or \`production\`, this is an alias for \`--omit=dev\`. + + #### \`optional\` * Default: null @@ -1673,6 +1974,8 @@ Default value does install optional deps unless otherwise omitted. Alias for --include=optional or --omit=optional + + #### \`production\` * Default: null @@ -1681,6 +1984,8 @@ Alias for --include=optional or --omit=optional Alias for \`--omit=dev\` + + #### \`shrinkwrap\` * Default: true @@ -1689,6 +1994,8 @@ Alias for \`--omit=dev\` Alias for --package-lock + + #### \`tmp\` * Default: The value returned by the Node.js \`os.tmpdir()\` method @@ -1700,6 +2007,8 @@ Alias for --package-lock Historically, the location where temporary files were stored. No longer relevant. + + ` exports[`test/lib/docs.js TAP config > all keys 1`] = ` @@ -1802,6 +2111,7 @@ Array [ "package-lock-only", "pack-destination", "parseable", + "prefer-dedupe", "prefer-offline", "prefer-online", "prefix", @@ -1809,6 +2119,7 @@ Array [ "production", "progress", "provenance", + "provenance-file", "proxy", "read-only", "rebuild-bundle", @@ -1938,12 +2249,14 @@ Array [ "package-lock-only", "pack-destination", "parseable", + "prefer-dedupe", "prefer-offline", "prefer-online", "preid", "production", "progress", "provenance", + "provenance-file", "proxy", "read-only", "rebuild-bundle", @@ -2013,6 +2326,129 @@ Array [ ] ` +exports[`test/lib/docs.js TAP flat options > full flat options object 1`] = ` +Object { + "_auth": null, + "access": null, + "all": false, + "allowSameVersion": false, + "audit": true, + "auditLevel": null, + "authType": "web", + "before": null, + "binLinks": true, + "browser": null, + "ca": null, + "cache": "{CWD}/cache/_cacache", + "call": "", + "cert": null, + "cidr": null, + "ciName": "{ci}", + "color": false, + "commitHooks": true, + "defaultTag": "latest", + "depth": null, + "diff": Array [], + "diffDstPrefix": "b/", + "diffIgnoreAllSpace": false, + "diffNameOnly": false, + "diffNoPrefix": false, + "diffSrcPrefix": "a/", + "diffText": false, + "diffUnified": 3, + "dryRun": false, + "editor": "{EDITOR}", + "engineStrict": false, + "force": false, + "foregroundScripts": false, + "formatPackageLock": true, + "fund": true, + "git": "git", + "gitTagVersion": true, + "global": false, + "globalconfig": "{CWD}/global/etc/npmrc", + "hashAlgorithm": "sha1", + "heading": "npm", + "httpsProxy": null, + "ifPresent": false, + "ignoreScripts": false, + "includeStaged": false, + "includeWorkspaceRoot": false, + "installLinks": false, + "installStrategy": "hoisted", + "json": false, + "key": null, + "legacyPeerDeps": false, + "localAddress": null, + "location": "user", + "lockfileVersion": null, + "logColor": false, + "maxSockets": 15, + "message": "%s", + "nodeBin": "{NODE}", + "nodeVersion": "2.2.2", + "noProxy": "", + "npmBin": "{CWD}/{TESTDIR}/docs.js", + "npmCommand": "version", + "npmVersion": "3.3.3", + "npxCache": "{CWD}/cache/_npx", + "offline": false, + "omit": Array [], + "omitLockfileRegistryResolved": false, + "otp": null, + "package": Array [], + "packageLock": true, + "packageLockOnly": false, + "packDestination": ".", + "parseable": false, + "preferDedupe": false, + "preferOffline": false, + "preferOnline": false, + "preid": "", + "progress": false, + "projectScope": "", + "provenance": false, + "provenanceFile": null, + "proxy": null, + "readOnly": false, + "rebuildBundle": true, + "registry": "https://registry.npmjs.org/", + "replaceRegistryHost": "npmjs", + "retry": Object { + "factor": 10, + "maxTimeout": 60000, + "minTimeout": 10000, + "retries": 0, + }, + "save": true, + "saveBundle": false, + "savePrefix": "^", + "scope": "", + "scriptShell": undefined, + "search": Object { + "description": true, + "exclude": "", + "limit": 20, + "opts": Null Object {}, + "staleness": 900, + }, + "shell": "{SHELL}", + "signGitCommit": false, + "signGitTag": false, + "silent": false, + "strictPeerDeps": false, + "strictSSL": true, + "tagVersionPrefix": "v", + "timeout": 300000, + "tufCache": "{CWD}/cache/_tuf", + "umask": 0, + "unicode": false, + "userAgent": "npm/1.1.1 node/2.2.2 {PLATFORM} {ARCH} workspaces/false ci/{ci}", + "workspacesEnabled": true, + "workspacesUpdate": true, +} +` + exports[`test/lib/docs.js TAP shorthands > docs 1`] = ` * \`-a\`: \`--all\` * \`--enjoy-by\`: \`--before\` @@ -2213,8 +2649,8 @@ npm ci Options: [--install-strategy ] [--legacy-bundling] [--global-style] [--omit [--omit ...]] -[--strict-peer-deps] [--no-package-lock] [--foreground-scripts] -[--ignore-scripts] [--no-audit] [--no-bin-links] [--no-fund] [--dry-run] +[--strict-peer-deps] [--foreground-scripts] [--ignore-scripts] [--no-audit] +[--no-bin-links] [--no-fund] [--dry-run] [-w|--workspace [-w|--workspace ...]] [-ws|--workspaces] [--include-workspace-root] [--install-links] @@ -2233,7 +2669,6 @@ aliases: clean-install, ic, install-clean, isntall-clean #### \`global-style\` #### \`omit\` #### \`strict-peer-deps\` -#### \`package-lock\` #### \`foreground-scripts\` #### \`ignore-scripts\` #### \`audit\` @@ -2639,6 +3074,9 @@ Get a value from the npm configuration Usage: npm get [ ...] (See \`npm config\`) +Options: +[-l|--long] + Run "npm help get" for more info \`\`\`bash @@ -2647,7 +3085,7 @@ npm get [ ...] (See \`npm config\`) Note: This command is unaware of workspaces. -NO PARAMS +#### \`long\` ` exports[`test/lib/docs.js TAP usage help > must match snapshot 1`] = ` @@ -2764,8 +3202,9 @@ Options: [-E|--save-exact] [-g|--global] [--install-strategy ] [--legacy-bundling] [--global-style] [--omit [--omit ...]] -[--strict-peer-deps] [--no-package-lock] [--foreground-scripts] -[--ignore-scripts] [--no-audit] [--no-bin-links] [--no-fund] [--dry-run] +[--strict-peer-deps] [--prefer-dedupe] [--no-package-lock] [--package-lock-only] +[--foreground-scripts] [--ignore-scripts] [--no-audit] [--no-bin-links] +[--no-fund] [--dry-run] [-w|--workspace [-w|--workspace ...]] [-ws|--workspaces] [--include-workspace-root] [--install-links] @@ -2787,7 +3226,9 @@ aliases: add, i, in, ins, inst, insta, instal, isnt, isnta, isntal, isntall #### \`global-style\` #### \`omit\` #### \`strict-peer-deps\` +#### \`prefer-dedupe\` #### \`package-lock\` +#### \`package-lock-only\` #### \`foreground-scripts\` #### \`ignore-scripts\` #### \`audit\` @@ -2809,8 +3250,8 @@ npm install-ci-test Options: [--install-strategy ] [--legacy-bundling] [--global-style] [--omit [--omit ...]] -[--strict-peer-deps] [--no-package-lock] [--foreground-scripts] -[--ignore-scripts] [--no-audit] [--no-bin-links] [--no-fund] [--dry-run] +[--strict-peer-deps] [--foreground-scripts] [--ignore-scripts] [--no-audit] +[--no-bin-links] [--no-fund] [--dry-run] [-w|--workspace [-w|--workspace ...]] [-ws|--workspaces] [--include-workspace-root] [--install-links] @@ -2829,7 +3270,6 @@ aliases: cit, clean-install-test, sit #### \`global-style\` #### \`omit\` #### \`strict-peer-deps\` -#### \`package-lock\` #### \`foreground-scripts\` #### \`ignore-scripts\` #### \`audit\` @@ -2853,8 +3293,9 @@ Options: [-E|--save-exact] [-g|--global] [--install-strategy ] [--legacy-bundling] [--global-style] [--omit [--omit ...]] -[--strict-peer-deps] [--no-package-lock] [--foreground-scripts] -[--ignore-scripts] [--no-audit] [--no-bin-links] [--no-fund] [--dry-run] +[--strict-peer-deps] [--prefer-dedupe] [--no-package-lock] [--package-lock-only] +[--foreground-scripts] [--ignore-scripts] [--no-audit] [--no-bin-links] +[--no-fund] [--dry-run] [-w|--workspace [-w|--workspace ...]] [-ws|--workspaces] [--include-workspace-root] [--install-links] @@ -2876,7 +3317,9 @@ alias: it #### \`global-style\` #### \`omit\` #### \`strict-peer-deps\` +#### \`prefer-dedupe\` #### \`package-lock\` +#### \`package-lock-only\` #### \`foreground-scripts\` #### \`ignore-scripts\` #### \`audit\` @@ -3326,7 +3769,8 @@ npm publish Options: [--tag ] [--access ] [--dry-run] [--otp ] [-w|--workspace [-w|--workspace ...]] -[-ws|--workspaces] [--include-workspace-root] [--provenance] +[-ws|--workspaces] [--include-workspace-root] +[--provenance|--provenance-file ] Run "npm help publish" for more info @@ -3342,6 +3786,7 @@ npm publish #### \`workspaces\` #### \`include-workspace-root\` #### \`provenance\` +#### \`provenance-file\` ` exports[`test/lib/docs.js TAP usage query > must match snapshot 1`] = ` @@ -3533,6 +3978,9 @@ Set a value in the npm configuration Usage: npm set = [= ...] (See \`npm config\`) +Options: +[-g|--global] [-L|--location ] + Run "npm help set" for more info \`\`\`bash @@ -3541,7 +3989,8 @@ npm set = [= ...] (See \`npm config\`) Note: This command is unaware of workspaces. -NO PARAMS +#### \`global\` +#### \`location\` ` exports[`test/lib/docs.js TAP usage shrinkwrap > must match snapshot 1`] = ` @@ -3731,6 +4180,7 @@ npm uninstall [<@scope>/]... Options: [-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer|--save-bundle] +[-g|--global] [-w|--workspace [-w|--workspace ...]] [-ws|--workspaces] [--include-workspace-root] [--install-links] @@ -3745,6 +4195,7 @@ aliases: unlink, remove, rm, r, un \`\`\` #### \`save\` +#### \`global\` #### \`workspace\` #### \`workspaces\` #### \`include-workspace-root\` diff --git a/tap-snapshots/test/lib/utils/explain-dep.js.test.cjs b/tap-snapshots/test/lib/utils/explain-dep.js.test.cjs index 8550617eb0a00..876cc6552b760 100644 --- a/tap-snapshots/test/lib/utils/explain-dep.js.test.cjs +++ b/tap-snapshots/test/lib/utils/explain-dep.js.test.cjs @@ -5,7 +5,7 @@ * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' -exports[`test/lib/utils/explain-dep.js TAP > ellipses test one 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic > ellipses test one 1`] = ` manydep@1.0.0 manydep@"1.0.0" from prod-dep@1.2.3 node_modules/prod-dep @@ -13,7 +13,7 @@ manydep@1.0.0 7 more (optdep, extra-neos, deep-dev, peer, the root project, ...) ` -exports[`test/lib/utils/explain-dep.js TAP > ellipses test two 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic > ellipses test two 1`] = ` manydep@1.0.0 manydep@"1.0.0" from prod-dep@1.2.3 node_modules/prod-dep @@ -21,29 +21,29 @@ manydep@1.0.0 6 more (optdep, extra-neos, deep-dev, peer, the root project, a package with a pretty long name) ` -exports[`test/lib/utils/explain-dep.js TAP bundled > explain color deep 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic bundled > explain color deep 1`] = ` bundle-of-joy@1.0.0 bundled node_modules/bundle-of-joy bundled prod-dep@"1.x" from the root project ` -exports[`test/lib/utils/explain-dep.js TAP bundled > explain nocolor shallow 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic bundled > explain nocolor shallow 1`] = ` bundle-of-joy@1.0.0 bundled node_modules/bundle-of-joy bundled prod-dep@"1.x" from the root project ` -exports[`test/lib/utils/explain-dep.js TAP bundled > print color 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic bundled > print color 1`] = ` bundle-of-joy@1.0.0 bundled node_modules/bundle-of-joy ` -exports[`test/lib/utils/explain-dep.js TAP bundled > print nocolor 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic bundled > print nocolor 1`] = ` bundle-of-joy@1.0.0 bundled node_modules/bundle-of-joy ` -exports[`test/lib/utils/explain-dep.js TAP deepDev > explain color deep 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic deepDev > explain color deep 1`] = ` deep-dev@2.3.4 dev node_modules/deep-dev deep-dev@"2.x" from metadev@3.4.5 @@ -53,7 +53,7 @@ exports[`test/lib/utils/explain-dep.js TAP deepDev > explain color deep 1`] = ` dev topdev@"4.x" from the root project ` -exports[`test/lib/utils/explain-dep.js TAP deepDev > explain nocolor shallow 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic deepDev > explain nocolor shallow 1`] = ` deep-dev@2.3.4 dev node_modules/deep-dev deep-dev@"2.x" from metadev@3.4.5 @@ -62,37 +62,37 @@ node_modules/deep-dev node_modules/topdev ` -exports[`test/lib/utils/explain-dep.js TAP deepDev > print color 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic deepDev > print color 1`] = ` deep-dev@2.3.4 dev node_modules/deep-dev ` -exports[`test/lib/utils/explain-dep.js TAP deepDev > print nocolor 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic deepDev > print nocolor 1`] = ` deep-dev@2.3.4 dev node_modules/deep-dev ` -exports[`test/lib/utils/explain-dep.js TAP extraneous > explain color deep 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic extraneous > explain color deep 1`] = ` extra-neos@1337.420.69-lol extraneous node_modules/extra-neos ` -exports[`test/lib/utils/explain-dep.js TAP extraneous > explain nocolor shallow 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic extraneous > explain nocolor shallow 1`] = ` extra-neos@1337.420.69-lol extraneous node_modules/extra-neos ` -exports[`test/lib/utils/explain-dep.js TAP extraneous > print color 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic extraneous > print color 1`] = ` extra-neos@1337.420.69-lol extraneous node_modules/extra-neos ` -exports[`test/lib/utils/explain-dep.js TAP extraneous > print nocolor 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic extraneous > print nocolor 1`] = ` extra-neos@1337.420.69-lol extraneous node_modules/extra-neos ` -exports[`test/lib/utils/explain-dep.js TAP manyDeps > explain color deep 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic manyDeps > explain color deep 1`] = ` manydep@1.0.0 manydep@"1.0.0" from prod-dep@1.2.3 node_modules/prod-dep @@ -118,7 +118,7 @@ exports[`test/lib/utils/explain-dep.js TAP manyDeps > explain color deep 1`] = ` manydep@"1" from yet another a package with a pretty long name@1.2.3 ` -exports[`test/lib/utils/explain-dep.js TAP manyDeps > explain nocolor shallow 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic manyDeps > explain nocolor shallow 1`] = ` manydep@1.0.0 manydep@"1.0.0" from prod-dep@1.2.3 node_modules/prod-dep @@ -126,103 +126,103 @@ manydep@1.0.0 8 more (optdep, extra-neos, deep-dev, peer, the root project, ...) ` -exports[`test/lib/utils/explain-dep.js TAP manyDeps > print color 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic manyDeps > print color 1`] = ` manydep@1.0.0 ` -exports[`test/lib/utils/explain-dep.js TAP manyDeps > print nocolor 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic manyDeps > print nocolor 1`] = ` manydep@1.0.0 ` -exports[`test/lib/utils/explain-dep.js TAP optional > explain color deep 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic optional > explain color deep 1`] = ` optdep@1.0.0 optional node_modules/optdep optional optdep@"1.0.0" from the root project ` -exports[`test/lib/utils/explain-dep.js TAP optional > explain nocolor shallow 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic optional > explain nocolor shallow 1`] = ` optdep@1.0.0 optional node_modules/optdep optional optdep@"1.0.0" from the root project ` -exports[`test/lib/utils/explain-dep.js TAP optional > print color 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic optional > print color 1`] = ` optdep@1.0.0 optional node_modules/optdep ` -exports[`test/lib/utils/explain-dep.js TAP optional > print nocolor 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic optional > print nocolor 1`] = ` optdep@1.0.0 optional node_modules/optdep ` -exports[`test/lib/utils/explain-dep.js TAP overridden > explain color deep 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic overridden > explain color deep 1`] = ` overridden-root@1.0.0 overridden node_modules/overridden-root overridden overridden-dep@"1.0.0" (was "^2.0.0") from the root project ` -exports[`test/lib/utils/explain-dep.js TAP overridden > explain nocolor shallow 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic overridden > explain nocolor shallow 1`] = ` overridden-root@1.0.0 overridden node_modules/overridden-root overridden overridden-dep@"1.0.0" (was "^2.0.0") from the root project ` -exports[`test/lib/utils/explain-dep.js TAP overridden > print color 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic overridden > print color 1`] = ` overridden-root@1.0.0 overridden node_modules/overridden-root ` -exports[`test/lib/utils/explain-dep.js TAP overridden > print nocolor 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic overridden > print nocolor 1`] = ` overridden-root@1.0.0 overridden node_modules/overridden-root ` -exports[`test/lib/utils/explain-dep.js TAP peer > explain color deep 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic peer > explain color deep 1`] = ` peer@1.0.0 peer node_modules/peer peer peer@"1.0.0" from the root project ` -exports[`test/lib/utils/explain-dep.js TAP peer > explain nocolor shallow 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic peer > explain nocolor shallow 1`] = ` peer@1.0.0 peer node_modules/peer peer peer@"1.0.0" from the root project ` -exports[`test/lib/utils/explain-dep.js TAP peer > print color 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic peer > print color 1`] = ` peer@1.0.0 peer node_modules/peer ` -exports[`test/lib/utils/explain-dep.js TAP peer > print nocolor 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic peer > print nocolor 1`] = ` peer@1.0.0 peer node_modules/peer ` -exports[`test/lib/utils/explain-dep.js TAP prodDep > explain color deep 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic prodDep > explain color deep 1`] = ` prod-dep@1.2.3 node_modules/prod-dep prod-dep@"1.x" from the root project ` -exports[`test/lib/utils/explain-dep.js TAP prodDep > explain nocolor shallow 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic prodDep > explain nocolor shallow 1`] = ` prod-dep@1.2.3 node_modules/prod-dep prod-dep@"1.x" from the root project ` -exports[`test/lib/utils/explain-dep.js TAP prodDep > print color 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic prodDep > print color 1`] = ` prod-dep@1.2.3 node_modules/prod-dep ` -exports[`test/lib/utils/explain-dep.js TAP prodDep > print nocolor 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic prodDep > print nocolor 1`] = ` prod-dep@1.2.3 node_modules/prod-dep ` -exports[`test/lib/utils/explain-dep.js TAP workspaces > explain color deep 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic workspaces > explain color deep 1`] = ` a@1.0.0 a a@1.0.0 @@ -230,7 +230,7 @@ exports[`test/lib/utils/explain-dep.js TAP workspaces > explain color deep 1`] = workspace a from the root project ` -exports[`test/lib/utils/explain-dep.js TAP workspaces > explain nocolor shallow 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic workspaces > explain nocolor shallow 1`] = ` a@1.0.0 a a@1.0.0 @@ -238,12 +238,12 @@ a workspace a from the root project ` -exports[`test/lib/utils/explain-dep.js TAP workspaces > print color 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic workspaces > print color 1`] = ` a@1.0.0 a ` -exports[`test/lib/utils/explain-dep.js TAP workspaces > print nocolor 1`] = ` +exports[`test/lib/utils/explain-dep.js TAP basic workspaces > print nocolor 1`] = ` a@1.0.0 a ` diff --git a/tap-snapshots/test/lib/utils/explain-eresolve.js.test.cjs b/tap-snapshots/test/lib/utils/explain-eresolve.js.test.cjs index 99ad5c0f31e90..3d73019d3e45b 100644 --- a/tap-snapshots/test/lib/utils/explain-eresolve.js.test.cjs +++ b/tap-snapshots/test/lib/utils/explain-eresolve.js.test.cjs @@ -5,7 +5,7 @@ * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' -exports[`test/lib/utils/explain-eresolve.js TAP chain-conflict > explain with color, depth of 2 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic chain-conflict > explain with color, depth of 2 1`] = ` While resolving: project@1.2.3 Found: @isaacs/testing-peer-dep-conflict-chain-d@2.0.0 node_modules/@isaacs/testing-peer-dep-conflict-chain-d @@ -17,7 +17,7 @@ Could not resolve dependency: @isaacs/testing-peer-dep-conflict-chain-c@"1" from the root project ` -exports[`test/lib/utils/explain-eresolve.js TAP chain-conflict > explain with no color, depth of 6 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic chain-conflict > explain with no color, depth of 6 1`] = ` While resolving: project@1.2.3 Found: @isaacs/testing-peer-dep-conflict-chain-d@2.0.0 node_modules/@isaacs/testing-peer-dep-conflict-chain-d @@ -29,7 +29,7 @@ node_modules/@isaacs/testing-peer-dep-conflict-chain-c @isaacs/testing-peer-dep-conflict-chain-c@"1" from the root project ` -exports[`test/lib/utils/explain-eresolve.js TAP chain-conflict > report from color 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic chain-conflict > report from color 1`] = ` # npm resolution error report While resolving: project@1.2.3 @@ -47,7 +47,7 @@ this command with --force or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. ` -exports[`test/lib/utils/explain-eresolve.js TAP chain-conflict > report with color 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic chain-conflict > report with color 1`] = ` While resolving: project@1.2.3 Found: @isaacs/testing-peer-dep-conflict-chain-d@2.0.0 node_modules/@isaacs/testing-peer-dep-conflict-chain-d @@ -63,7 +63,7 @@ this command with --force or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. ` -exports[`test/lib/utils/explain-eresolve.js TAP chain-conflict > report with no color 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic chain-conflict > report with no color 1`] = ` While resolving: project@1.2.3 Found: @isaacs/testing-peer-dep-conflict-chain-d@2.0.0 node_modules/@isaacs/testing-peer-dep-conflict-chain-d @@ -79,7 +79,7 @@ this command with --force or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. ` -exports[`test/lib/utils/explain-eresolve.js TAP cycleNested > explain with color, depth of 2 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic cycleNested > explain with color, depth of 2 1`] = ` Found: @isaacs/peer-dep-cycle-c@2.0.0 node_modules/@isaacs/peer-dep-cycle-c @isaacs/peer-dep-cycle-c@"2.x" from the root project @@ -97,7 +97,7 @@ Conflicting peer dependency: @isaacs/peer-dep-cycle-c@1.0.0[2 node_modules/@isaacs/peer-dep-cycle-a ` -exports[`test/lib/utils/explain-eresolve.js TAP cycleNested > explain with no color, depth of 6 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic cycleNested > explain with no color, depth of 6 1`] = ` Found: @isaacs/peer-dep-cycle-c@2.0.0 node_modules/@isaacs/peer-dep-cycle-c @isaacs/peer-dep-cycle-c@"2.x" from the root project @@ -116,7 +116,7 @@ node_modules/@isaacs/peer-dep-cycle-c @isaacs/peer-dep-cycle-a@"1.x" from the root project ` -exports[`test/lib/utils/explain-eresolve.js TAP cycleNested > report from color 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic cycleNested > report from color 1`] = ` # npm resolution error report Found: @isaacs/peer-dep-cycle-c@2.0.0 @@ -141,7 +141,7 @@ this command with --no-strict-peer-deps, --force, or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. ` -exports[`test/lib/utils/explain-eresolve.js TAP cycleNested > report with color 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic cycleNested > report with color 1`] = ` Found: @isaacs/peer-dep-cycle-c@2.0.0 node_modules/@isaacs/peer-dep-cycle-c @isaacs/peer-dep-cycle-c@"2.x" from the root project @@ -164,7 +164,7 @@ this command with --no-strict-peer-deps, --force, or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. ` -exports[`test/lib/utils/explain-eresolve.js TAP cycleNested > report with no color 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic cycleNested > report with no color 1`] = ` Found: @isaacs/peer-dep-cycle-c@2.0.0 node_modules/@isaacs/peer-dep-cycle-c @isaacs/peer-dep-cycle-c@"2.x" from the root project @@ -187,7 +187,7 @@ this command with --no-strict-peer-deps, --force, or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. ` -exports[`test/lib/utils/explain-eresolve.js TAP eslint-plugin case > explain with color, depth of 2 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic eslint-plugin case > explain with color, depth of 2 1`] = ` While resolving: eslint-plugin-react@7.24.0 Found: eslint@6.8.0 node_modules/eslint @@ -204,7 +204,7 @@ Conflicting peer dependency: eslint@7.31.0 dev eslint-plugin-eslint-plugin@"^3.1.0" from the root project ` -exports[`test/lib/utils/explain-eresolve.js TAP eslint-plugin case > explain with no color, depth of 6 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic eslint-plugin case > explain with no color, depth of 6 1`] = ` While resolving: eslint-plugin-react@7.24.0 Found: eslint@6.8.0 node_modules/eslint @@ -227,7 +227,7 @@ node_modules/eslint dev eslint-plugin-eslint-plugin@"^3.1.0" from the root project ` -exports[`test/lib/utils/explain-eresolve.js TAP eslint-plugin case > report from color 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic eslint-plugin case > report from color 1`] = ` # npm resolution error report While resolving: eslint-plugin-react@7.24.0 @@ -261,7 +261,7 @@ this command with --force or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. ` -exports[`test/lib/utils/explain-eresolve.js TAP eslint-plugin case > report with color 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic eslint-plugin case > report with color 1`] = ` While resolving: eslint-plugin-react@7.24.0 Found: eslint@6.8.0 node_modules/eslint @@ -285,7 +285,7 @@ this command with --force or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. ` -exports[`test/lib/utils/explain-eresolve.js TAP eslint-plugin case > report with no color 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic eslint-plugin case > report with no color 1`] = ` While resolving: eslint-plugin-react@7.24.0 Found: eslint@6.8.0 node_modules/eslint @@ -309,7 +309,7 @@ this command with --force or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. ` -exports[`test/lib/utils/explain-eresolve.js TAP gatsby > explain with color, depth of 2 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic gatsby > explain with color, depth of 2 1`] = ` While resolving: gatsby-recipes@0.2.31 Found: ink@3.0.0-7 node_modules/ink @@ -325,7 +325,7 @@ Could not resolve dependency: node_modules/gatsby-recipes ` -exports[`test/lib/utils/explain-eresolve.js TAP gatsby > explain with no color, depth of 6 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic gatsby > explain with no color, depth of 6 1`] = ` While resolving: gatsby-recipes@0.2.31 Found: ink@3.0.0-7 node_modules/ink @@ -349,7 +349,7 @@ node_modules/ink-box gatsby@"" from the root project ` -exports[`test/lib/utils/explain-eresolve.js TAP gatsby > report from color 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic gatsby > report from color 1`] = ` # npm resolution error report While resolving: gatsby-recipes@0.2.31 @@ -379,7 +379,7 @@ this command with --no-strict-peer-deps, --force, or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. ` -exports[`test/lib/utils/explain-eresolve.js TAP gatsby > report with color 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic gatsby > report with color 1`] = ` While resolving: gatsby-recipes@0.2.31 Found: ink@3.0.0-7 node_modules/ink @@ -406,7 +406,7 @@ this command with --no-strict-peer-deps, --force, or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. ` -exports[`test/lib/utils/explain-eresolve.js TAP gatsby > report with no color 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic gatsby > report with no color 1`] = ` While resolving: gatsby-recipes@0.2.31 Found: ink@3.0.0-7 node_modules/ink @@ -433,7 +433,7 @@ this command with --no-strict-peer-deps, --force, or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. ` -exports[`test/lib/utils/explain-eresolve.js TAP no current node, but has current edge > explain with color, depth of 2 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic no current node, but has current edge > explain with color, depth of 2 1`] = ` While resolving: eslint@7.22.0 Found: dev eslint@"file:." from the root project @@ -443,7 +443,7 @@ Could not resolve dependency: dev eslint-plugin-jsdoc@"^22.1.0" from the root project ` -exports[`test/lib/utils/explain-eresolve.js TAP no current node, but has current edge > explain with no color, depth of 6 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic no current node, but has current edge > explain with no color, depth of 6 1`] = ` While resolving: eslint@7.22.0 Found: dev eslint@"file:." from the root project @@ -453,7 +453,7 @@ node_modules/eslint-plugin-jsdoc dev eslint-plugin-jsdoc@"^22.1.0" from the root project ` -exports[`test/lib/utils/explain-eresolve.js TAP no current node, but has current edge > report from color 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic no current node, but has current edge > report from color 1`] = ` # npm resolution error report While resolving: eslint@7.22.0 @@ -469,7 +469,7 @@ this command with --force or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. ` -exports[`test/lib/utils/explain-eresolve.js TAP no current node, but has current edge > report with color 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic no current node, but has current edge > report with color 1`] = ` While resolving: eslint@7.22.0 Found: dev eslint@"file:." from the root project @@ -483,7 +483,7 @@ this command with --force or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. ` -exports[`test/lib/utils/explain-eresolve.js TAP no current node, but has current edge > report with no color 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic no current node, but has current edge > report with no color 1`] = ` While resolving: eslint@7.22.0 Found: dev eslint@"file:." from the root project @@ -497,7 +497,7 @@ this command with --force or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. ` -exports[`test/lib/utils/explain-eresolve.js TAP no current node, no current edge, idk > explain with color, depth of 2 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic no current node, no current edge, idk > explain with color, depth of 2 1`] = ` While resolving: eslint@7.22.0 Found: peer eslint@"^6.0.0" from eslint-plugin-jsdoc@22.2.0 node_modules/eslint-plugin-jsdoc @@ -509,7 +509,7 @@ Could not resolve dependency: dev eslint-plugin-jsdoc@"^22.1.0" from the root project ` -exports[`test/lib/utils/explain-eresolve.js TAP no current node, no current edge, idk > explain with no color, depth of 6 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic no current node, no current edge, idk > explain with no color, depth of 6 1`] = ` While resolving: eslint@7.22.0 Found: peer eslint@"^6.0.0" from eslint-plugin-jsdoc@22.2.0 node_modules/eslint-plugin-jsdoc @@ -521,7 +521,7 @@ node_modules/eslint-plugin-jsdoc dev eslint-plugin-jsdoc@"^22.1.0" from the root project ` -exports[`test/lib/utils/explain-eresolve.js TAP no current node, no current edge, idk > report from color 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic no current node, no current edge, idk > report from color 1`] = ` # npm resolution error report While resolving: eslint@7.22.0 @@ -539,7 +539,7 @@ this command with --force or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. ` -exports[`test/lib/utils/explain-eresolve.js TAP no current node, no current edge, idk > report with color 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic no current node, no current edge, idk > report with color 1`] = ` While resolving: eslint@7.22.0 Found: peer eslint@"^6.0.0" from eslint-plugin-jsdoc@22.2.0 node_modules/eslint-plugin-jsdoc @@ -555,7 +555,7 @@ this command with --force or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. ` -exports[`test/lib/utils/explain-eresolve.js TAP no current node, no current edge, idk > report with no color 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic no current node, no current edge, idk > report with no color 1`] = ` While resolving: eslint@7.22.0 Found: peer eslint@"^6.0.0" from eslint-plugin-jsdoc@22.2.0 node_modules/eslint-plugin-jsdoc @@ -571,7 +571,7 @@ this command with --force or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. ` -exports[`test/lib/utils/explain-eresolve.js TAP withShrinkwrap > explain with color, depth of 2 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic withShrinkwrap > explain with color, depth of 2 1`] = ` While resolving: @isaacs/peer-dep-cycle-b@1.0.0 Found: @isaacs/peer-dep-cycle-c@2.0.0 node_modules/@isaacs/peer-dep-cycle-c @@ -584,7 +584,7 @@ Could not resolve dependency: node_modules/@isaacs/peer-dep-cycle-a ` -exports[`test/lib/utils/explain-eresolve.js TAP withShrinkwrap > explain with no color, depth of 6 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic withShrinkwrap > explain with no color, depth of 6 1`] = ` While resolving: @isaacs/peer-dep-cycle-b@1.0.0 Found: @isaacs/peer-dep-cycle-c@2.0.0 node_modules/@isaacs/peer-dep-cycle-c @@ -598,7 +598,7 @@ node_modules/@isaacs/peer-dep-cycle-b @isaacs/peer-dep-cycle-a@"1.x" from the root project ` -exports[`test/lib/utils/explain-eresolve.js TAP withShrinkwrap > report from color 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic withShrinkwrap > report from color 1`] = ` # npm resolution error report While resolving: @isaacs/peer-dep-cycle-b@1.0.0 @@ -618,7 +618,7 @@ this command with --no-strict-peer-deps, --force, or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. ` -exports[`test/lib/utils/explain-eresolve.js TAP withShrinkwrap > report with color 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic withShrinkwrap > report with color 1`] = ` While resolving: @isaacs/peer-dep-cycle-b@1.0.0 Found: @isaacs/peer-dep-cycle-c@2.0.0 node_modules/@isaacs/peer-dep-cycle-c @@ -636,7 +636,7 @@ this command with --no-strict-peer-deps, --force, or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. ` -exports[`test/lib/utils/explain-eresolve.js TAP withShrinkwrap > report with no color 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP basic withShrinkwrap > report with no color 1`] = ` While resolving: @isaacs/peer-dep-cycle-b@1.0.0 Found: @isaacs/peer-dep-cycle-c@2.0.0 node_modules/@isaacs/peer-dep-cycle-c diff --git a/tap-snapshots/test/lib/utils/open-url-prompt.js.test.cjs b/tap-snapshots/test/lib/utils/open-url-prompt.js.test.cjs index 8af3c475c7720..968b14a20d90f 100644 --- a/tap-snapshots/test/lib/utils/open-url-prompt.js.test.cjs +++ b/tap-snapshots/test/lib/utils/open-url-prompt.js.test.cjs @@ -6,20 +6,10 @@ */ 'use strict' exports[`test/lib/utils/open-url-prompt.js TAP opens a url > must match snapshot 1`] = ` -Array [ - Array [ - String( - npm home: - https://www.npmjs.com - ), - ], -] +npm home: +https://www.npmjs.com ` exports[`test/lib/utils/open-url-prompt.js TAP prints json output > must match snapshot 1`] = ` -Array [ - Array [ - "{\\"title\\":\\"npm home\\",\\"url\\":\\"https://www.npmjs.com\\"}", - ], -] +{"title":"npm home","url":"https://www.npmjs.com"} ` diff --git a/tap-snapshots/test/lib/utils/reify-finish.js.test.cjs b/tap-snapshots/test/lib/utils/reify-finish.js.test.cjs deleted file mode 100644 index a82905a399679..0000000000000 --- a/tap-snapshots/test/lib/utils/reify-finish.js.test.cjs +++ /dev/null @@ -1,15 +0,0 @@ -/* IMPORTANT - * This snapshot file is auto-generated, but designed for humans. - * It should be checked into source control and tracked carefully. - * Re-generate by setting TAP_SNAPSHOT=1 and running tests. - * Make sure to inspect the output below. Do not ignore changes! - */ -'use strict' -exports[`test/lib/utils/reify-finish.js TAP should write if everything above passes > written config 1`] = ` -hasBuiltinConfig=true -x=y - -[nested] -foo=bar - -` diff --git a/test/bin/npx-cli.js b/test/bin/npx-cli.js index 5670f24f07b77..67a8d3319fc18 100644 --- a/test/bin/npx-cli.js +++ b/test/bin/npx-cli.js @@ -1,5 +1,5 @@ const t = require('tap') -const mockGlobals = require('../fixtures/mock-globals') +const mockGlobals = require('@npmcli/mock-globals') const tmock = require('../fixtures/tmock') const npm = require.resolve('../../bin/npm-cli.js') diff --git a/test/bin/windows-shims.js b/test/bin/windows-shims.js index e06e41bf8901d..13005ccf642ee 100644 --- a/test/bin/windows-shims.js +++ b/test/bin/windows-shims.js @@ -1,133 +1,145 @@ const t = require('tap') - -if (process.platform !== 'win32') { - t.plan(0, 'test only relevant on windows') - process.exit(0) -} - -const has = path => { - try { - // If WSL is installed, it *has* a bash.exe, but it fails if - // there is no distro installed, so we need to detect that. - const result = spawnSync(path, ['-l', '-c', 'exit 0']) - if (result.status === 0) { - return true - } else { - // print whatever error we got - throw result.error || Object.assign(new Error(String(result.stderr)), { - code: result.status, - }) - } - } catch (er) { - t.comment(`not installed: ${path}`, er) - return false - } -} - -const { version } = require('../../package.json') const spawn = require('@npmcli/promise-spawn') const { spawnSync } = require('child_process') -const { resolve } = require('path') -const { ProgramFiles, SystemRoot } = process.env +const { resolve, join } = require('path') const { readFileSync, chmodSync } = require('fs') -const gitBash = resolve(ProgramFiles, 'Git', 'bin', 'bash.exe') -const gitUsrBinBash = resolve(ProgramFiles, 'Git', 'usr', 'bin', 'bash.exe') -const wslBash = resolve(SystemRoot, 'System32', 'bash.exe') -const cygwinBash = resolve(SystemRoot, '/', 'cygwin64', 'bin', 'bash.exe') +const Diff = require('diff') +const { version } = require('../../package.json') + +const root = resolve(__dirname, '../..') +const npmShim = join(root, 'bin/npm') +const npxShim = join(root, 'bin/npx') -const bashes = Object.entries({ - 'wsl bash': wslBash, - 'git bash': gitBash, - 'git internal bash': gitUsrBinBash, - 'cygwin bash': cygwinBash, +t.test('npm vs npx', t => { + // these scripts should be kept in sync so this tests the contents of each + // and does a diff to ensure the only differences between them are necessary + const diffFiles = (ext = '') => Diff.diffChars( + readFileSync(`${npmShim}${ext}`, 'utf8'), + readFileSync(`${npxShim}${ext}`, 'utf8') + ).filter(v => v.added || v.removed).map((v, i) => i === 0 ? v.value : v.value.toUpperCase()) + + t.test('bash', t => { + const [npxCli, ...changes] = diffFiles() + const npxCliLine = npxCli.split('\n').reverse().join('') + t.match(npxCliLine, /^NPX_CLI_JS=/, 'has NPX_CLI') + t.equal(changes.length, 20) + t.strictSame([...new Set(changes)], ['M', 'X'], 'all other changes are m->x') + t.end() + }) + + t.test('cmd', t => { + const [npxCli, ...changes] = diffFiles('.cmd') + t.match(npxCli, /^SET "NPX_CLI_JS=/, 'has NPX_CLI') + t.equal(changes.length, 12) + t.strictSame([...new Set(changes)], ['M', 'X'], 'all other changes are m->x') + t.end() + }) + + t.end() }) -const npmShim = resolve(__dirname, '../../bin/npm') -const npxShim = resolve(__dirname, '../../bin/npx') +t.test('basic', async t => { + if (process.platform !== 'win32') { + t.comment('test only relevant on windows') + return + } -const path = t.testdir({ - 'node.exe': readFileSync(process.execPath), - npm: readFileSync(npmShim), - npx: readFileSync(npxShim), - // simulate the state where one version of npm is installed - // with node, but we should load the globally installed one - 'global-prefix': { - node_modules: { - npm: t.fixture('symlink', resolve(__dirname, '../..')), + const path = t.testdir({ + 'node.exe': readFileSync(process.execPath), + npm: readFileSync(npmShim), + npx: readFileSync(npxShim), + // simulate the state where one version of npm is installed + // with node, but we should load the globally installed one + 'global-prefix': { + node_modules: { + npm: t.fixture('symlink', root), + }, }, - }, - // put in a shim that ONLY prints the intended global prefix, - // and should not be used for anything else. - node_modules: { - npm: { - bin: { - 'npx-cli.js': ` - throw new Error('this should not be called') - `, - 'npm-cli.js': ` - const assert = require('assert') - const args = process.argv.slice(2) - assert.equal(args[0], 'prefix') - assert.equal(args[1], '-g') - const { resolve } = require('path') - console.log(resolve(__dirname, '../../../global-prefix')) - `, + // put in a shim that ONLY prints the intended global prefix, + // and should not be used for anything else. + node_modules: { + npm: { + bin: { + 'npx-cli.js': ` + throw new Error('this should not be called') + `, + 'npm-cli.js': ` + const assert = require('assert') + const args = process.argv.slice(2) + assert.equal(args[0], 'prefix') + assert.equal(args[1], '-g') + const { resolve } = require('path') + console.log(resolve(__dirname, '../../../global-prefix')) + `, + }, }, }, - }, -}) -chmodSync(resolve(path, 'npm'), 0o755) -chmodSync(resolve(path, 'npx'), 0o755) - -for (const [name, bash] of bashes) { - if (!has(bash)) { - t.skip(`${name} not installed`, { bin: bash, diagnostic: true }) - continue - } + }) - if (bash === cygwinBash && process.env.NYC_CONFIG) { - t.skip('Cygwin does not play nicely with NYC, run without coverage') - continue - } + chmodSync(join(path, 'npm'), 0o755) + chmodSync(join(path, 'npx'), 0o755) - t.test(name, async t => { - t.plan(2) - t.test('npm', async t => { - // only cygwin *requires* the -l, but the others are ok with it - // don't hit the registry for the update check - const args = ['-l', 'npm', 'help'] + const { ProgramFiles, SystemRoot, NYC_CONFIG } = process.env + const gitBash = join(ProgramFiles, 'Git', 'bin', 'bash.exe') + const gitUsrBinBash = join(ProgramFiles, 'Git', 'usr', 'bin', 'bash.exe') + const wslBash = join(SystemRoot, 'System32', 'bash.exe') + const cygwinBash = join(SystemRoot, '/', 'cygwin64', 'bin', 'bash.exe') - const result = await spawn(bash, args, { - env: { PATH: path, npm_config_update_notifier: 'false' }, - cwd: path, - }) - t.match(result, { - cmd: bash, - args: ['-l', 'npm', 'help'], - code: 0, - signal: null, - stderr: String, - // should have loaded this instance of npm we symlinked in - stdout: `npm@${version} ${resolve(__dirname, '../..')}`, - }) - }) + const bashes = Object.entries({ + 'wsl bash': wslBash, + 'git bash': gitBash, + 'git internal bash': gitUsrBinBash, + 'cygwin bash': cygwinBash, + }).map(([name, bash]) => { + let skip + if (bash === cygwinBash && NYC_CONFIG) { + skip = 'does not play nicely with NYC, run without coverage' + } else { + try { + // If WSL is installed, it *has* a bash.exe, but it fails if + // there is no distro installed, so we need to detect that. + if (spawnSync(bash, ['-l', '-c', 'exit 0']).status !== 0) { + throw new Error('not installed') + } + } catch { + skip = 'not installed' + } + } + return { name, bash, skip } + }) - t.test('npx', async t => { - const args = ['-l', 'npx', '--version'] + for (const { name, bash, skip } of bashes) { + if (skip) { + t.skip(name, { diagnostic: true, bin: bash, reason: skip }) + continue + } - const result = await spawn(bash, args, { - env: { PATH: path, npm_config_update_notifier: 'false' }, - cwd: path, - }) - t.match(result, { - cmd: bash, - args: ['-l', 'npx', '--version'], - code: 0, - signal: null, - stderr: String, + await t.test(name, async t => { + const bins = Object.entries({ // should have loaded this instance of npm we symlinked in - stdout: version, + npm: [['help'], `npm@${version} ${root}`], + npx: [['--version'], version], }) + + for (const [binName, [cmdArgs, stdout]] of bins) { + await t.test(binName, async t => { + // only cygwin *requires* the -l, but the others are ok with it + const args = ['-l', binName, ...cmdArgs] + const result = await spawn(bash, args, { + // don't hit the registry for the update check + env: { PATH: path, npm_config_update_notifier: 'false' }, + cwd: path, + }) + t.match(result, { + cmd: bash, + args: args, + code: 0, + signal: null, + stderr: String, + stdout, + }) + }) + } }) - }) -} + } +}) diff --git a/test/fixtures/libnpmsearch-stream-result.js b/test/fixtures/libnpmsearch-stream-result.js index b2ec20f59efeb..1ec8b7b113d6b 100644 --- a/test/fixtures/libnpmsearch-stream-result.js +++ b/test/fixtures/libnpmsearch-stream-result.js @@ -216,7 +216,7 @@ module.exports = [ version: '1.0.1', description: 'Retrieves a name:pathname Map for a given workspaces config', keywords: [ - 'npm', + '\x1B[33mnpm\x1B[39m', 'npmcli', 'libnpm', 'cli', @@ -240,10 +240,10 @@ module.exports = [ ], }, { - name: 'libnpmversion', + name: '\x1B[31mlibnpmversion\x1B[39m', scope: 'unscoped', version: '1.0.7', - description: "library to do the things that 'npm version' does", + description: "library to do the things that '\x1B[32mnpm version\x1B[39m' does", date: '2020-11-04T00:21:41.069Z', links: { npm: 'https://www.npmjs.com/package/libnpmversion', @@ -259,7 +259,7 @@ module.exports = [ }, publisher: { username: 'isaacs', email: 'i@izs.me' }, maintainers: [ - { username: 'nlf', email: 'quitlahok@gmail.com' }, + { username: '\x1B[34mnlf\x1B[39m', email: 'quitlahok@gmail.com' }, { username: 'ruyadorno', email: 'ruyadorno@hotmail.com' }, { username: 'darcyclarke', email: 'darcy@darcyclarke.me' }, { username: 'isaacs', email: 'i@izs.me' }, diff --git a/test/fixtures/mock-npm.js b/test/fixtures/mock-npm.js index a2d35c2479d73..4646e79146e86 100644 --- a/test/fixtures/mock-npm.js +++ b/test/fixtures/mock-npm.js @@ -4,7 +4,7 @@ const path = require('path') const tap = require('tap') const errorMessage = require('../../lib/utils/error-message') const mockLogs = require('./mock-logs') -const mockGlobals = require('./mock-globals') +const mockGlobals = require('@npmcli/mock-globals') const tmock = require('./tmock') const defExitCode = process.exitCode @@ -47,19 +47,28 @@ const setGlobalNodeModules = (globalDir) => { return globalDir } -const getMockNpm = async (t, { mocks, init, load, npm: npmOpts }) => { - const mock = { - ...mockLogs(mocks), - outputs: [], - outputErrors: [], - joinedOutput: () => mock.outputs.map(o => o.join(' ')).join('\n'), - } - - const Npm = tmock(t, '{LIB}/npm.js', { +const buildMocks = (t, mocks) => { + const allMocks = { '{LIB}/utils/update-notifier.js': async () => {}, ...mocks, - ...mock.logMocks, - }) + } + // The definitions must be mocked since they are a singleton that reads from + // process and environs to build defaults in order to break the requiure + // cache. We also need to mock them with any mocks that were passed in for the + // test in case those mocks are for things like ci-info which is used there. + const definitions = '@npmcli/config/lib/definitions' + allMocks[definitions] = tmock(t, definitions, allMocks) + + return allMocks +} + +const getMockNpm = async (t, { mocks, init, load, npm: npmOpts }) => { + const { logMocks, logs, display } = mockLogs(mocks) + const allMocks = buildMocks(t, { ...mocks, ...logMocks }) + const Npm = tmock(t, '{LIB}/npm.js', allMocks) + + const outputs = [] + const outputErrors = [] class MockNpm extends Npm { async exec (...args) { @@ -86,23 +95,29 @@ const getMockNpm = async (t, { mocks, init, load, npm: npmOpts }) => { } output (...args) { - mock.outputs.push(args) + outputs.push(args) } outputError (...args) { - mock.outputErrors.push(args) + outputErrors.push(args) } } - mock.Npm = MockNpm - if (init) { - mock.npm = new MockNpm(npmOpts) - if (load) { - await mock.npm.load() - } + const npm = init ? new MockNpm(npmOpts) : null + if (npm && load) { + await npm.load() } - return mock + return { + Npm: MockNpm, + npm, + outputs, + outputErrors, + joinedOutput: () => outputs.map(o => o.join(' ')).join('\n'), + logMocks, + logs, + display, + } } const mockNpms = new Map() @@ -113,6 +128,7 @@ const setupMockNpm = async (t, { // preload a command command = null, // string name of the command exec = null, // optionally exec the command before returning + setCmd = false, // test dirs prefixDir = {}, homeDir = {}, @@ -126,6 +142,7 @@ const setupMockNpm = async (t, { globals = {}, npm: npmOpts = {}, argv: rawArgv = [], + ...r } = {}) => { // easy to accidentally forget to pass in tap if (!(t instanceof tap.Test)) { @@ -212,7 +229,7 @@ const setupMockNpm = async (t, { return acc }, { argv: [...rawArgv], env: {}, config: {} }) - mockGlobals(t, { + const mockedGlobals = mockGlobals(t, { 'process.env.HOME': dirs.home, // global prefix cannot be (easily) set via argv so this is the easiest way // to set it that also closely mimics the behavior a user would see since it @@ -251,16 +268,25 @@ const setupMockNpm = async (t, { const mockCommand = {} if (command) { - const cmd = await npm.cmd(command) - const usage = await cmd.usage - mockCommand.cmd = cmd + const Cmd = mockNpm.Npm.cmd(command) + if (setCmd) { + // XXX(hack): This is a hack to allow fake-ish tests to set the currently + // running npm command without running exec. Generally, we should rely on + // actually exec-ing the command to asserting the state of the world + // through what is printed/on disk/etc. This is a stop-gap to allow tests + // that are time intensive to convert to continue setting the npm command + // this way. TODO: remove setCmd from all tests and remove the setCmd + // method from `lib/npm.js` + npm.setCmd(command) + } + mockCommand.cmd = new Cmd(npm) mockCommand[command] = { - usage, + usage: Cmd.describeUsage, exec: (args) => npm.exec(command, args), - completion: (args) => cmd.completion(args), + completion: (args) => Cmd.completion(args, npm), } if (exec) { - await mockCommand[command].exec(exec) + await mockCommand[command].exec(exec === true ? [] : exec) // assign string output to the command now that we have it // for easier testing mockCommand[command].output = mockNpm.joinedOutput() @@ -269,6 +295,7 @@ const setupMockNpm = async (t, { return { npm, + mockedGlobals, ...mockNpm, ...dirs, ...mockCommand, diff --git a/test/fixtures/sandbox.js b/test/fixtures/sandbox.js index 460609628c8ab..2c4e5c2968a38 100644 --- a/test/fixtures/sandbox.js +++ b/test/fixtures/sandbox.js @@ -81,7 +81,7 @@ class Sandbox extends EventEmitter { get: this[_get].bind(this), set: this[_set].bind(this), }) - this[_proxy].env = {} + this[_proxy].env = { ...options.env } this[_proxy].argv = [] test.cleanSnapshot = this.cleanSnapshot.bind(this) @@ -262,7 +262,9 @@ class Sandbox extends EventEmitter { const mockedLogs = mockLogs(this[_mocks]) this[_logs] = mockedLogs.logs + const definitions = this[_test].mock('@npmcli/config/lib/definitions') const Npm = this[_test].mock('../../lib/npm.js', { + '@npmcli/config/lib/definitions': definitions, '../../lib/utils/update-notifier.js': async () => {}, ...this[_mocks], ...mockedLogs.logMocks, @@ -313,7 +315,9 @@ class Sandbox extends EventEmitter { const mockedLogs = mockLogs(this[_mocks]) this[_logs] = mockedLogs.logs + const definitions = this[_test].mock('@npmcli/config/lib/definitions') const Npm = this[_test].mock('../../lib/npm.js', { + '@npmcli/config/lib/definitions': definitions, '../../lib/utils/update-notifier.js': async () => {}, ...this[_mocks], ...mockedLogs.logMocks, @@ -328,8 +332,8 @@ class Sandbox extends EventEmitter { this[_npm].output = (...args) => this[_output].push(args) await this[_npm].load() - const impl = await this[_npm].cmd(command) - return impl.completion({ + const Cmd = Npm.cmd(command) + return Cmd.completion({ partialWord: partial, conf: { argv: { diff --git a/test/lib/cli-entry.js b/test/lib/cli-entry.js new file mode 100644 index 0000000000000..22dca32f1a934 --- /dev/null +++ b/test/lib/cli-entry.js @@ -0,0 +1,163 @@ +const t = require('tap') +const { load: loadMockNpm } = require('../fixtures/mock-npm.js') +const tmock = require('../fixtures/tmock.js') +const validateEngines = require('../../lib/es6/validate-engines.js') + +const cliMock = async (t, opts) => { + let exitHandlerArgs = null + let npm = null + const exitHandlerMock = (...args) => { + exitHandlerArgs = args + npm.unload() + } + exitHandlerMock.setNpm = _npm => npm = _npm + + const { Npm, outputs, logMocks, logs } = await loadMockNpm(t, { ...opts, init: false }) + const cli = tmock(t, '{LIB}/cli-entry.js', { + '{LIB}/npm.js': Npm, + '{LIB}/utils/exit-handler.js': exitHandlerMock, + ...logMocks, + }) + + return { + Npm, + cli: (p) => validateEngines(p, () => cli), + outputs, + exitHandlerCalled: () => exitHandlerArgs, + exitHandlerNpm: () => npm, + logs, + logsBy: (title) => logs.verbose.filter(([p]) => p === title).map(([p, ...rest]) => rest), + } +} + +t.test('print the version, and treat npm_g as npm -g', async t => { + const { logsBy, logs, cli, Npm, outputs, exitHandlerCalled } = await cliMock(t, { + globals: { 'process.argv': ['node', 'npm_g', '-v'] }, + }) + await cli(process) + + t.strictSame(process.argv, ['node', 'npm', '-g', '-v'], 'system process.argv was rewritten') + t.strictSame(logsBy('cli'), [['node npm']]) + t.strictSame(logsBy('title'), [['npm']]) + t.match(logsBy('argv'), [['"--global" "--version"']]) + t.strictSame(logs.info, [ + ['using', 'npm@%s', Npm.version], + ['using', 'node@%s', process.version], + ]) + t.equal(outputs.length, 1) + t.strictSame(outputs, [[Npm.version]]) + t.strictSame(exitHandlerCalled(), []) +}) + +t.test('calling with --versions calls npm version with no args', async t => { + const { logsBy, cli, outputs, exitHandlerCalled } = await cliMock(t, { + globals: { + 'process.argv': ['node', 'npm', 'install', 'or', 'whatever', '--versions'], + }, + }) + await cli(process) + + t.equal(process.title, 'npm install or whatever') + t.strictSame(logsBy('cli'), [['node npm']]) + t.strictSame(logsBy('title'), [['npm install or whatever']]) + t.match(logsBy('argv'), [['"install" "or" "whatever" "--versions"']]) + t.equal(outputs.length, 1) + t.match(outputs[0][0], { npm: String, node: String, v8: String }) + t.strictSame(exitHandlerCalled(), []) +}) + +t.test('logged argv is sanitized', async t => { + const { logsBy, cli } = await cliMock(t, { + globals: { + 'process.argv': [ + 'node', + 'npm', + 'version', + '--registry', + 'https://u:password@npmjs.org/password', + ], + }, + }) + + await cli(process) + t.equal(process.title, 'npm version') + t.strictSame(logsBy('cli'), [['node npm']]) + t.strictSame(logsBy('title'), [['npm version']]) + t.match(logsBy('argv'), [['"version" "--registry" "https://u:***@npmjs.org/password"']]) +}) + +t.test('logged argv is sanitized with equals', async t => { + const { logsBy, cli } = await cliMock(t, { + globals: { + 'process.argv': [ + 'node', + 'npm', + 'version', + '--registry=https://u:password@npmjs.org', + ], + }, + }) + await cli(process) + + t.match(logsBy('argv'), [['"version" "--registry" "https://u:***@npmjs.org/"']]) +}) + +t.test('print usage if no params provided', async t => { + const { cli, outputs, exitHandlerCalled, exitHandlerNpm } = await cliMock(t, { + globals: { + 'process.argv': ['node', 'npm'], + }, + }) + await cli(process) + + t.match(outputs[0][0], 'Usage:', 'outputs npm usage') + t.match(exitHandlerCalled(), [], 'should call exitHandler with no args') + t.ok(exitHandlerNpm(), 'exitHandler npm is set') + t.match(process.exitCode, 1) +}) + +t.test('print usage if non-command param provided', async t => { + const { cli, outputs, exitHandlerCalled, exitHandlerNpm } = await cliMock(t, { + globals: { + 'process.argv': ['node', 'npm', 'tset'], + }, + }) + await cli(process) + + t.match(outputs[0][0], 'Unknown command: "tset"') + t.match(outputs[0][0], 'Did you mean this?') + t.match(exitHandlerCalled(), [], 'should call exitHandler with no args') + t.ok(exitHandlerNpm(), 'exitHandler npm is set') + t.match(process.exitCode, 1) +}) + +t.test('load error calls error handler', async t => { + const err = new Error('test load error') + const { cli, exitHandlerCalled } = await cliMock(t, { + mocks: { + '@npmcli/config': class BadConfig { + async load () { + throw err + } + }, + }, + globals: { + 'process.argv': ['node', 'npm', 'asdf'], + }, + }) + await cli(process) + t.strictSame(exitHandlerCalled(), [err]) +}) + +t.test('unsupported node version', async t => { + const { cli, logs } = await cliMock(t, { + globals: { + 'process.version': '12.6.0', + }, + }) + await cli(process) + t.match( + logs.warn[0][1], + /npm v.* does not support Node\.js 12\.6\.0\./ + ) +}) diff --git a/test/lib/cli.js b/test/lib/cli.js index cafd13feabe93..a6cb576e886ee 100644 --- a/test/lib/cli.js +++ b/test/lib/cli.js @@ -1,167 +1,10 @@ const t = require('tap') -const { load: loadMockNpm } = require('../fixtures/mock-npm.js') const tmock = require('../fixtures/tmock') -const cliMock = async (t, opts) => { - let exitHandlerArgs = null - let npm = null - const exitHandlerMock = (...args) => { - exitHandlerArgs = args - npm.unload() - } - exitHandlerMock.setNpm = _npm => npm = _npm - - const { Npm, outputs, logMocks, logs } = await loadMockNpm(t, { ...opts, init: false }) +t.test('returns cli-entry function', async t => { const cli = tmock(t, '{LIB}/cli.js', { - '{LIB}/npm.js': Npm, - '{LIB}/utils/exit-handler.js': exitHandlerMock, - ...logMocks, - }) - - return { - Npm, - cli, - outputs, - exitHandlerCalled: () => exitHandlerArgs, - exitHandlerNpm: () => npm, - logs, - logsBy: (title) => logs.verbose.filter(([p]) => p === title).map(([p, ...rest]) => rest), - } -} - -t.test('print the version, and treat npm_g as npm -g', async t => { - const { logsBy, logs, cli, Npm, outputs, exitHandlerCalled } = await cliMock(t, { - globals: { 'process.argv': ['node', 'npm_g', '-v'] }, - }) - await cli(process) - - t.strictSame(process.argv, ['node', 'npm', '-g', '-v'], 'system process.argv was rewritten') - t.strictSame(logsBy('cli'), [['node npm']]) - t.strictSame(logsBy('title'), [['npm']]) - t.match(logsBy('argv'), [['"--global" "--version"']]) - t.strictSame(logs.info, [ - ['using', 'npm@%s', Npm.version], - ['using', 'node@%s', process.version], - ]) - t.equal(outputs.length, 1) - t.strictSame(outputs, [[Npm.version]]) - t.strictSame(exitHandlerCalled(), []) -}) - -t.test('calling with --versions calls npm version with no args', async t => { - const { logsBy, cli, outputs, exitHandlerCalled } = await cliMock(t, { - globals: { - 'process.argv': ['node', 'npm', 'install', 'or', 'whatever', '--versions'], - }, - }) - await cli(process) - - t.equal(process.title, 'npm install or whatever') - t.strictSame(logsBy('cli'), [['node npm']]) - t.strictSame(logsBy('title'), [['npm install or whatever']]) - t.match(logsBy('argv'), [['"install" "or" "whatever" "--versions"']]) - t.equal(outputs.length, 1) - t.match(outputs[0][0], { npm: String, node: String, v8: String }) - t.strictSame(exitHandlerCalled(), []) -}) - -t.test('logged argv is sanitized', async t => { - const { logsBy, cli } = await cliMock(t, { - globals: { - 'process.argv': [ - 'node', - 'npm', - 'version', - '--registry', - 'https://u:password@npmjs.org/password', - ], - }, - }) - - await cli(process) - t.equal(process.title, 'npm version') - t.strictSame(logsBy('cli'), [['node npm']]) - t.strictSame(logsBy('title'), [['npm version']]) - t.match(logsBy('argv'), [['"version" "--registry" "https://u:***@npmjs.org/password"']]) -}) - -t.test('logged argv is sanitized with equals', async t => { - const { logsBy, cli } = await cliMock(t, { - globals: { - 'process.argv': [ - 'node', - 'npm', - 'version', - '--registry=https://u:password@npmjs.org', - ], - }, - }) - await cli(process) - - t.match(logsBy('argv'), [['"version" "--registry" "https://u:***@npmjs.org/"']]) -}) - -t.test('print usage if no params provided', async t => { - const { cli, outputs, exitHandlerCalled, exitHandlerNpm } = await cliMock(t, { - globals: { - 'process.argv': ['node', 'npm'], - }, + '{LIB}/cli-entry.js': () => 'ENTRY', }) - await cli(process) - - t.match(outputs[0][0], 'Usage:', 'outputs npm usage') - t.match(exitHandlerCalled(), [], 'should call exitHandler with no args') - t.ok(exitHandlerNpm(), 'exitHandler npm is set') - t.match(process.exitCode, 1) -}) -t.test('print usage if non-command param provided', async t => { - const { cli, outputs, exitHandlerCalled, exitHandlerNpm } = await cliMock(t, { - globals: { - 'process.argv': ['node', 'npm', 'tset'], - }, - }) - await cli(process) - - t.match(outputs[0][0], 'Unknown command: "tset"') - t.match(outputs[0][0], 'Did you mean this?') - t.match(exitHandlerCalled(), [], 'should call exitHandler with no args') - t.ok(exitHandlerNpm(), 'exitHandler npm is set') - t.match(process.exitCode, 1) -}) - -t.test('load error calls error handler', async t => { - const err = new Error('test load error') - const { cli, exitHandlerCalled } = await cliMock(t, { - mocks: { - '{LIB}/utils/config/index.js': { - definitions: null, - flatten: null, - shorthands: null, - }, - '@npmcli/config': class BadConfig { - async load () { - throw err - } - }, - }, - globals: { - 'process.argv': ['node', 'npm', 'asdf'], - }, - }) - await cli(process) - t.strictSame(exitHandlerCalled(), [err]) -}) - -t.test('unsupported node version', async t => { - const { cli, logs } = await cliMock(t, { - globals: { - 'process.version': '12.6.0', - }, - }) - await cli(process) - t.match( - logs.warn[0][1], - /npm v.* does not support Node\.js 12\.6\.0\./ - ) + t.equal(cli(process), 'ENTRY') }) diff --git a/test/lib/commands/access.js b/test/lib/commands/access.js index d1839aaaef219..7aec33701297c 100644 --- a/test/lib/commands/access.js +++ b/test/lib/commands/access.js @@ -7,8 +7,7 @@ const token = 'test-auth-token' const auth = { '//registry.npmjs.org/:_authToken': 'test-auth-token' } t.test('completion', async t => { - const { npm } = await loadMockNpm(t) - const access = await npm.cmd('access') + const { access } = await loadMockNpm(t, { command: 'access' }) const testComp = (argv, expect) => { const res = access.completion({ conf: { argv: { remain: argv } } }) t.resolves(res, expect, argv.join(' ')) diff --git a/test/lib/commands/adduser.js b/test/lib/commands/adduser.js index ddfbb945b2fcf..410e8c4987ca6 100644 --- a/test/lib/commands/adduser.js +++ b/test/lib/commands/adduser.js @@ -4,27 +4,47 @@ const path = require('path') const ini = require('ini') const { load: loadMockNpm } = require('../../fixtures/mock-npm.js') -const mockGlobals = require('../../fixtures/mock-globals.js') +const mockGlobals = require('@npmcli/mock-globals') const MockRegistry = require('@npmcli/mock-registry') const stream = require('stream') +const mockAddUser = async (t, { stdin: stdinLines, registry: registryUrl, ...options } = {}) => { + let stdin + if (stdinLines) { + stdin = new stream.PassThrough() + for (const l of stdinLines) { + stdin.write(l + '\n') + } + mockGlobals(t, { + 'process.stdin': stdin, + 'process.stdout': new stream.PassThrough(), // to quiet readline + }, { replace: true }) + } + const mock = await loadMockNpm(t, { + ...options, + command: 'adduser', + }) + const registry = new MockRegistry({ + tap: t, + registry: registryUrl ?? mock.npm.config.get('registry'), + }) + return { + registry, + stdin, + rc: () => ini.parse(fs.readFileSync(path.join(mock.home, '.npmrc'), 'utf8')), + ...mock, + } +} + t.test('usage', async t => { - const { npm } = await loadMockNpm(t) - const adduser = await npm.cmd('adduser') + const { adduser } = await loadMockNpm(t, { command: 'adduser' }) t.match(adduser.usage, 'adduser', 'usage has command name in it') }) t.test('legacy', async t => { t.test('simple adduser', async t => { - const stdin = new stream.PassThrough() - stdin.write('test-user\n') - stdin.write('test-password\n') - stdin.write('test-email@npmjs.org\n') - mockGlobals(t, { - 'process.stdin': stdin, - 'process.stdout': new stream.PassThrough(), // to quiet readline - }, { replace: true }) - const { npm, home } = await loadMockNpm(t, { + const { npm, rc, registry, adduser } = await mockAddUser(t, { + stdin: ['test-user', 'test-password', 'test-email@npmjs.org'], config: { 'auth-type': 'legacy' }, homeDir: { '.npmrc': [ @@ -34,71 +54,48 @@ t.test('legacy', async t => { ].join('\n'), }, }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), - }) registry.couchadduser({ username: 'test-user', password: 'test-password', email: 'test-email@npmjs.org', token: 'npm_test-token', }) - await npm.exec('adduser', []) + await adduser.exec([]) t.same(npm.config.get('email'), 'test-email-old@npmjs.org') t.same(npm.config.get('//registry.npmjs.org/:_authToken'), 'npm_test-token') - const rc = ini.parse(fs.readFileSync(path.join(home, '.npmrc'), 'utf8')) - t.same(rc, { + t.same(rc(), { '//registry.npmjs.org/:_authToken': 'npm_test-token', email: 'test-email-old@npmjs.org', }, 'should only have token and un-nerfed old email') }) t.test('scoped adduser', async t => { - const stdin = new stream.PassThrough() - stdin.write('test-user\n') - stdin.write('test-password\n') - stdin.write('test-email@npmjs.org\n') - mockGlobals(t, { - 'process.stdin': stdin, - 'process.stdout': new stream.PassThrough(), // to quiet readline - }, { replace: true }) - const { npm, home } = await loadMockNpm(t, { + const { npm, rc, registry, adduser } = await mockAddUser(t, { + stdin: ['test-user', 'test-password', 'test-email@npmjs.org'], config: { 'auth-type': 'legacy', scope: '@myscope', }, }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), - }) registry.couchadduser({ username: 'test-user', password: 'test-password', email: 'test-email@npmjs.org', token: 'npm_test-token', }) - await npm.exec('adduser', []) + await adduser.exec([]) t.same(npm.config.get('//registry.npmjs.org/:_authToken'), 'npm_test-token') t.same(npm.config.get('@myscope:registry'), 'https://registry.npmjs.org/') - const rc = ini.parse(fs.readFileSync(path.join(home, '.npmrc'), 'utf8')) - t.same(rc, { + t.same(rc(), { '//registry.npmjs.org/:_authToken': 'npm_test-token', '@myscope:registry': 'https://registry.npmjs.org/', }, 'should only have token and scope:registry') }) t.test('scoped adduser with valid scoped registry config', async t => { - const stdin = new stream.PassThrough() - stdin.write('test-user\n') - stdin.write('test-password\n') - stdin.write('test-email@npmjs.org\n') - mockGlobals(t, { - 'process.stdin': stdin, - 'process.stdout': new stream.PassThrough(), // to quiet readline - }, { replace: true }) - const { npm, home } = await loadMockNpm(t, { + const { npm, rc, registry, adduser } = await mockAddUser(t, { + stdin: ['test-user', 'test-password', 'test-email@npmjs.org'], + registry: 'https://diff-registry.npmjs.org', homeDir: { '.npmrc': '@myscope:registry=https://diff-registry.npmjs.org', }, @@ -107,106 +104,70 @@ t.test('legacy', async t => { scope: '@myscope', }, }) - const registry = new MockRegistry({ - tap: t, - registry: 'https://diff-registry.npmjs.org', - }) registry.couchadduser({ username: 'test-user', password: 'test-password', email: 'test-email@npmjs.org', token: 'npm_test-token', }) - await npm.exec('adduser', []) + await adduser.exec([]) t.same(npm.config.get('//diff-registry.npmjs.org/:_authToken'), 'npm_test-token') t.same(npm.config.get('@myscope:registry'), 'https://diff-registry.npmjs.org') - const rc = ini.parse(fs.readFileSync(path.join(home, '.npmrc'), 'utf8')) - t.same(rc, { + t.same(rc(), { '@myscope:registry': 'https://diff-registry.npmjs.org', '//diff-registry.npmjs.org/:_authToken': 'npm_test-token', }, 'should only have token and scope:registry') }) t.test('save config failure', async t => { - const stdin = new stream.PassThrough() - stdin.write('test-user\n') - stdin.write('test-password\n') - stdin.write('test-email@npmjs.org\n') - mockGlobals(t, { - 'process.stdin': stdin, - 'process.stdout': new stream.PassThrough(), // to quiet readline - }, { replace: true }) - const { npm } = await loadMockNpm(t, { + const { registry, adduser } = await mockAddUser(t, { + stdin: ['test-user', 'test-password', 'test-email@npmjs.org'], config: { 'auth-type': 'legacy' }, homeDir: { '.npmrc': {}, }, }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), - }) registry.couchadduser({ username: 'test-user', password: 'test-password', email: 'test-email@npmjs.org', token: 'npm_test-token', }) - await t.rejects(npm.exec('adduser', [])) + await t.rejects(adduser.exec([])) }) t.end() }) t.test('web', t => { t.test('basic adduser', async t => { - const { npm, home } = await loadMockNpm(t, { + const { npm, rc, registry, adduser } = await mockAddUser(t, { config: { 'auth-type': 'web' }, }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), - }) registry.webadduser({ token: 'npm_test-token' }) - await npm.exec('adduser', []) + await adduser.exec([]) t.same(npm.config.get('//registry.npmjs.org/:_authToken'), 'npm_test-token') - const rc = ini.parse(fs.readFileSync(path.join(home, '.npmrc'), 'utf8')) - t.same(rc, { + t.same(rc(), { '//registry.npmjs.org/:_authToken': 'npm_test-token', }) }) t.test('server error', async t => { - const { npm } = await loadMockNpm(t, { + const { adduser, registry } = await mockAddUser(t, { config: { 'auth-type': 'web' }, }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), - }) registry.nock.post(registry.fullPath('/-/v1/login')) .reply(503, {}) await t.rejects( - npm.exec('adduser', []), + adduser.exec([]), { message: /503/ } ) }) t.test('fallback', async t => { - const stdin = new stream.PassThrough() - stdin.write('test-user\n') - stdin.write('test-password\n') - stdin.write('test-email@npmjs.org\n') - mockGlobals(t, { - 'process.stdin': stdin, - 'process.stdout': new stream.PassThrough(), // to quiet readline - }, { replace: true }) - const { npm } = await loadMockNpm(t, { + const { npm, registry, adduser } = await mockAddUser(t, { + stdin: ['test-user', 'test-password', 'test-email@npmjs.org'], config: { 'auth-type': 'web' }, }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), - }) registry.nock.post(registry.fullPath('/-/v1/login')) .reply(404, {}) registry.couchadduser({ @@ -215,7 +176,7 @@ t.test('web', t => { email: 'test-email@npmjs.org', token: 'npm_test-token', }) - await npm.exec('adduser', []) + await adduser.exec([]) t.same(npm.config.get('//registry.npmjs.org/:_authToken'), 'npm_test-token') }) t.end() diff --git a/test/lib/commands/audit.js b/test/lib/commands/audit.js index 5c82fa14de32c..4014e73387351 100644 --- a/test/lib/commands/audit.js +++ b/test/lib/commands/audit.js @@ -3,6 +3,7 @@ const zlib = require('zlib') const path = require('path') const t = require('tap') +const { default: tufmock } = require('@tufjs/repo-mock') const { load: loadMockNpm } = require('../../fixtures/mock-npm') const MockRegistry = require('@npmcli/mock-registry') @@ -210,8 +211,7 @@ t.test('audit fix - bulk endpoint', async t => { }) t.test('completion', async t => { - const { npm } = await loadMockNpm(t) - const audit = await npm.cmd('audit') + const { audit } = await loadMockNpm(t, { command: 'audit' }) t.test('fix', async t => { await t.resolveMatch( audit.completion({ conf: { argv: { remain: ['npm', 'audit'] } } }), @@ -247,28 +247,69 @@ t.test('audit signatures', async t => { }], } - const MISMATCHING_REGISTRY_KEYS = { + const TUF_VALID_REGISTRY_KEYS = { keys: [{ - expires: null, - keyid: 'SHA256:2l3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA', - keytype: 'ecdsa-sha2-nistp256', - scheme: 'ecdsa-sha2-nistp256', - key: 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1Olb3zMAFFxXKHiIkQO5cJ3Yhl5i6UPp+' + + keyId: 'SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA', + keyUsage: 'npm:signatures', + publicKey: { + rawBytes: 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1Olb3zMAFFxXKHiIkQO5cJ3Yhl5i6UPp+' + 'IhuteBJbuHcA5UogKo0EWtlWwW6KSaKoTNEYL7JlCQiVnkhBktUgg==', + keyDetails: 'PKIX_ECDSA_P256_SHA_256', + validFor: { + start: '1999-01-01T00:00:00.000Z', + }, + }, }], } - const EXPIRED_REGISTRY_KEYS = { + const TUF_MISMATCHING_REGISTRY_KEYS = { keys: [{ - expires: '2021-01-11T15:45:42.144Z', - keyid: 'SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA', - keytype: 'ecdsa-sha2-nistp256', - scheme: 'ecdsa-sha2-nistp256', - key: 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1Olb3zMAFFxXKHiIkQO5cJ3Yhl5i6UPp+' + + keyId: 'SHA256:2l3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA', + keyUsage: 'npm:signatures', + publicKey: { + rawBytes: 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1Olb3zMAFFxXKHiIkQO5cJ3Yhl5i6UPp+' + + 'IhuteBJbuHcA5UogKo0EWtlWwW6KSaKoTNEYL7JlCQiVnkhBktUgg==', + keyDetails: 'PKIX_ECDSA_P256_SHA_256', + validFor: { + start: '1999-01-01T00:00:00.000Z', + }, + }, + }], + } + + const TUF_EXPIRED_REGISTRY_KEYS = { + keys: [{ + keyId: 'SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA', + keyUsage: 'npm:signatures', + publicKey: { + rawBytes: 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1Olb3zMAFFxXKHiIkQO5cJ3Yhl5i6UPp+' + 'IhuteBJbuHcA5UogKo0EWtlWwW6KSaKoTNEYL7JlCQiVnkhBktUgg==', + keyDetails: 'PKIX_ECDSA_P256_SHA_256', + validFor: { + start: '1999-01-01T00:00:00.000Z', + end: '2021-01-11T15:45:42.144Z', + }, + }, }], } + const TUF_VALID_KEYS_TARGET = { + name: 'registry.npmjs.org/keys.json', + content: JSON.stringify(TUF_VALID_REGISTRY_KEYS), + } + + const TUF_MISMATCHING_KEYS_TARGET = { + name: 'registry.npmjs.org/keys.json', + content: JSON.stringify(TUF_MISMATCHING_REGISTRY_KEYS), + } + + const TUF_EXPIRED_KEYS_TARGET = { + name: 'registry.npmjs.org/keys.json', + content: JSON.stringify(TUF_EXPIRED_REGISTRY_KEYS), + } + + const TUF_TARGET_NOT_FOUND = [] + const installWithValidSigs = { 'package.json': JSON.stringify({ name: 'test-dep', @@ -882,13 +923,22 @@ t.test('audit signatures', async t => { await registry.package({ manifest }) } + function mockTUF ({ target, npm }) { + const opts = { + baseURL: 'https://tuf-repo-cdn.sigstore.dev', + metadataPathPrefix: '', + cachePath: path.join(npm.cache, '_tuf'), + } + return tufmock(target, opts) + } + t.test('with valid signatures', async t => { const { npm, joinedOutput } = await loadMockNpm(t, { prefixDir: installWithValidSigs, }) const registry = new MockRegistry({ tap: t, registry: npm.config.get('registry') }) await manifestWithValidSigs({ registry }) - registry.nock.get('/-/npm/v1/keys').reply(200, VALID_REGISTRY_KEYS) + mockTUF({ npm, target: TUF_VALID_KEYS_TARGET }) await npm.exec('audit', ['signatures']) @@ -921,6 +971,22 @@ t.test('audit signatures', async t => { }], }) await registry.package({ manifest }) + mockTUF({ npm, target: TUF_VALID_KEYS_TARGET }) + + await npm.exec('audit', ['signatures']) + + t.notOk(process.exitCode, 'should exit successfully') + t.match(joinedOutput(), /audited 1 package/) + t.matchSnapshot(joinedOutput()) + }) + + t.test('with key fallback to legacy API', async t => { + const { npm, joinedOutput } = await loadMockNpm(t, { + prefixDir: installWithValidSigs, + }) + const registry = new MockRegistry({ tap: t, registry: npm.config.get('registry') }) + await manifestWithValidSigs({ registry }) + mockTUF({ npm, target: TUF_TARGET_NOT_FOUND }) registry.nock.get('/-/npm/v1/keys').reply(200, VALID_REGISTRY_KEYS) await npm.exec('audit', ['signatures']) @@ -1027,7 +1093,7 @@ t.test('audit signatures', async t => { }) await registry.package({ manifest: asyncManifest }) await manifestWithInvalidSigs({ registry, name: 'node-fetch', version: '1.6.0' }) - registry.nock.get('/-/npm/v1/keys').reply(200, VALID_REGISTRY_KEYS) + mockTUF({ npm, target: TUF_VALID_KEYS_TARGET }) await npm.exec('audit', ['signatures']) @@ -1044,7 +1110,7 @@ t.test('audit signatures', async t => { }) const registry = new MockRegistry({ tap: t, registry: npm.config.get('registry') }) await manifestWithValidSigs({ registry }) - registry.nock.get('/-/npm/v1/keys').reply(200, VALID_REGISTRY_KEYS) + mockTUF({ npm, target: TUF_VALID_KEYS_TARGET }) await npm.exec('audit', ['signatures']) @@ -1059,7 +1125,7 @@ t.test('audit signatures', async t => { }) const registry = new MockRegistry({ tap: t, registry: npm.config.get('registry') }) await manifestWithInvalidSigs({ registry }) - registry.nock.get('/-/npm/v1/keys').reply(200, VALID_REGISTRY_KEYS) + mockTUF({ npm, target: TUF_VALID_KEYS_TARGET }) await npm.exec('audit', ['signatures']) @@ -1076,7 +1142,7 @@ t.test('audit signatures', async t => { const registry = new MockRegistry({ tap: t, registry: npm.config.get('registry') }) await manifestWithValidSigs({ registry }) await manifestWithoutSigs({ registry, name: 'async', version: '1.1.1' }) - registry.nock.get('/-/npm/v1/keys').reply(200, VALID_REGISTRY_KEYS) + mockTUF({ npm, target: TUF_VALID_KEYS_TARGET }) await npm.exec('audit', ['signatures']) @@ -1094,7 +1160,7 @@ t.test('audit signatures', async t => { const registry = new MockRegistry({ tap: t, registry: npm.config.get('registry') }) await manifestWithInvalidSigs({ registry }) await manifestWithoutSigs({ registry, name: 'async', version: '1.1.1' }) - registry.nock.get('/-/npm/v1/keys').reply(200, VALID_REGISTRY_KEYS) + mockTUF({ npm, target: TUF_VALID_KEYS_TARGET }) await npm.exec('audit', ['signatures']) @@ -1112,7 +1178,7 @@ t.test('audit signatures', async t => { const registry = new MockRegistry({ tap: t, registry: npm.config.get('registry') }) await manifestWithInvalidSigs({ registry, name: 'kms-demo', version: '1.0.0' }) await manifestWithInvalidSigs({ registry, name: 'async', version: '1.1.1' }) - registry.nock.get('/-/npm/v1/keys').reply(200, VALID_REGISTRY_KEYS) + mockTUF({ npm, target: TUF_VALID_KEYS_TARGET }) await npm.exec('audit', ['signatures']) @@ -1127,7 +1193,7 @@ t.test('audit signatures', async t => { const registry = new MockRegistry({ tap: t, registry: npm.config.get('registry') }) await manifestWithoutSigs({ registry, name: 'kms-demo', version: '1.0.0' }) await manifestWithoutSigs({ registry, name: 'async', version: '1.1.1' }) - registry.nock.get('/-/npm/v1/keys').reply(200, VALID_REGISTRY_KEYS) + mockTUF({ npm, target: TUF_VALID_KEYS_TARGET }) await npm.exec('audit', ['signatures']) @@ -1141,6 +1207,7 @@ t.test('audit signatures', async t => { }) const registry = new MockRegistry({ tap: t, registry: npm.config.get('registry') }) await manifestWithValidSigs({ registry }) + mockTUF({ npm, target: TUF_TARGET_NOT_FOUND }) registry.nock.get('/-/npm/v1/keys').reply(404) await t.rejects( @@ -1156,7 +1223,7 @@ t.test('audit signatures', async t => { }) const registry = new MockRegistry({ tap: t, registry: npm.config.get('registry') }) await manifestWithValidSigs({ registry }) - registry.nock.get('/-/npm/v1/keys').reply(200, EXPIRED_REGISTRY_KEYS) + mockTUF({ npm, target: TUF_EXPIRED_KEYS_TARGET }) await t.rejects( npm.exec('audit', ['signatures']), @@ -1171,7 +1238,7 @@ t.test('audit signatures', async t => { }) const registry = new MockRegistry({ tap: t, registry: npm.config.get('registry') }) await manifestWithValidSigs({ registry }) - registry.nock.get('/-/npm/v1/keys').reply(200, MISMATCHING_REGISTRY_KEYS) + mockTUF({ npm, target: TUF_MISMATCHING_KEYS_TARGET }) await t.rejects( npm.exec('audit', ['signatures']), @@ -1186,7 +1253,7 @@ t.test('audit signatures', async t => { }) const registry = new MockRegistry({ tap: t, registry: npm.config.get('registry') }) await manifestWithoutSigs({ registry }) - registry.nock.get('/-/npm/v1/keys').reply(200, VALID_REGISTRY_KEYS) + mockTUF({ npm, target: TUF_VALID_KEYS_TARGET }) await npm.exec('audit', ['signatures']) @@ -1204,7 +1271,7 @@ t.test('audit signatures', async t => { }) const registry = new MockRegistry({ tap: t, registry: npm.config.get('registry') }) await manifestWithoutSigs({ registry }) - registry.nock.get('/-/npm/v1/keys').reply(200, VALID_REGISTRY_KEYS) + mockTUF({ npm, target: TUF_VALID_KEYS_TARGET }) await npm.exec('audit', ['signatures']) @@ -1225,7 +1292,7 @@ t.test('audit signatures', async t => { }) const registry = new MockRegistry({ tap: t, registry: npm.config.get('registry') }) await manifestWithValidSigs({ registry }) - registry.nock.get('/-/npm/v1/keys').reply(200, VALID_REGISTRY_KEYS) + mockTUF({ npm, target: TUF_VALID_KEYS_TARGET }) await npm.exec('audit', ['signatures']) @@ -1243,7 +1310,7 @@ t.test('audit signatures', async t => { }) const registry = new MockRegistry({ tap: t, registry: npm.config.get('registry') }) await manifestWithInvalidSigs({ registry }) - registry.nock.get('/-/npm/v1/keys').reply(200, VALID_REGISTRY_KEYS) + mockTUF({ npm, target: TUF_VALID_KEYS_TARGET }) await npm.exec('audit', ['signatures']) @@ -1261,7 +1328,7 @@ t.test('audit signatures', async t => { const registry = new MockRegistry({ tap: t, registry: npm.config.get('registry') }) await manifestWithInvalidSigs({ registry }) await manifestWithoutSigs({ registry, name: 'async', version: '1.1.1' }) - registry.nock.get('/-/npm/v1/keys').reply(200, VALID_REGISTRY_KEYS) + mockTUF({ npm, target: TUF_VALID_KEYS_TARGET }) await npm.exec('audit', ['signatures']) @@ -1278,7 +1345,7 @@ t.test('audit signatures', async t => { }) const registry = new MockRegistry({ tap: t, registry: npm.config.get('registry') }) await manifestWithValidSigs({ registry }) - registry.nock.get('/-/npm/v1/keys').reply(200, VALID_REGISTRY_KEYS) + mockTUF({ npm, target: TUF_VALID_KEYS_TARGET }) await npm.exec('audit', ['signatures']) @@ -1309,6 +1376,7 @@ t.test('audit signatures', async t => { }], }) await registry.package({ manifest }) + mockTUF({ npm, target: TUF_TARGET_NOT_FOUND }) registry.nock.get('/-/npm/v1/keys').reply(404) await t.rejects( @@ -1339,6 +1407,7 @@ t.test('audit signatures', async t => { }], }) await registry.package({ manifest }) + mockTUF({ npm, target: TUF_TARGET_NOT_FOUND }) registry.nock.get('/-/npm/v1/keys').reply(400) await t.rejects( @@ -1377,17 +1446,11 @@ t.test('audit signatures', async t => { }], }) await registry.package({ manifest }) - registry.nock.get('/-/npm/v1/keys') - .reply(200, { - keys: [{ - expires: null, - keyid: 'SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA', - keytype: 'ecdsa-sha2-nistp256', - scheme: 'ecdsa-sha2-nistp256', - key: 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1Olb3zMAFFxXKHiIkQO5cJ3Yhl5i6UPp+' + - 'IhuteBJbuHcA5UogKo0EWtlWwW6KSaKoTNEYL7JlCQiVnkhBktUgg==', - }], - }) + mockTUF({ npm, + target: { + name: 'verdaccio-clone.org/keys.json', + content: JSON.stringify(TUF_VALID_REGISTRY_KEYS), + } }) await npm.exec('audit', ['signatures']) @@ -1425,17 +1488,11 @@ t.test('audit signatures', async t => { }], }) await registry.package({ manifest }) - registry.nock.get('/-/npm/v1/keys') - .reply(200, { - keys: [{ - expires: null, - keyid: 'SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA', - keytype: 'ecdsa-sha2-nistp256', - scheme: 'ecdsa-sha2-nistp256', - key: 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1Olb3zMAFFxXKHiIkQO5cJ3Yhl5i6UPp+' + - 'IhuteBJbuHcA5UogKo0EWtlWwW6KSaKoTNEYL7JlCQiVnkhBktUgg==', - }], - }) + mockTUF({ npm, + target: { + name: 'verdaccio-clone.org/keys.json', + content: JSON.stringify(TUF_VALID_REGISTRY_KEYS), + } }) await npm.exec('audit', ['signatures']) @@ -1467,17 +1524,11 @@ t.test('audit signatures', async t => { }], }) await registry.package({ manifest }) - registry.nock.get('/-/npm/v1/keys') - .reply(200, { - keys: [{ - expires: null, - keyid: 'SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA', - keytype: 'ecdsa-sha2-nistp256', - scheme: 'ecdsa-sha2-nistp256', - key: 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1Olb3zMAFFxXKHiIkQO5cJ3Yhl5i6UPp+' + - 'IhuteBJbuHcA5UogKo0EWtlWwW6KSaKoTNEYL7JlCQiVnkhBktUgg==', - }], - }) + mockTUF({ npm, + target: { + name: 'verdaccio-clone.org/keys.json', + content: JSON.stringify(TUF_VALID_REGISTRY_KEYS), + } }) await npm.exec('audit', ['signatures']) @@ -1486,6 +1537,94 @@ t.test('audit signatures', async t => { t.matchSnapshot(joinedOutput()) }) + t.test('third-party registry with sub-path', async t => { + const registryUrl = 'https://verdaccio-clone.org/npm' + const { npm, joinedOutput } = await loadMockNpm(t, { + prefixDir: installWithThirdPartyRegistry, + config: { + scope: '@npmcli', + registry: registryUrl, + }, + }) + const registry = new MockRegistry({ tap: t, registry: registryUrl }) + + const manifest = registry.manifest({ + name: '@npmcli/arborist', + packuments: [{ + version: '1.0.14', + dist: { + tarball: 'https://registry.npmjs.org/@npmcli/arborist/-/@npmcli/arborist-1.0.14.tgz', + integrity: 'sha512-caa8hv5rW9VpQKk6tyNRvSaVDySVjo9GkI7Wj/wcsFyxPm3tYrE' + + 'sFyTjSnJH8HCIfEGVQNjqqKXaXLFVp7UBag==', + signatures: [ + { + keyid: 'SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA', + sig: 'MEUCIAvNpR3G0j7WOPUuVMhE0ZdM8PnDNcsoeFD8Iwz9YWIMAiEAn8cicDC2' + + 'Sf9MFQydqTv6S5XYsAh9Af1sig1nApNI11M=', + }, + ], + }, + }], + }) + await registry.package({ manifest }) + + mockTUF({ npm, + target: { + name: 'verdaccio-clone.org/npm/keys.json', + content: JSON.stringify(TUF_VALID_REGISTRY_KEYS), + } }) + + await npm.exec('audit', ['signatures']) + + t.notOk(process.exitCode, 'should exit successfully') + t.match(joinedOutput(), /audited 1 package/) + t.matchSnapshot(joinedOutput()) + }) + + t.test('third-party registry with sub-path (trailing slash)', async t => { + const registryUrl = 'https://verdaccio-clone.org/npm/' + const { npm, joinedOutput } = await loadMockNpm(t, { + prefixDir: installWithThirdPartyRegistry, + config: { + scope: '@npmcli', + registry: registryUrl, + }, + }) + const registry = new MockRegistry({ tap: t, registry: registryUrl }) + + const manifest = registry.manifest({ + name: '@npmcli/arborist', + packuments: [{ + version: '1.0.14', + dist: { + tarball: 'https://registry.npmjs.org/@npmcli/arborist/-/@npmcli/arborist-1.0.14.tgz', + integrity: 'sha512-caa8hv5rW9VpQKk6tyNRvSaVDySVjo9GkI7Wj/wcsFyxPm3tYrE' + + 'sFyTjSnJH8HCIfEGVQNjqqKXaXLFVp7UBag==', + signatures: [ + { + keyid: 'SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA', + sig: 'MEUCIAvNpR3G0j7WOPUuVMhE0ZdM8PnDNcsoeFD8Iwz9YWIMAiEAn8cicDC2' + + 'Sf9MFQydqTv6S5XYsAh9Af1sig1nApNI11M=', + }, + ], + }, + }], + }) + await registry.package({ manifest }) + + mockTUF({ npm, + target: { + name: 'verdaccio-clone.org/npm/keys.json', + content: JSON.stringify(TUF_VALID_REGISTRY_KEYS), + } }) + + await npm.exec('audit', ['signatures']) + + t.notOk(process.exitCode, 'should exit successfully') + t.match(joinedOutput(), /audited 1 package/) + t.matchSnapshot(joinedOutput()) + }) + t.test('multiple registries with keys and signatures', async t => { const registryUrl = 'https://verdaccio-clone.org' const { npm, joinedOutput } = await loadMockNpm(t, { @@ -1500,7 +1639,7 @@ t.test('audit signatures', async t => { registry: registryUrl, }) await manifestWithValidSigs({ registry }) - registry.nock.get('/-/npm/v1/keys').reply(200, VALID_REGISTRY_KEYS) + mockTUF({ npm, target: TUF_VALID_KEYS_TARGET }) const manifest = thirdPartyRegistry.manifest({ name: '@npmcli/arborist', @@ -1556,11 +1695,36 @@ t.test('audit signatures', async t => { ) }) + t.test('errors when TUF errors', async t => { + const { npm } = await loadMockNpm(t, { + prefixDir: installWithMultipleDeps, + mocks: { + sigstore: { + sigstore: { + tuf: { + client: async () => ({ + getTarget: async () => { + throw new Error('error refreshing TUF metadata') + }, + }), + }, + }, + }, + }, + }) + + await t.rejects( + npm.exec('audit', ['signatures']), + /error refreshing TUF metadata/ + ) + }) + t.test('errors when the keys endpoint errors', async t => { const { npm } = await loadMockNpm(t, { prefixDir: installWithMultipleDeps, }) const registry = new MockRegistry({ tap: t, registry: npm.config.get('registry') }) + mockTUF({ npm, target: TUF_TARGET_NOT_FOUND }) registry.nock.get('/-/npm/v1/keys') .reply(500, { error: 'keys broke' }) @@ -1577,7 +1741,7 @@ t.test('audit signatures', async t => { const registry = new MockRegistry({ tap: t, registry: npm.config.get('registry') }) await manifestWithValidSigs({ registry }) - registry.nock.get('/-/npm/v1/keys').reply(200, VALID_REGISTRY_KEYS) + mockTUF({ npm, target: TUF_VALID_KEYS_TARGET }) await npm.exec('audit', ['signatures']) @@ -1590,8 +1754,7 @@ t.test('audit signatures', async t => { const { npm } = await loadMockNpm(t, { prefixDir: noInstall, }) - const registry = new MockRegistry({ tap: t, registry: npm.config.get('registry') }) - registry.nock.get('/-/npm/v1/keys').reply(200, VALID_REGISTRY_KEYS) + mockTUF({ npm, target: TUF_VALID_KEYS_TARGET }) await t.rejects( npm.exec('audit', ['signatures']), @@ -1612,8 +1775,7 @@ t.test('audit signatures', async t => { node_modules: {}, }, }) - const registry = new MockRegistry({ tap: t, registry: npm.config.get('registry') }) - registry.nock.get('/-/npm/v1/keys').reply(200, VALID_REGISTRY_KEYS) + mockTUF({ npm, target: TUF_VALID_KEYS_TARGET }) await t.rejects( npm.exec('audit', ['signatures']), @@ -1641,6 +1803,7 @@ t.test('audit signatures', async t => { }, }, }) + mockTUF({ npm, target: TUF_TARGET_NOT_FOUND }) await t.rejects( npm.exec('audit', ['signatures']), @@ -1669,8 +1832,7 @@ t.test('audit signatures', async t => { }, }) - const registry = new MockRegistry({ tap: t, registry: npm.config.get('registry') }) - registry.nock.get('/-/npm/v1/keys').reply(200, VALID_REGISTRY_KEYS) + mockTUF({ npm, target: TUF_VALID_KEYS_TARGET }) await t.rejects( npm.exec('audit', ['signatures']), @@ -1697,7 +1859,7 @@ t.test('audit signatures', async t => { }) const registry = new MockRegistry({ tap: t, registry: npm.config.get('registry') }) await manifestWithInvalidSigs({ registry }) - registry.nock.get('/-/npm/v1/keys').reply(200, VALID_REGISTRY_KEYS) + mockTUF({ npm, target: TUF_VALID_KEYS_TARGET }) await npm.exec('audit', ['signatures']) @@ -1728,7 +1890,7 @@ t.test('audit signatures', async t => { 'utf8' ) registry.nock.get('/-/npm/v1/attestations/sigstore@1.0.0').reply(200, fixture) - registry.nock.get('/-/npm/v1/keys').reply(200, VALID_REGISTRY_KEYS) + mockTUF({ npm, target: TUF_VALID_KEYS_TARGET }) await npm.exec('audit', ['signatures']) @@ -1761,7 +1923,7 @@ t.test('audit signatures', async t => { ) registry.nock.get('/-/npm/v1/attestations/sigstore@1.0.0').reply(200, fixture1) registry.nock.get('/-/npm/v1/attestations/tuf-js@1.0.0').reply(200, fixture2) - registry.nock.get('/-/npm/v1/keys').reply(200, VALID_REGISTRY_KEYS) + mockTUF({ npm, target: TUF_VALID_KEYS_TARGET }) await npm.exec('audit', ['signatures']) @@ -1791,7 +1953,7 @@ t.test('audit signatures', async t => { 'utf8' ) registry.nock.get('/-/npm/v1/attestations/sigstore@1.0.0').reply(200, fixture) - registry.nock.get('/-/npm/v1/keys').reply(200, VALID_REGISTRY_KEYS) + mockTUF({ npm, target: TUF_VALID_KEYS_TARGET }) await npm.exec('audit', ['signatures']) @@ -1828,7 +1990,7 @@ t.test('audit signatures', async t => { 'utf8' ) registry.nock.get('/-/npm/v1/attestations/sigstore@1.0.0').reply(200, fixture) - registry.nock.get('/-/npm/v1/keys').reply(200, VALID_REGISTRY_KEYS) + mockTUF({ npm, target: TUF_VALID_KEYS_TARGET }) await npm.exec('audit', ['signatures']) @@ -1865,7 +2027,7 @@ t.test('audit signatures', async t => { ) registry.nock.get('/-/npm/v1/attestations/sigstore@1.0.0').reply(200, fixture1) registry.nock.get('/-/npm/v1/attestations/tuf-js@1.0.0').reply(200, fixture2) - registry.nock.get('/-/npm/v1/keys').reply(200, VALID_REGISTRY_KEYS) + mockTUF({ npm, target: TUF_VALID_KEYS_TARGET }) await npm.exec('audit', ['signatures']) @@ -1922,7 +2084,7 @@ t.test('audit signatures', async t => { }) await registry.package({ manifest: asyncManifest }) await registry.package({ manifest: lightCycleManifest }) - registry.nock.get('/-/npm/v1/keys').reply(200, VALID_REGISTRY_KEYS) + mockTUF({ npm, target: TUF_VALID_KEYS_TARGET }) await npm.exec('audit', ['signatures']) @@ -1975,7 +2137,7 @@ t.test('audit signatures', async t => { }) await registry.package({ manifest: asyncManifest }) await registry.package({ manifest: lightCycleManifest }) - registry.nock.get('/-/npm/v1/keys').reply(200, VALID_REGISTRY_KEYS) + mockTUF({ npm, target: TUF_VALID_KEYS_TARGET }) await npm.exec('audit', ['signatures']) diff --git a/test/lib/commands/bugs.js b/test/lib/commands/bugs.js index bf45b9eee81ab..953c8e6345a2a 100644 --- a/test/lib/commands/bugs.js +++ b/test/lib/commands/bugs.js @@ -43,8 +43,7 @@ const pacote = { } t.test('usage', async (t) => { - const { npm } = await loadMockNpm(t) - const bugs = await npm.cmd('bugs') + const { bugs } = await loadMockNpm(t, { command: 'bugs' }) t.match(bugs.usage, 'bugs', 'usage has command name in it') }) diff --git a/test/lib/commands/cache.js b/test/lib/commands/cache.js index fe2854f9aa626..15ee4dc80aa1a 100644 --- a/test/lib/commands/cache.js +++ b/test/lib/commands/cache.js @@ -1,7 +1,6 @@ const t = require('tap') const { load: loadMockNpm } = require('../../fixtures/mock-npm.js') const MockRegistry = require('@npmcli/mock-registry') -const mockGlobals = require('../../fixtures/mock-globals') const cacache = require('cacache') const fs = require('fs') @@ -267,8 +266,9 @@ t.test('cache verify', async t => { }) t.test('cache verify as part of home', async t => { - const { npm, joinedOutput, prefix } = await loadMockNpm(t) - mockGlobals(t, { 'process.env.HOME': path.dirname(prefix) }) + const { npm, joinedOutput } = await loadMockNpm(t, { + globals: ({ prefix }) => ({ 'process.env.HOME': path.dirname(prefix) }), + }) await npm.exec('cache', ['verify']) t.match(joinedOutput(), 'Cache verified and compressed (~', 'contains ~ shorthand') }) @@ -302,8 +302,7 @@ t.test('cache verify w/ extra output', async t => { }) t.test('cache completion', async t => { - const { npm } = await loadMockNpm(t) - const cache = await npm.cmd('cache') + const { cache } = await loadMockNpm(t, { command: 'cache' }) const { completion } = cache const testComp = (argv, expect) => { diff --git a/test/lib/commands/completion.js b/test/lib/commands/completion.js index 6cc1677552e8a..904d9410fdd6c 100644 --- a/test/lib/commands/completion.js +++ b/test/lib/commands/completion.js @@ -1,30 +1,26 @@ const t = require('tap') const fs = require('fs') const path = require('path') +const { load: loadMockNpm } = require('../../fixtures/mock-npm') const completionScript = fs .readFileSync(path.resolve(__dirname, '../../../lib/utils/completion.sh'), { encoding: 'utf8' }) .replace(/^#!.*?\n/, '') -const { load: loadMockNpm } = require('../../fixtures/mock-npm') -const mockGlobals = require('../../fixtures/mock-globals') - const loadMockCompletion = async (t, o = {}) => { const { globals = {}, windows, ...options } = o - let resetGlobals = {} - resetGlobals = mockGlobals(t, { - 'process.platform': windows ? 'win32' : 'posix', - 'process.env.term': 'notcygwin', - 'process.env.msystem': 'nogmingw', - ...globals, - }).reset const res = await loadMockNpm(t, { + command: 'completion', ...options, + globals: (dirs) => ({ + 'process.platform': windows ? 'win32' : 'posix', + 'process.env.term': 'notcygwin', + 'process.env.msystem': 'nogmingw', + ...(typeof globals === 'function' ? globals(dirs) : globals), + }), }) - const completion = await res.npm.cmd('completion') return { - resetGlobals, - completion, + resetGlobals: res.mockedGlobals.reset, ...res, } } @@ -40,21 +36,26 @@ const loadMockCompletionComp = async (t, word, line) => t.test('completion', async t => { t.test('completion completion', async t => { - const { outputs, completion, prefix } = await loadMockCompletion(t, { + const { outputs, completion } = await loadMockCompletion(t, { prefixDir: { '.bashrc': 'aaa', '.zshrc': 'aaa', }, + globals: ({ prefix }) => ({ + 'process.env.HOME': prefix, + }), }) - mockGlobals(t, { 'process.env.HOME': prefix }) await completion.completion({ w: 2 }) t.matchSnapshot(outputs, 'both shells') }) t.test('completion completion no known shells', async t => { - const { outputs, completion, prefix } = await loadMockCompletion(t) - mockGlobals(t, { 'process.env.HOME': prefix }) + const { outputs, completion } = await loadMockCompletion(t, { + globals: ({ prefix }) => ({ + 'process.env.HOME': prefix, + }), + }) await completion.completion({ w: 2 }) t.matchSnapshot(outputs, 'no responses') @@ -86,7 +87,7 @@ t.test('completion', async t => { }, }) - await completion.exec({}) + await completion.exec() t.equal(data, completionScript, 'wrote the completion script') }) @@ -111,7 +112,7 @@ t.test('completion', async t => { }, }) - await completion.exec({}) + await completion.exec() t.equal(data, completionScript, 'wrote the completion script') }) @@ -190,7 +191,7 @@ t.test('completion', async t => { t.test('windows without bash', async t => { const { outputs, completion } = await loadMockCompletion(t, { windows: true }) await t.rejects( - completion.exec({}), + completion.exec(), { code: 'ENOTSUP', message: /completion supported only in MINGW/ }, 'returns the correct error' ) diff --git a/test/lib/commands/config.js b/test/lib/commands/config.js index 7d5140bffc45b..b54096fd216f2 100644 --- a/test/lib/commands/config.js +++ b/test/lib/commands/config.js @@ -33,8 +33,6 @@ t.test('config ignores workspaces', async t => { }) t.test('config list', async t => { - const sandbox = new Sandbox(t) - const temp = t.testdir({ global: { npmrc: 'globalloaded=yes', @@ -50,7 +48,8 @@ t.test('config list', async t => { const project = join(temp, 'project') const home = join(temp, 'home') - await sandbox.run('config', ['list'], { global, project, home }) + const sandbox = new Sandbox(t, { global, project, home }) + await sandbox.run('config', ['list']) t.matchSnapshot(sandbox.output, 'output matches snapshot') }) @@ -137,8 +136,8 @@ t.test('config delete single key', async t => { '.npmrc': 'access=public\nall=true', }) - const sandbox = new Sandbox(t) - await sandbox.run('config', ['delete', 'access'], { home }) + const sandbox = new Sandbox(t, { home }) + await sandbox.run('config', ['delete', 'access']) t.equal(sandbox.config.get('access'), null, 'acces should be defaulted') @@ -152,8 +151,8 @@ t.test('config delete multiple keys', async t => { '.npmrc': 'access=public\nall=true\naudit=false', }) - const sandbox = new Sandbox(t) - await sandbox.run('config', ['delete', 'access', 'all'], { home }) + const sandbox = new Sandbox(t, { home }) + await sandbox.run('config', ['delete', 'access', 'all']) t.equal(sandbox.config.get('access'), null, 'access should be defaulted') t.equal(sandbox.config.get('all'), false, 'all should be defaulted') @@ -169,8 +168,8 @@ t.test('config delete key --location=global', async t => { npmrc: 'access=public\nall=true', }) - const sandbox = new Sandbox(t) - await sandbox.run('config', ['delete', 'access', '--location=global'], { global }) + const sandbox = new Sandbox(t, { global }) + await sandbox.run('config', ['delete', 'access', '--location=global']) t.equal(sandbox.config.get('access', 'global'), undefined, 'access should be defaulted') @@ -184,8 +183,8 @@ t.test('config delete key --global', async t => { npmrc: 'access=public\nall=true', }) - const sandbox = new Sandbox(t) - await sandbox.run('config', ['delete', 'access', '--global'], { global }) + const sandbox = new Sandbox(t, { global }) + await sandbox.run('config', ['delete', 'access', '--global']) t.equal(sandbox.config.get('access', 'global'), undefined, 'access should no longer be set') @@ -408,8 +407,7 @@ t.test('config edit', async t => { const EDITOR = 'vim' const editor = spawk.spawn(EDITOR).exit(0) - const sandbox = new Sandbox(t, { home }) - sandbox.process.env.EDITOR = EDITOR + const sandbox = new Sandbox(t, { home, env: { EDITOR } }) await sandbox.run('config', ['edit']) t.ok(editor.called, 'editor was spawned') diff --git a/test/lib/commands/deprecate.js b/test/lib/commands/deprecate.js index 48513c7303a01..4ae146fd3aee0 100644 --- a/test/lib/commands/deprecate.js +++ b/test/lib/commands/deprecate.js @@ -12,13 +12,13 @@ const versions = ['1.0.0', '1.0.1', '1.0.1-pre'] const packages = { foo: 'write', bar: 'write', baz: 'write', buzz: 'read' } t.test('completion', async t => { - const { npm } = await loadMockNpm(t, { + const { npm, deprecate } = await loadMockNpm(t, { + command: 'deprecate', config: { ...auth, }, }) - const deprecate = await npm.cmd('deprecate') const testComp = async (argv, expect) => { const res = await deprecate.completion({ conf: { argv: { remain: argv } } }) diff --git a/test/lib/commands/diff.js b/test/lib/commands/diff.js index d9ff9e5dad0e6..36a9e4bc17d9f 100644 --- a/test/lib/commands/diff.js +++ b/test/lib/commands/diff.js @@ -25,7 +25,9 @@ const mockDiff = async (t, { ...opts } = {}) => { const tarballFixtures = Object.entries(tarballs).reduce((acc, [spec, fixture]) => { - const [name, version] = spec.split('@') + const lastAt = spec.lastIndexOf('@') + const name = spec.slice(0, lastAt) + const version = spec.slice(lastAt + 1) acc[name] = acc[name] || {} acc[name][version] = fixture if (!acc[name][version]['package.json']) { @@ -39,6 +41,7 @@ const mockDiff = async (t, { const { prefixDir, globalPrefixDir, otherDirs, config, ...rest } = opts const { npm, ...res } = await loadMockNpm(t, { + command: 'diff', prefixDir: jsonifyTestdir(prefixDir), otherDirs: jsonifyTestdir({ tarballs: tarballFixtures, ...otherDirs }), globalPrefixDir: jsonifyTestdir(globalPrefixDir), @@ -75,7 +78,7 @@ const mockDiff = async (t, { } if (exec) { - await npm.exec('diff', exec) + await res.diff.exec(exec) res.output = res.joinedOutput() } @@ -98,13 +101,13 @@ const assertFoo = async (t, arg) => { const { output } = await mockDiff(t, { diff, prefixDir: { - 'package.json': { name: 'foo', version: '1.0.0' }, + 'package.json': { name: '@npmcli/foo', version: '1.0.0' }, 'index.js': 'const version = "1.0.0"', 'a.js': 'const a = "a@1.0.0"', 'b.js': 'const b = "b@1.0.0"', }, tarballs: { - 'foo@0.1.0': { + '@npmcli/foo@0.1.0': { 'index.js': 'const version = "0.1.0"', 'a.js': 'const a = "a@0.1.0"', 'b.js': 'const b = "b@0.1.0"', @@ -162,17 +165,17 @@ t.test('no args', async t => { t.test('single arg', async t => { t.test('spec using cwd package name', async t => { - await assertFoo(t, 'foo@0.1.0') + await assertFoo(t, '@npmcli/foo@0.1.0') }) t.test('unknown spec, no package.json', async t => { await rejectDiff(t, /Needs multiple arguments to compare or run from a project dir./, { - diff: ['foo@1.0.0'], + diff: ['@npmcli/foo@1.0.0'], }) }) t.test('spec using semver range', async t => { - await assertFoo(t, 'foo@~0.1.0') + await assertFoo(t, '@npmcli/foo@~0.1.0') }) t.test('version', async t => { @@ -429,17 +432,17 @@ t.test('single arg', async t => { t.test('use project name in project dir', async t => { const { output } = await mockDiff(t, { - diff: 'foo', + diff: '@npmcli/foo', prefixDir: { - 'package.json': { name: 'foo', version: '1.0.0' }, + 'package.json': { name: '@npmcli/foo', version: '1.0.0' }, }, tarballs: { - 'foo@2.2.2': {}, + '@npmcli/foo@2.2.2': {}, }, exec: [], }) - t.match(output, 'foo') + t.match(output, '@npmcli/foo') t.match(output, /-\s*"version": "2\.2\.2"/) t.match(output, /\+\s*"version": "1\.0\.0"/) }) @@ -448,17 +451,17 @@ t.test('single arg', async t => { const { output } = await mockDiff(t, { diff: '../other/other-pkg', prefixDir: { - 'package.json': { name: 'foo', version: '1.0.0' }, + 'package.json': { name: '@npmcli/foo', version: '1.0.0' }, }, otherDirs: { 'other-pkg': { - 'package.json': { name: 'foo', version: '2.0.0' }, + 'package.json': { name: '@npmcli/foo', version: '2.0.0' }, }, }, exec: [], }) - t.match(output, 'foo') + t.match(output, '@npmcli/foo') t.match(output, /-\s*"version": "2\.0\.0"/) t.match(output, /\+\s*"version": "1\.0\.0"/) }) diff --git a/test/lib/commands/dist-tag.js b/test/lib/commands/dist-tag.js index 4cc241f74582d..1c63ce497d3fb 100644 --- a/test/lib/commands/dist-tag.js +++ b/test/lib/commands/dist-tag.js @@ -77,22 +77,15 @@ const mockDist = async (t, { ...npmOpts } = {}) => { const mock = await mockNpm(t, { ...npmOpts, + command: 'dist-tag', mocks: { 'npm-registry-fetch': Object.assign(nrf, realFetch, { json: getTag }), }, }) - const usage = await mock.npm.cmd('dist-tag').then(c => c.usage) - return { ...mock, - distTag: { - exec: (args) => mock.npm.exec('dist-tag', args), - usage, - completion: (remain) => mock.npm.cmd('dist-tag').then(c => c.completion({ - conf: { argv: { remain } }, - })), - }, + distTag: mock['dist-tag'], fetchOpts: () => fetchOpts, result: () => mock.joinedOutput(), logs: () => { @@ -365,10 +358,10 @@ t.test('remove missing pkg name', async t => { t.test('completion', async t => { const { distTag } = await mockDist(t) - const match = distTag.completion(['npm', 'dist-tag']) + const match = distTag.completion({ conf: { argv: { remain: ['npm', 'dist-tag'] } } }) t.resolveMatch(match, ['add', 'rm', 'ls'], 'should list npm dist-tag commands for completion') - const noMatch = distTag.completion(['npm', 'dist-tag', 'foobar']) + const noMatch = distTag.completion({ conf: { argv: { remain: ['npm', 'dist-tag', 'foobar'] } } }) t.resolveMatch(noMatch, []) }) diff --git a/test/lib/commands/doctor.js b/test/lib/commands/doctor.js index d1a88299e69ae..1682a6cccfa48 100644 --- a/test/lib/commands/doctor.js +++ b/test/lib/commands/doctor.js @@ -4,7 +4,7 @@ const path = require('path') const { load: loadMockNpm } = require('../../fixtures/mock-npm') const tnock = require('../../fixtures/tnock.js') -const mockGlobals = require('../../fixtures/mock-globals') +const mockGlobals = require('@npmcli/mock-globals') const { cleanCwd, cleanDate } = require('../../fixtures/clean-snapshot.js') const cleanCacheSha = (str) => diff --git a/test/lib/commands/explain.js b/test/lib/commands/explain.js index 79c917a1cd452..f4d898797bcbe 100644 --- a/test/lib/commands/explain.js +++ b/test/lib/commands/explain.js @@ -4,6 +4,7 @@ const mockNpm = require('../../fixtures/mock-npm.js') const mockExplain = async (t, opts) => { const mock = await mockNpm(t, { + command: 'explain', mocks: { // keep the snapshots pared down a bit, since this has its own tests. '{LIB}/utils/explain-dep.js': { @@ -16,15 +17,7 @@ const mockExplain = async (t, opts) => { ...opts, }) - const usage = await mock.npm.cmd('explain').then(c => c.usage) - - return { - ...mock, - explain: { - usage, - exec: (args) => mock.npm.exec('explain', args), - }, - } + return mock } t.test('no args throws usage', async t => { diff --git a/test/lib/commands/explore.js b/test/lib/commands/explore.js index 786a34a8e2988..6988dca90fbfb 100644 --- a/test/lib/commands/explore.js +++ b/test/lib/commands/explore.js @@ -3,18 +3,20 @@ const mockNpm = require('../../fixtures/mock-npm') const { cleanCwd } = require('../../fixtures/clean-snapshot') const mockExplore = async (t, exec, { - RPJ_ERROR = null, + PJ_ERROR = null, RUN_SCRIPT_ERROR = null, RUN_SCRIPT_EXIT_CODE = 0, RUN_SCRIPT_SIGNAL = null, } = {}) => { - let RPJ_CALLED = '' - const mockRPJ = async path => { - if (RPJ_ERROR) { - throw RPJ_ERROR - } - RPJ_CALLED = cleanCwd(path) - return { some: 'package' } + let PJ_CALLED = '' + const mockPJ = { + normalize: async path => { + if (PJ_ERROR) { + throw PJ_ERROR + } + PJ_CALLED = cleanCwd(path) + return { content: { some: 'package' } } + }, } let RUN_SCRIPT_EXEC = null @@ -41,7 +43,7 @@ const mockExplore = async (t, exec, { const mock = await mockNpm(t, { mocks: { - 'read-package-json-fast': mockRPJ, + '@npmcli/package-json': mockPJ, '@npmcli/run-script': mockRunScript, }, config: { @@ -53,7 +55,7 @@ const mockExplore = async (t, exec, { return { ...mock, - RPJ_CALLED, + PJ_CALLED, RUN_SCRIPT_EXEC, output: cleanCwd(mock.joinedOutput()).trim(), } @@ -62,11 +64,11 @@ const mockExplore = async (t, exec, { t.test('basic interactive', async t => { const { output, - RPJ_CALLED, + PJ_CALLED, RUN_SCRIPT_EXEC, } = await mockExplore(t, ['pkg']) - t.match(RPJ_CALLED, /\/pkg\/package.json$/) + t.ok(PJ_CALLED.endsWith('/pkg')) t.strictSame(RUN_SCRIPT_EXEC, 'shell-command') t.match(output, /Exploring \{CWD\}\/[\w-_/]+\nType 'exit' or \^D when finished/) }) @@ -75,11 +77,11 @@ t.test('interactive tracks exit code', async t => { t.test('code', async t => { const { output, - RPJ_CALLED, + PJ_CALLED, RUN_SCRIPT_EXEC, } = await mockExplore(t, ['pkg'], { RUN_SCRIPT_EXIT_CODE: 99 }) - t.match(RPJ_CALLED, /\/pkg\/package.json$/) + t.ok(PJ_CALLED.endsWith('/pkg')) t.strictSame(RUN_SCRIPT_EXEC, 'shell-command') t.match(output, /Exploring \{CWD\}\/[\w-_/]+\nType 'exit' or \^D when finished/) @@ -123,11 +125,11 @@ t.test('interactive tracks exit code', async t => { t.test('basic non-interactive', async t => { const { output, - RPJ_CALLED, + PJ_CALLED, RUN_SCRIPT_EXEC, } = await mockExplore(t, ['pkg', 'ls']) - t.match(RPJ_CALLED, /\/pkg\/package.json$/) + t.ok(PJ_CALLED.endsWith('/pkg')) t.strictSame(RUN_SCRIPT_EXEC, 'ls') t.strictSame(output, '') @@ -164,10 +166,10 @@ t.test('usage if no pkg provided', async t => { }) t.test('pkg not installed', async t => { - const RPJ_ERROR = new Error('plurple') + const PJ_ERROR = new Error('plurple') await t.rejects( - mockExplore(t, ['pkg', 'ls'], { RPJ_ERROR }), + mockExplore(t, ['pkg', 'ls'], { PJ_ERROR }), { message: 'plurple' } ) }) diff --git a/test/lib/commands/get.js b/test/lib/commands/get.js index 597cccc3ff0ba..dec634f835172 100644 --- a/test/lib/commands/get.js +++ b/test/lib/commands/get.js @@ -2,10 +2,11 @@ const t = require('tap') const { load: loadMockNpm } = require('../../fixtures/mock-npm') t.test('should retrieve values from config', async t => { - const { joinedOutput, npm } = await loadMockNpm(t) const name = 'editor' const value = 'vigor' - npm.config.set(name, value) + const { joinedOutput, npm } = await loadMockNpm(t, { + config: { [name]: value }, + }) await npm.exec('get', [name]) t.equal( joinedOutput(), diff --git a/test/lib/commands/help-search.js b/test/lib/commands/help-search.js index ce6e5f7cf00b0..8da725fad7692 100644 --- a/test/lib/commands/help-search.js +++ b/test/lib/commands/help-search.js @@ -1,6 +1,5 @@ const t = require('tap') const { load: loadMockNpm } = require('../../fixtures/mock-npm.js') -const chalk = require('chalk') /* eslint-disable max-len */ const docsFixtures = { @@ -70,6 +69,8 @@ t.test('npm help-search long output with color', async t => { }, }) + const chalk = await import('chalk').then(v => v.default) + const highlightedText = chalk.bgBlack.red('help-search') t.equal( output.split('\n').some(line => line.includes(highlightedText)), diff --git a/test/lib/commands/help.js b/test/lib/commands/help.js index e38f1bbce24d4..3fda9fb6e07fd 100644 --- a/test/lib/commands/help.js +++ b/test/lib/commands/help.js @@ -61,18 +61,13 @@ const mockHelp = async (t, { mocks: { '@npmcli/promise-spawn': mockSpawn }, otherDirs: { ...manPages.fixtures }, config, + command: 'help', + exec: execArgs, ...opts, }) - const help = await npm.cmd('help') - const exec = execArgs - ? await npm.exec('help', execArgs) - : (...a) => npm.exec('help', a) - return { npm, - help, - exec, manPages: manPages.pages, getArgs: () => args, ...rest, @@ -80,8 +75,8 @@ const mockHelp = async (t, { } t.test('npm help', async t => { - const { exec, joinedOutput } = await mockHelp(t) - await exec() + const { help, joinedOutput } = await mockHelp(t) + await help.exec() t.match(joinedOutput(), 'npm ', 'showed npm usage') }) @@ -216,17 +211,17 @@ t.test('npm help - works in the presence of strange man pages', async t => { }) t.test('rejects with code', async t => { - const { exec } = await mockHelp(t, { + const { help } = await mockHelp(t, { spawnErr: Object.assign(new Error('errrrr'), { code: 'SPAWN_ERR' }), }) - await t.rejects(exec('whoami'), /help process exited with code: SPAWN_ERR/) + await t.rejects(help.exec(['whoami']), /help process exited with code: SPAWN_ERR/) }) t.test('rejects with no code', async t => { - const { exec } = await mockHelp(t, { + const { help } = await mockHelp(t, { spawnErr: new Error('errrrr'), }) - await t.rejects(exec('whoami'), /errrrr/) + await t.rejects(help.exec(['whoami']), /errrrr/) }) diff --git a/test/lib/commands/hook.js b/test/lib/commands/hook.js index 01da9dc720dae..e4e1214b812f3 100644 --- a/test/lib/commands/hook.js +++ b/test/lib/commands/hook.js @@ -51,6 +51,7 @@ const mockHook = async (t, { hookResponse, ...npmOpts } = {}) => { const mock = await mockNpm(t, { ...npmOpts, + command: 'hook', mocks: { libnpmhook, ...npmOpts.mocks, @@ -60,7 +61,6 @@ const mockHook = async (t, { hookResponse, ...npmOpts } = {}) => { return { ...mock, now, - hook: { exec: (args) => mock.npm.exec('hook', args) }, hookArgs: () => hookArgs, } } diff --git a/test/lib/commands/init.js b/test/lib/commands/init.js index 00caf90d0ec9b..cb708303f405a 100644 --- a/test/lib/commands/init.js +++ b/test/lib/commands/init.js @@ -6,13 +6,12 @@ const { cleanTime } = require('../../fixtures/clean-snapshot') t.cleanSnapshot = cleanTime -const mockNpm = async (t, { noLog, libnpmexec, initPackageJson, packageJson, ...opts } = {}) => { +const mockNpm = async (t, { noLog, libnpmexec, initPackageJson, ...opts } = {}) => { const res = await _mockNpm(t, { ...opts, mocks: { ...(libnpmexec ? { libnpmexec } : {}), ...(initPackageJson ? { 'init-package-json': initPackageJson } : {}), - ...(packageJson ? { '@npmcli/package-json': packageJson } : {}), }, globals: { // init-package-json prints directly to console.log @@ -313,14 +312,7 @@ t.test('workspaces', async t => { await t.test('fail parsing top-level package.json to set workspace', async t => { const { npm } = await mockNpm(t, { prefixDir: { - 'package.json': JSON.stringify({ - name: 'top-level', - }), - }, - packageJson: { - async load () { - throw new Error('ERR') - }, + 'package.json': 'not json[', }, config: { workspace: 'a', yes: true }, noLog: true, @@ -328,8 +320,7 @@ t.test('workspaces', async t => { await t.rejects( npm.exec('init', []), - /ERR/, - 'should exit with error' + { code: 'EJSONPARSE' } ) }) diff --git a/test/lib/commands/install.js b/test/lib/commands/install.js index 1be42d6e6125f..f40b62edde17c 100644 --- a/test/lib/commands/install.js +++ b/test/lib/commands/install.js @@ -355,31 +355,32 @@ t.test('completion', async t => { t.test('location detection and audit', async (t) => { await t.test('audit false without package.json', async t => { const { npm } = await loadMockNpm(t, { + command: 'install', prefixDir: { // no package.json 'readme.txt': 'just a file', 'other-dir': { a: 'a' }, }, }) - const install = await npm.cmd('install') - t.equal(install.npm.config.get('location'), 'user') - t.equal(install.npm.config.get('audit'), false) + t.equal(npm.config.get('location'), 'user') + t.equal(npm.config.get('audit'), false) }) await t.test('audit true with package.json', async t => { const { npm } = await loadMockNpm(t, { + command: 'install', prefixDir: { 'package.json': '{ "name": "testpkg", "version": "1.0.0" }', 'readme.txt': 'just a file', }, }) - const install = await npm.cmd('install') - t.equal(install.npm.config.get('location'), 'user') - t.equal(install.npm.config.get('audit'), true) + t.equal(npm.config.get('location'), 'user') + t.equal(npm.config.get('audit'), true) }) await t.test('audit true without package.json when set', async t => { const { npm } = await loadMockNpm(t, { + command: 'install', prefixDir: { // no package.json 'readme.txt': 'just a file', @@ -389,13 +390,13 @@ t.test('location detection and audit', async (t) => { audit: true, }, }) - const install = await npm.cmd('install') - t.equal(install.npm.config.get('location'), 'user') - t.equal(install.npm.config.get('audit'), true) + t.equal(npm.config.get('location'), 'user') + t.equal(npm.config.get('audit'), true) }) await t.test('audit true in root config without package.json', async t => { const { npm } = await loadMockNpm(t, { + command: 'install', prefixDir: { // no package.json 'readme.txt': 'just a file', @@ -405,13 +406,13 @@ t.test('location detection and audit', async (t) => { otherDirs: { npmrc: 'audit=true' }, npm: ({ other }) => ({ npmRoot: other }), }) - const install = await npm.cmd('install') - t.equal(install.npm.config.get('location'), 'user') - t.equal(install.npm.config.get('audit'), true) + t.equal(npm.config.get('location'), 'user') + t.equal(npm.config.get('audit'), true) }) await t.test('test for warning when --global & --audit', async t => { const { npm, logs } = await loadMockNpm(t, { + command: 'install', prefixDir: { // no package.json 'readme.txt': 'just a file', @@ -422,9 +423,8 @@ t.test('location detection and audit', async (t) => { global: true, }, }) - const install = await npm.cmd('install') - t.equal(install.npm.config.get('location'), 'user') - t.equal(install.npm.config.get('audit'), true) + t.equal(npm.config.get('location'), 'user') + t.equal(npm.config.get('audit'), true) t.equal(logs.warn[0][0], 'config') t.equal(logs.warn[0][1], 'includes both --global and --audit, which is currently unsupported.') }) diff --git a/test/lib/commands/link.js b/test/lib/commands/link.js index feae75a4b9096..65792fd141acb 100644 --- a/test/lib/commands/link.js +++ b/test/lib/commands/link.js @@ -10,6 +10,7 @@ t.cleanSnapshot = (str) => cleanCwd(str) const mockLink = async (t, { globalPrefixDir, ...opts } = {}) => { const mock = await mockNpm(t, { ...opts, + command: 'link', globalPrefixDir, mocks: { ...opts.mocks, @@ -36,10 +37,6 @@ const mockLink = async (t, { globalPrefixDir, ...opts } = {}) => { return { ...mock, - link: { - exec: (args = []) => mock.npm.exec('link', args), - completion: (o) => mock.npm.cmd('link').then(c => c.completion(o)), - }, printLinks, } } diff --git a/test/lib/commands/login.js b/test/lib/commands/login.js index 63666670712ef..b42d3001ebb90 100644 --- a/test/lib/commands/login.js +++ b/test/lib/commands/login.js @@ -4,26 +4,47 @@ const path = require('path') const ini = require('ini') const { load: loadMockNpm } = require('../../fixtures/mock-npm.js') -const mockGlobals = require('../../fixtures/mock-globals.js') +const mockGlobals = require('@npmcli/mock-globals') const MockRegistry = require('@npmcli/mock-registry') const stream = require('stream') +const mockLogin = async (t, { stdin: stdinLines, registry: registryUrl, ...options } = {}) => { + let stdin + if (stdinLines) { + stdin = new stream.PassThrough() + for (const l of stdinLines) { + stdin.write(l + '\n') + } + mockGlobals(t, { + 'process.stdin': stdin, + 'process.stdout': new stream.PassThrough(), // to quiet readline + }, { replace: true }) + } + const mock = await loadMockNpm(t, { + ...options, + command: 'login', + }) + const registry = new MockRegistry({ + tap: t, + registry: registryUrl ?? mock.npm.config.get('registry'), + }) + return { + registry, + stdin, + rc: () => ini.parse(fs.readFileSync(path.join(mock.home, '.npmrc'), 'utf8')), + ...mock, + } +} + t.test('usage', async t => { - const { npm } = await loadMockNpm(t) - const login = await npm.cmd('login') + const { login } = await loadMockNpm(t, { command: 'login' }) t.match(login.usage, 'login', 'usage has command name in it') }) t.test('legacy', t => { t.test('basic login', async t => { - const stdin = new stream.PassThrough() - stdin.write('test-user\n') - stdin.write('test-password\n') - mockGlobals(t, { - 'process.stdin': stdin, - 'process.stdout': new stream.PassThrough(), // to quiet readline - }, { replace: true }) - const { npm, home } = await loadMockNpm(t, { + const { npm, registry, login, rc } = await mockLogin(t, { + stdin: ['test-user', 'test-password'], config: { 'auth-type': 'legacy' }, homeDir: { '.npmrc': [ @@ -33,66 +54,45 @@ t.test('legacy', t => { ].join('\n'), }, }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), - }) registry.couchlogin({ username: 'test-user', password: 'test-password', token: 'npm_test-token', }) - await npm.exec('login', []) + await login.exec([]) t.same(npm.config.get('//registry.npmjs.org/:_authToken'), 'npm_test-token') - const rc = ini.parse(fs.readFileSync(path.join(home, '.npmrc'), 'utf8')) - t.same(rc, { + t.same(rc(), { '//registry.npmjs.org/:_authToken': 'npm_test-token', email: 'test-email-old@npmjs.org', }, 'should only have token and un-nerfed old email') }) t.test('scoped login default registry', async t => { - const stdin = new stream.PassThrough() - stdin.write('test-user\n') - stdin.write('test-password\n') - mockGlobals(t, { - 'process.stdin': stdin, - 'process.stdout': new stream.PassThrough(), // to quiet readline - }, { replace: true }) - const { npm, home } = await loadMockNpm(t, { + const { npm, registry, login, rc } = await mockLogin(t, { + stdin: ['test-user', 'test-password'], config: { 'auth-type': 'legacy', scope: '@npmcli', }, }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), - }) registry.couchlogin({ username: 'test-user', password: 'test-password', token: 'npm_test-token', }) - await npm.exec('login', []) + await login.exec([]) t.same(npm.config.get('//registry.npmjs.org/:_authToken'), 'npm_test-token') t.same(npm.config.get('@npmcli:registry'), 'https://registry.npmjs.org/') - const rc = ini.parse(fs.readFileSync(path.join(home, '.npmrc'), 'utf8')) - t.same(rc, { + t.same(rc(), { '//registry.npmjs.org/:_authToken': 'npm_test-token', '@npmcli:registry': 'https://registry.npmjs.org/', }, 'should only have token and scope:registry') }) t.test('scoped login scoped registry', async t => { - const stdin = new stream.PassThrough() - stdin.write('test-user\n') - stdin.write('test-password\n') - mockGlobals(t, { - 'process.stdin': stdin, - 'process.stdout': new stream.PassThrough(), // to quiet readline - }, { replace: true }) - const { npm, home } = await loadMockNpm(t, { + const { npm, registry, login, rc } = await mockLogin(t, { + stdin: ['test-user', 'test-password'], + registry: 'https://diff-registry.npmjs.org', config: { 'auth-type': 'legacy', scope: '@npmcli', @@ -101,20 +101,15 @@ t.test('legacy', t => { '.npmrc': '@npmcli:registry=https://diff-registry.npmjs.org', }, }) - const registry = new MockRegistry({ - tap: t, - registry: 'https://diff-registry.npmjs.org', - }) registry.couchlogin({ username: 'test-user', password: 'test-password', token: 'npm_test-token', }) - await npm.exec('login', []) + await login.exec([]) t.same(npm.config.get('//diff-registry.npmjs.org/:_authToken'), 'npm_test-token') t.same(npm.config.get('@npmcli:registry'), 'https://diff-registry.npmjs.org') - const rc = ini.parse(fs.readFileSync(path.join(home, '.npmrc'), 'utf8')) - t.same(rc, { + t.same(rc(), { '@npmcli:registry': 'https://diff-registry.npmjs.org', '//diff-registry.npmjs.org/:_authToken': 'npm_test-token', }, 'should only have token and scope:registry') @@ -124,51 +119,32 @@ t.test('legacy', t => { t.test('web', t => { t.test('basic login', async t => { - const { npm, home } = await loadMockNpm(t, { + const { npm, registry, login, rc } = await mockLogin(t, { config: { 'auth-type': 'web' }, }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), - }) registry.weblogin({ token: 'npm_test-token' }) - await npm.exec('login', []) + await login.exec([]) t.same(npm.config.get('//registry.npmjs.org/:_authToken'), 'npm_test-token') - const rc = ini.parse(fs.readFileSync(path.join(home, '.npmrc'), 'utf8')) - t.same(rc, { + t.same(rc(), { '//registry.npmjs.org/:_authToken': 'npm_test-token', }) }) t.test('server error', async t => { - const { npm } = await loadMockNpm(t, { + const { registry, login } = await mockLogin(t, { config: { 'auth-type': 'web' }, }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), - }) registry.nock.post(registry.fullPath('/-/v1/login')) .reply(503, {}) await t.rejects( - npm.exec('login', []), + login.exec([]), { message: /503/ } ) }) t.test('fallback', async t => { - const stdin = new stream.PassThrough() - stdin.write('test-user\n') - stdin.write('test-password\n') - mockGlobals(t, { - 'process.stdin': stdin, - 'process.stdout': new stream.PassThrough(), // to quiet readline - }, { replace: true }) - const { npm } = await loadMockNpm(t, { + const { npm, registry, login } = await mockLogin(t, { + stdin: ['test-user', 'test-password'], config: { 'auth-type': 'web' }, }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), - }) registry.nock.post(registry.fullPath('/-/v1/login')) .reply(404, {}) registry.couchlogin({ @@ -176,7 +152,7 @@ t.test('web', t => { password: 'test-password', token: 'npm_test-token', }) - await npm.exec('login', []) + await login.exec([]) t.same(npm.config.get('//registry.npmjs.org/:_authToken'), 'npm_test-token') }) t.end() diff --git a/test/lib/commands/logout.js b/test/lib/commands/logout.js index 0043bb4c57922..4ff21665f3035 100644 --- a/test/lib/commands/logout.js +++ b/test/lib/commands/logout.js @@ -8,6 +8,7 @@ const mockLogout = async (t, { userRc = [], ...npmOpts } = {}) => { let result = null const mock = await mockNpm(t, { + command: 'logout', mocks: { // XXX: refactor to use mock registry 'npm-registry-fetch': Object.assign(async (url, opts) => { @@ -22,7 +23,6 @@ const mockLogout = async (t, { userRc = [], ...npmOpts } = {}) => { return { ...mock, - logout: { exec: (args) => mock.npm.exec('logout', args) }, result: () => result, // get only the message portion of the verbose log from the command logMsg: () => mock.logs.verbose.find(l => l[0] === 'logout')[1], diff --git a/test/lib/commands/org.js b/test/lib/commands/org.js index d3700304328ee..511251e1bb096 100644 --- a/test/lib/commands/org.js +++ b/test/lib/commands/org.js @@ -30,6 +30,7 @@ const mockOrg = async (t, { orgSize = 1, orgList = {}, ...npmOpts } = {}) => { const mock = await mockNpm(t, { ...npmOpts, + command: 'org', mocks: { libnpmorg, ...npmOpts.mocks, @@ -38,11 +39,6 @@ const mockOrg = async (t, { orgSize = 1, orgList = {}, ...npmOpts } = {}) => { return { ...mock, - org: { - exec: (args) => mock.npm.exec('org', args), - completion: (arg) => mock.npm.cmd('org').then(c => c.completion(arg)), - usage: () => mock.npm.cmd('org').then(c => c.usage), - }, setArgs: () => setArgs, rmArgs: () => rmArgs, lsArgs: () => lsArgs, @@ -77,7 +73,7 @@ t.test('completion', async t => { t.test('npm org - invalid subcommand', async t => { const { org } = await mockOrg(t) - await t.rejects(org.exec(['foo']), org.usage()) + await t.rejects(org.exec(['foo']), org.usage) }) t.test('npm org add', async t => { diff --git a/test/lib/commands/outdated.js b/test/lib/commands/outdated.js index 02f2067c5480e..7becc79d62e17 100644 --- a/test/lib/commands/outdated.js +++ b/test/lib/commands/outdated.js @@ -234,6 +234,7 @@ const fixtures = { const mockNpm = async (t, { prefixDir, ...opts } = {}) => { const res = await _mockNpm(t, { + command: 'outdated', mocks: { pacote: { packument, @@ -255,151 +256,150 @@ const mockNpm = async (t, { prefixDir, ...opts } = {}) => { return { ...res, registry, - exec: (args) => res.npm.exec('outdated', args), } } t.test('should display outdated deps', async t => { await t.test('outdated global', async t => { - const { exec, joinedOutput } = await mockNpm(t, { + const { outdated, joinedOutput } = await mockNpm(t, { globalPrefixDir: fixtures.global, config: { global: true }, }) - await exec([]) + await outdated.exec([]) t.equal(process.exitCode, 1) t.matchSnapshot(joinedOutput()) }) await t.test('outdated', async t => { - const { exec, joinedOutput } = await mockNpm(t, { + const { outdated, joinedOutput } = await mockNpm(t, { prefixDir: fixtures.local, config: { color: 'always', }, }) - await exec([]) + await outdated.exec([]) t.equal(process.exitCode, 1) t.matchSnapshot(joinedOutput()) }) await t.test('outdated --omit=dev', async t => { - const { exec, joinedOutput } = await mockNpm(t, { + const { outdated, joinedOutput } = await mockNpm(t, { prefixDir: fixtures.local, config: { omit: ['dev'], color: 'always', }, }) - await exec([]) + await outdated.exec([]) t.equal(process.exitCode, 1) t.matchSnapshot(joinedOutput()) }) await t.test('outdated --omit=dev --omit=peer', async t => { - const { exec, joinedOutput } = await mockNpm(t, { + const { outdated, joinedOutput } = await mockNpm(t, { prefixDir: fixtures.local, config: { omit: ['dev', 'peer'], color: 'always', }, }) - await exec([]) + await outdated.exec([]) t.equal(process.exitCode, 1) t.matchSnapshot(joinedOutput()) }) await t.test('outdated --omit=prod', async t => { - const { exec, joinedOutput } = await mockNpm(t, { + const { outdated, joinedOutput } = await mockNpm(t, { prefixDir: fixtures.local, config: { omit: ['prod'], color: 'always', }, }) - await exec([]) + await outdated.exec([]) t.equal(process.exitCode, 1) t.matchSnapshot(joinedOutput()) }) await t.test('outdated --long', async t => { - const { exec, joinedOutput } = await mockNpm(t, { + const { outdated, joinedOutput } = await mockNpm(t, { prefixDir: fixtures.local, config: { long: true, }, }) - await exec([]) + await outdated.exec([]) t.equal(process.exitCode, 1) t.matchSnapshot(joinedOutput()) }) await t.test('outdated --json', async t => { - const { exec, joinedOutput } = await mockNpm(t, { + const { outdated, joinedOutput } = await mockNpm(t, { prefixDir: fixtures.local, config: { json: true, }, }) - await exec([]) + await outdated.exec([]) t.equal(process.exitCode, 1) t.matchSnapshot(joinedOutput()) }) await t.test('outdated --json --long', async t => { - const { exec, joinedOutput } = await mockNpm(t, { + const { outdated, joinedOutput } = await mockNpm(t, { prefixDir: fixtures.local, config: { json: true, long: true, }, }) - await exec([]) + await outdated.exec([]) t.equal(process.exitCode, 1) t.matchSnapshot(joinedOutput()) }) await t.test('outdated --parseable', async t => { - const { exec, joinedOutput } = await mockNpm(t, { + const { outdated, joinedOutput } = await mockNpm(t, { prefixDir: fixtures.local, config: { parseable: true, }, }) - await exec([]) + await outdated.exec([]) t.equal(process.exitCode, 1) t.matchSnapshot(joinedOutput()) }) await t.test('outdated --parseable --long', async t => { - const { exec, joinedOutput } = await mockNpm(t, { + const { outdated, joinedOutput } = await mockNpm(t, { prefixDir: fixtures.local, config: { parseable: true, long: true, }, }) - await exec([]) + await outdated.exec([]) t.equal(process.exitCode, 1) t.matchSnapshot(joinedOutput()) }) await t.test('outdated --all', async t => { - const { exec, joinedOutput } = await mockNpm(t, { + const { outdated, joinedOutput } = await mockNpm(t, { prefixDir: fixtures.local, config: { all: true, }, }) - await exec([]) + await outdated.exec([]) t.equal(process.exitCode, 1) t.matchSnapshot(joinedOutput()) }) await t.test('outdated specific dep', async t => { - const { exec, joinedOutput } = await mockNpm(t, { + const { outdated, joinedOutput } = await mockNpm(t, { prefixDir: fixtures.local, }) - await exec(['cat']) + await outdated.exec(['cat']) t.equal(process.exitCode, 1) t.matchSnapshot(joinedOutput()) }) @@ -424,11 +424,11 @@ t.test('should return if no outdated deps', async t => { }, } - const { exec, joinedOutput } = await mockNpm(t, { + const { outdated, joinedOutput } = await mockNpm(t, { prefixDir: testDir, }) - await exec([]) + await outdated.exec([]) t.equal(joinedOutput(), '', 'no logs') }) @@ -451,11 +451,11 @@ t.test('throws if error with a dep', async t => { }, } - const { exec } = await mockNpm(t, { + const { outdated } = await mockNpm(t, { prefixDir: testDir, }) - await t.rejects(exec([]), 'There is an error with this package.') + await t.rejects(outdated.exec([]), 'There is an error with this package.') }) t.test('should skip missing non-prod deps', async t => { @@ -470,11 +470,11 @@ t.test('should skip missing non-prod deps', async t => { node_modules: {}, } - const { exec, joinedOutput } = await mockNpm(t, { + const { outdated, joinedOutput } = await mockNpm(t, { prefixDir: testDir, }) - await exec([]) + await outdated.exec([]) t.equal(joinedOutput(), '', 'no logs') }) @@ -498,10 +498,10 @@ t.test('should skip invalid pkg ranges', async t => { }, } - const { exec, joinedOutput } = await mockNpm(t, { + const { outdated, joinedOutput } = await mockNpm(t, { prefixDir: testDir, }) - await exec([]) + await outdated.exec([]) t.equal(joinedOutput(), '', 'no logs') }) @@ -524,21 +524,21 @@ t.test('should skip git specs', async t => { }, } - const { exec, joinedOutput } = await mockNpm(t, { + const { outdated, joinedOutput } = await mockNpm(t, { prefixDir: testDir, }) - await exec([]) + await outdated.exec([]) t.equal(joinedOutput(), '', 'no logs') }) t.test('workspaces', async t => { const mockWorkspaces = async (t, { exitCode = 1, ...config } = {}) => { - const { exec, joinedOutput } = await mockNpm(t, { + const { outdated, joinedOutput } = await mockNpm(t, { prefixDir: fixtures.workspaces, config, }) - await exec([]) + await outdated.exec([]) t.matchSnapshot(joinedOutput(), 'output') t.equal(process.exitCode, exitCode ?? undefined) @@ -603,10 +603,10 @@ t.test('aliases', async t => { }, } - const { exec, joinedOutput } = await mockNpm(t, { + const { outdated, joinedOutput } = await mockNpm(t, { prefixDir: testDir, }) - await exec([]) + await outdated.exec([]) t.matchSnapshot(joinedOutput(), 'should display aliased outdated dep output') t.equal(process.exitCode, 1) diff --git a/test/lib/commands/owner.js b/test/lib/commands/owner.js index f9399a60cdf81..9329e8985e60c 100644 --- a/test/lib/commands/owner.js +++ b/test/lib/commands/owner.js @@ -613,9 +613,10 @@ t.test('workspaces', async t => { }) t.test('completion', async t => { + const mockCompletion = (t, opts) => loadMockNpm(t, { command: 'owner', ...opts }) + t.test('basic commands', async t => { - const { npm } = await loadMockNpm(t) - const owner = await npm.cmd('owner') + const { owner } = await mockCompletion(t) const testComp = async (argv, expect) => { const res = await owner.completion({ conf: { argv: { remain: argv } } }) t.strictSame(res, expect, argv.join(' ')) @@ -631,10 +632,9 @@ t.test('completion', async t => { }) t.test('completion npm owner rm', async t => { - const { npm } = await loadMockNpm(t, { + const { npm, owner } = await mockCompletion(t, { prefixDir: { 'package.json': JSON.stringify({ name: packageName }) }, }) - const owner = await npm.cmd('owner') const registry = new MockRegistry({ tap: t, registry: npm.config.get('registry'), @@ -649,26 +649,23 @@ t.test('completion', async t => { }) t.test('completion npm owner rm no cwd package', async t => { - const { npm } = await loadMockNpm(t) - const owner = await npm.cmd('owner') + const { owner } = await mockCompletion(t) const res = await owner.completion({ conf: { argv: { remain: ['npm', 'owner', 'rm'] } } }) t.strictSame(res, [], 'should have no owners to autocomplete if not cwd package') }) t.test('completion npm owner rm global', async t => { - const { npm } = await loadMockNpm(t, { + const { owner } = await mockCompletion(t, { config: { global: true }, }) - const owner = await npm.cmd('owner') const res = await owner.completion({ conf: { argv: { remain: ['npm', 'owner', 'rm'] } } }) t.strictSame(res, [], 'should have no owners to autocomplete if global') }) t.test('completion npm owner rm no owners found', async t => { - const { npm } = await loadMockNpm(t, { + const { npm, owner } = await mockCompletion(t, { prefixDir: { 'package.json': JSON.stringify({ name: packageName }) }, }) - const owner = await npm.cmd('owner') const registry = new MockRegistry({ tap: t, registry: npm.config.get('registry'), diff --git a/test/lib/commands/pack.js b/test/lib/commands/pack.js index 3e7c0225c3068..61296cc93a53a 100644 --- a/test/lib/commands/pack.js +++ b/test/lib/commands/pack.js @@ -28,8 +28,8 @@ t.test('follows pack-destination config', async t => { }), 'tar-destination': {}, }, + config: ({ prefix }) => ({ 'pack-destination': path.join(prefix, 'tar-destination') }), }) - npm.config.set('pack-destination', path.join(npm.prefix, 'tar-destination')) await npm.exec('pack', []) const filename = 'test-package-1.0.0.tgz' t.strictSame(outputs, [[filename]]) @@ -59,8 +59,8 @@ t.test('should log output as valid json', async t => { version: '1.0.0', }), }, + config: { json: true }, }) - npm.config.set('json', true) await npm.exec('pack', []) const filename = 'test-package-1.0.0.tgz' t.matchSnapshot(outputs.map(JSON.parse), 'outputs as json') @@ -76,8 +76,8 @@ t.test('should log scoped package output as valid json', async t => { version: '1.0.0', }), }, + config: { json: true }, }) - npm.config.set('json', true) await npm.exec('pack', []) const filename = 'myscope-test-package-1.0.0.tgz' t.matchSnapshot(outputs.map(JSON.parse), 'outputs as json') @@ -93,8 +93,8 @@ t.test('dry run', async t => { version: '1.0.0', }), }, + config: { 'dry-run': true }, }) - npm.config.set('dry-run', true) await npm.exec('pack', []) const filename = 'test-package-1.0.0.tgz' t.strictSame(outputs, [[filename]]) diff --git a/test/lib/commands/prefix.js b/test/lib/commands/prefix.js index e8295cf6a5b3c..4fc348843fa25 100644 --- a/test/lib/commands/prefix.js +++ b/test/lib/commands/prefix.js @@ -2,7 +2,7 @@ const t = require('tap') const { load: loadMockNpm } = require('../../fixtures/mock-npm') t.test('prefix', async t => { - const { joinedOutput, npm } = await loadMockNpm(t, { load: false }) + const { joinedOutput, npm } = await loadMockNpm(t) await npm.exec('prefix', []) t.equal( joinedOutput(), diff --git a/test/lib/commands/profile.js b/test/lib/commands/profile.js index 1152acfdc5c46..784523f7ccd8a 100644 --- a/test/lib/commands/profile.js +++ b/test/lib/commands/profile.js @@ -24,6 +24,7 @@ const mockProfile = async (t, { npmProfile, readUserInfo, qrcode, config, ...opt const mock = await mockNpm(t, { ...opts, + command: 'profile', config: { color: false, ...config, @@ -37,10 +38,6 @@ const mockProfile = async (t, { npmProfile, readUserInfo, qrcode, config, ...opt return { ...mock, result: () => mock.joinedOutput(), - profile: { - exec: (args) => mock.npm.exec('profile', args), - usage: () => mock.npm.cmd('profile').then(c => c.usage), - }, } } @@ -61,7 +58,7 @@ const userProfile = { t.test('no args', async t => { const { profile } = await mockProfile(t) - await t.rejects(profile.exec([]), await profile.usage()) + await t.rejects(profile.exec([]), await profile.usage) }) t.test('profile get no args', async t => { @@ -1081,8 +1078,7 @@ t.test('unknown subcommand', async t => { t.test('completion', async t => { const testComp = async (t, { argv, expect, title } = {}) => { - const { npm } = await mockProfile(t) - const profile = await npm.cmd('profile') + const { profile } = await mockProfile(t) t.resolveMatch(profile.completion({ conf: { argv: { remain: argv } } }), expect, title) } @@ -1114,8 +1110,7 @@ t.test('completion', async t => { }) t.test('npm profile unknown subcommand autocomplete', async t => { - const { npm } = await mockProfile(t) - const profile = await npm.cmd('profile') + const { profile } = await mockProfile(t) t.rejects( profile.completion({ conf: { argv: { remain: ['npm', 'profile', 'asdf'] } } }), { message: 'asdf not recognized' }, diff --git a/test/lib/commands/prune.js b/test/lib/commands/prune.js index 81245bcfca167..65cfba5e5c00a 100644 --- a/test/lib/commands/prune.js +++ b/test/lib/commands/prune.js @@ -4,7 +4,6 @@ const { load: loadMockNpm } = require('../../fixtures/mock-npm') t.test('should prune using Arborist', async (t) => { t.plan(4) const { npm } = await loadMockNpm(t, { - load: false, mocks: { '@npmcli/arborist': function (args) { t.ok(args, 'gets options object') diff --git a/test/lib/commands/publish.js b/test/lib/commands/publish.js index 39696066130f9..820760bb5704d 100644 --- a/test/lib/commands/publish.js +++ b/test/lib/commands/publish.js @@ -172,8 +172,7 @@ t.test('dry-run', async t => { }) t.test('shows usage with wrong set of arguments', async t => { - const { npm } = await loadMockNpm(t) - const publish = await npm.cmd('publish') + const { publish } = await loadMockNpm(t, { command: 'publish' }) await t.rejects(publish.exec(['a', 'b', 'c']), publish.usage) }) @@ -720,3 +719,54 @@ t.test('public access', async t => { t.matchSnapshot(joinedOutput(), 'new package version') t.matchSnapshot(logs.notice) }) + +t.test('manifest', async t => { + // https://github.com/npm/cli/pull/6470#issuecomment-1571234863 + + // snapshot test that was generated against v9.6.7 originally to ensure our + // own manifest does not change unexpectedly when publishing. this test + // asserts a bunch of keys are there that will change often and then snapshots + // the rest of the manifest. + + const root = path.resolve(__dirname, '../../..') + const npmPkg = require(path.join(root, 'package.json')) + + t.cleanSnapshot = (s) => s.replace(new RegExp(npmPkg.version, 'g'), '{VERSION}') + + let manifest = null + const { npm } = await loadMockNpm(t, { + config: { + ...auth, + }, + chdir: () => root, + mocks: { + libnpmpublish: { + publish: (m) => manifest = m, + }, + }, + }) + await npm.exec('publish', []) + + const okKeys = [ + 'contributors', + 'bundleDependencies', + 'dependencies', + 'devDependencies', + 'templateOSS', + 'scripts', + 'tap', + 'readme', + 'gitHead', + 'engines', + 'workspaces', + ] + + for (const k of okKeys) { + t.ok(manifest[k], k) + delete manifest[k] + } + + manifest.man.sort() + + t.matchSnapshot(manifest, 'manifest') +}) diff --git a/test/lib/commands/root.js b/test/lib/commands/root.js index a886b30c3ee48..506e2bc04eb84 100644 --- a/test/lib/commands/root.js +++ b/test/lib/commands/root.js @@ -2,7 +2,7 @@ const t = require('tap') const { load: loadMockNpm } = require('../../fixtures/mock-npm') t.test('prefix', async (t) => { - const { joinedOutput, npm } = await loadMockNpm(t, { load: false }) + const { joinedOutput, npm } = await loadMockNpm(t) await npm.exec('root', []) t.equal( joinedOutput(), diff --git a/test/lib/commands/run-script.js b/test/lib/commands/run-script.js index 6e2bf22adddcf..cb54a7f51e900 100644 --- a/test/lib/commands/run-script.js +++ b/test/lib/commands/run-script.js @@ -11,6 +11,7 @@ const mockRs = async (t, { windows = false, runScript, ...opts } = {}) => { const mock = await mockNpm(t, { ...opts, + command: 'run-script', mocks: { '@npmcli/run-script': Object.assign( async rs => { @@ -28,18 +29,17 @@ const mockRs = async (t, { windows = false, runScript, ...opts } = {}) => { return { ...mock, RUN_SCRIPTS: () => RUN_SCRIPTS, - runScript: { exec: (args) => mock.npm.exec('run-script', args) }, + runScript: mock['run-script'], cleanLogs: () => mock.logs.error.flat().map(v => v.toString()).map(cleanCwd), } } t.test('completion', async t => { const completion = async (t, remain, pkg, isFish = false) => { - const { npm } = await mockRs(t, + const { runScript } = await mockRs(t, pkg ? { prefixDir: { 'package.json': JSON.stringify(pkg) } } : {} ) - const cmd = await npm.cmd('run-script') - return cmd.completion({ conf: { argv: { remain } }, isFish }) + return runScript.completion({ conf: { argv: { remain } }, isFish }) } t.test('already have a script name', async t => { diff --git a/test/lib/commands/stars.js b/test/lib/commands/stars.js index 124d2d344d8da..d92ced950291f 100644 --- a/test/lib/commands/stars.js +++ b/test/lib/commands/stars.js @@ -6,6 +6,8 @@ const noop = () => {} const mockStars = async (t, { npmFetch = noop, exec = true, ...opts }) => { const mock = await mockNpm(t, { + command: 'stars', + exec, mocks: { 'npm-registry-fetch': Object.assign(noop, realFetch, { json: npmFetch }), '{LIB}/utils/get-identity.js': async () => 'foo', @@ -13,16 +15,9 @@ const mockStars = async (t, { npmFetch = noop, exec = true, ...opts }) => { ...opts, }) - const stars = { exec: (args) => mock.npm.exec('stars', args) } - - if (exec) { - await stars.exec(Array.isArray(exec) ? exec : []) - mock.result = mock.joinedOutput() - } - return { ...mock, - stars, + result: mock.stars.output, logs: () => mock.logs.filter(l => l[1] === 'stars').map(l => l[2]), } } @@ -45,7 +40,7 @@ t.test('no args', async t => { } } - const { result } = await mockStars(t, { npmFetch, exec: true }) + const { result } = await mockStars(t, { npmFetch }) t.matchSnapshot( result, @@ -122,7 +117,7 @@ t.test('unexpected error', async t => { t.test('no pkg starred', async t => { const npmFetch = async () => ({ rows: [] }) - const { logs } = await mockStars(t, { npmFetch, exec: true }) + const { logs } = await mockStars(t, { npmFetch }) t.strictSame( logs(), diff --git a/test/lib/commands/team.js b/test/lib/commands/team.js index a13a56d986e35..1a5480293edc9 100644 --- a/test/lib/commands/team.js +++ b/test/lib/commands/team.js @@ -6,6 +6,7 @@ t.cleanSnapshot = s => s.trim().replace(/\n+/g, '\n') const mockTeam = async (t, { libnpmteam, ...opts } = {}) => { const mock = await mockNpm(t, { ...opts, + command: 'team', mocks: { // XXX: this should be refactored to use the mock registry libnpmteam: libnpmteam || { @@ -21,7 +22,6 @@ const mockTeam = async (t, { libnpmteam, ...opts } = {}) => { return { ...mock, - team: { exec: (args) => mock.npm.exec('team', args) }, result: () => mock.joinedOutput(), } } @@ -384,11 +384,10 @@ t.test('team rm ', async t => { }) t.test('completion', async t => { - const { npm } = await mockTeam(t) - const { completion } = await npm.cmd('team') + const { team } = await mockTeam(t) t.test('npm team autocomplete', async t => { - const res = await completion({ + const res = await team.completion({ conf: { argv: { remain: ['npm', 'team'], @@ -405,7 +404,7 @@ t.test('completion', async t => { t.test('npm team autocomplete', async t => { for (const subcmd of ['create', 'destroy', 'add', 'rm', 'ls']) { - const res = await completion({ + const res = await team.completion({ conf: { argv: { remain: ['npm', 'team', subcmd], @@ -421,7 +420,8 @@ t.test('completion', async t => { }) t.test('npm team unknown subcommand autocomplete', async t => { - t.rejects(completion({ conf: { argv: { remain: ['npm', 'team', 'missing-subcommand'] } } }), + t.rejects( + team.completion({ conf: { argv: { remain: ['npm', 'team', 'missing-subcommand'] } } }), { message: 'missing-subcommand not recognized' }, 'should throw a a not recognized error' ) diff --git a/test/lib/commands/token.js b/test/lib/commands/token.js index 1fd686a4427c9..2bc4af4a81a3d 100644 --- a/test/lib/commands/token.js +++ b/test/lib/commands/token.js @@ -14,6 +14,7 @@ const mockToken = async (t, { profile, getCredentialsByURI, readUserInfo, ...opt const mock = await mockNpm(t, { ...opts, + command: 'token', mocks, }) @@ -22,22 +23,14 @@ const mockToken = async (t, { profile, getCredentialsByURI, readUserInfo, ...opt mock.npm.config.getCredentialsByURI = getCredentialsByURI } - const token = { - exec: (args) => mock.npm.exec('token', args), - } - - return { - ...mock, - token, - } + return mock } t.test('completion', async t => { - const { npm } = await mockToken(t) - const { completion } = await npm.cmd('token') + const { token } = await mockToken(t) const testComp = (argv, expect) => { - t.resolveMatch(completion({ conf: { argv: { remain: argv } } }), expect, argv.join(' ')) + t.resolveMatch(token.completion({ conf: { argv: { remain: argv } } }), expect, argv.join(' ')) } testComp(['npm', 'token'], ['list', 'revoke', 'create']) @@ -45,7 +38,7 @@ t.test('completion', async t => { testComp(['npm', 'token', 'revoke'], []) testComp(['npm', 'token', 'create'], []) - t.rejects(completion({ conf: { argv: { remain: ['npm', 'token', 'foobar'] } } }), { + t.rejects(token.completion({ conf: { argv: { remain: ['npm', 'token', 'foobar'] } } }), { message: 'foobar not recognize', }) }) diff --git a/test/lib/commands/uninstall.js b/test/lib/commands/uninstall.js index 59a517d144d38..ae116d44c208b 100644 --- a/test/lib/commands/uninstall.js +++ b/test/lib/commands/uninstall.js @@ -188,19 +188,15 @@ t.test('no args global but no package.json', async t => { ) }) -t.test('unknown error reading from localPrefix package.json', async t => { +t.test('non ENOENT error reading from localPrefix package.json', async t => { const { uninstall } = await mockNpm(t, { config: { global: true }, - mocks: { - 'read-package-json-fast': async () => { - throw new Error('ERR') - }, - }, + prefixDir: { 'package.json': 'not[json]' }, }) await t.rejects( uninstall([]), - /ERR/, - 'should throw unknown error' + { code: 'EJSONPARSE' }, + 'should throw non ENOENT error' ) }) diff --git a/test/lib/commands/unpublish.js b/test/lib/commands/unpublish.js index 96c06bf3ffee6..6e898bd3d07e4 100644 --- a/test/lib/commands/unpublish.js +++ b/test/lib/commands/unpublish.js @@ -58,7 +58,7 @@ t.test('no args --force error reading package.json', async t => { await t.rejects( npm.exec('unpublish', []), - /Failed to parse json/, + /Invalid package.json/, 'should throw error from reading package.json' ) }) @@ -427,13 +427,13 @@ t.test('scoped registry config', async t => { }) t.test('completion', async t => { - const { npm } = await loadMockNpm(t, { + const { npm, unpublish } = await loadMockNpm(t, { + command: 'unpublish', config: { ...auth, }, }) - const unpublish = await npm.cmd('unpublish') const testComp = async (t, { argv, partialWord, expect, title }) => { const res = await unpublish.completion( diff --git a/test/lib/commands/version.js b/test/lib/commands/version.js index c48ff827fa28c..8aa6c088bfc9b 100644 --- a/test/lib/commands/version.js +++ b/test/lib/commands/version.js @@ -2,11 +2,12 @@ const { readFileSync, statSync } = require('fs') const { resolve } = require('path') const t = require('tap') const _mockNpm = require('../../fixtures/mock-npm') -const mockGlobals = require('../../fixtures/mock-globals.js') +const mockGlobals = require('@npmcli/mock-globals') const mockNpm = async (t, opts = {}) => { const res = await _mockNpm(t, { ...opts, + command: 'version', mocks: { ...opts.mocks, '{ROOT}/package.json': { version: '1.0.0' }, @@ -14,7 +15,6 @@ const mockNpm = async (t, opts = {}) => { }) return { ...res, - version: { exec: (args) => res.npm.exec('version', args) }, result: () => res.outputs[0], } } @@ -55,8 +55,7 @@ t.test('node@1', async t => { }) t.test('completion', async t => { - const { npm } = await mockNpm(t) - const version = await npm.cmd('version') + const { version } = await mockNpm(t) const testComp = async (argv, expect) => { const res = await version.completion({ conf: { argv: { remain: argv } } }) t.strictSame(res, expect, argv.join(' ')) diff --git a/test/lib/commands/view.js b/test/lib/commands/view.js index 51bc130df24e5..ca07ef9eec2ff 100644 --- a/test/lib/commands/view.js +++ b/test/lib/commands/view.js @@ -576,8 +576,7 @@ t.test('workspaces', async t => { }) t.test('completion', async t => { - const { npm } = await loadMockNpm(t) - const view = await npm.cmd('view') + const { view } = await loadMockNpm(t, { command: 'view' }) const res = await view.completion({ conf: { argv: { remain: ['npm', 'view', 'green@1.0.0'] } }, }) @@ -585,8 +584,7 @@ t.test('completion', async t => { }) t.test('no package completion', async t => { - const { npm } = await loadMockNpm(t) - const view = await npm.cmd('view') + const { view } = await loadMockNpm(t, { command: 'view' }) const res = await view.completion({ conf: { argv: { remain: ['npm', 'view'] } } }) t.notOk(res, 'there is no package completion') t.end() diff --git a/test/lib/docs.js b/test/lib/docs.js index b8a1a4fc60074..7ace9b9995701 100644 --- a/test/lib/docs.js +++ b/test/lib/docs.js @@ -1,14 +1,14 @@ const t = require('tap') -const { join, resolve, basename, extname, dirname } = require('path') +const { join, resolve, basename, extname } = require('path') const fs = require('fs/promises') const localeCompare = require('@isaacs/string-locale-compare')('en') const docs = require('@npmcli/docs') const { load: loadMockNpm } = require('../fixtures/mock-npm.js') -const mockGlobals = require('../fixtures/mock-globals.js') -const { definitions } = require('../../lib/utils/config/index.js') +const { definitions } = require('@npmcli/config/lib/definitions') const cmdList = require('../../lib/utils/cmd-list.js') const pkg = require('../../package.json') +const { cleanCwd } = require('../fixtures/clean-snapshot.js') t.test('command list', async t => { for (const [key, value] of Object.entries(cmdList)) { @@ -30,23 +30,62 @@ t.test('config', async t => { t.matchSnapshot(docs.config(docs.TAGS.CONFIG, {}), 'all definitions') }) -t.test('basic usage', async t => { - mockGlobals(t, { process: { platform: 'posix' } }) +t.test('flat options', async t => { + t.cleanSnapshot = (s) => cleanCwd(s) + .split(cleanCwd(process.execPath)).join('{NODE}') - t.cleanSnapshot = str => str - .split(dirname(dirname(__dirname))).join('{BASEDIR}') - .split(pkg.version).join('{VERSION}') + const { npm } = await loadMockNpm(t, { + command: 'version', + exec: true, + npm: ({ other }) => ({ + npmRoot: other, + }), + otherDirs: { + 'package.json': JSON.stringify({ version: '1.1.1' }), + }, + globals: { + 'process.stdout.isTTY': false, + 'process.stderr.isTTY': false, + 'process.env': { + EDITOR: '{EDITOR}', + SHELL: '{SHELL}', + }, + 'process.version': '2.2.2', + 'process.platform': '{PLATFORM}', + 'process.arch': '{ARCH}', + }, + mocks: { + 'ci-info': { isCI: true, name: '{CI}' }, + // currently the config version is read from npmRoot and the Npm + // constructor version is read from the root package.json file. This + // snapshot is meant to explicitly show that they are read from different + // places. In the future we should probably only read it from npmRoot, + // which would require more changes to ensure nothing depends on it being + // a static prop on the constructor + '{ROOT}/package.json': { version: '3.3.3' }, + }, + }) + + t.matchSnapshot(npm.flatOptions, 'full flat options object') +}) +t.test('basic usage', async t => { // snapshot basic usage without commands since all the command snapshots // are generated in the following test const { npm } = await loadMockNpm(t, { mocks: { '{LIB}/utils/cmd-list.js': { commands: [] }, }, + config: { userconfig: '/some/config/file/.npmrc' }, + globals: { process: { platform: 'posix' } }, }) - npm.config.set('userconfig', '/some/config/file/.npmrc') - t.matchSnapshot(await npm.usage) + t.cleanSnapshot = str => str + .replace(npm.npmRoot, '{BASEDIR}') + .replace(npm.config.get('userconfig'), '{USERCONFIG}') + .split(pkg.version).join('{VERSION}') + + t.matchSnapshot(npm.usage) }) t.test('usage', async t => { @@ -81,9 +120,8 @@ t.test('usage', async t => { t.test(cmd, async t => { let output = null if (!bareCommands.includes(cmd)) { - const { npm } = await loadMockNpm(t) - const impl = await npm.cmd(cmd) - output = impl.usage + const mock = await loadMockNpm(t, { command: cmd }) + output = mock[cmd].usage } const usage = docs.usage(docs.TAGS.USAGE, { path: cmd }) diff --git a/test/lib/es6/validate-engines.js b/test/lib/es6/validate-engines.js new file mode 100644 index 0000000000000..0e6bce726af96 --- /dev/null +++ b/test/lib/es6/validate-engines.js @@ -0,0 +1,34 @@ +const t = require('tap') +const mockGlobals = require('@npmcli/mock-globals') +const tmock = require('../../fixtures/tmock') + +const mockValidateEngines = (t) => { + const validateEngines = tmock(t, '{LIB}/es6/validate-engines.js', { + '{ROOT}/package.json': { version: '1.2.3', engines: { node: '>=0' } }, + }) + mockGlobals(t, { 'process.version': 'v4.5.6' }) + return validateEngines(process, () => (_, r) => r) +} + +t.test('validate engines', async t => { + t.equal(process.listenerCount('uncaughtException'), 0) + t.equal(process.listenerCount('unhandledRejection'), 0) + + const result = mockValidateEngines(t) + + t.equal(process.listenerCount('uncaughtException'), 1) + t.equal(process.listenerCount('unhandledRejection'), 1) + + t.match(result, { + node: 'v4.5.6', + npm: 'v1.2.3', + engines: '>=0', + /* eslint-disable-next-line max-len */ + unsupportedMessage: 'npm v1.2.3 does not support Node.js v4.5.6. This version of npm supports the following node versions: `>=0`. You can find the latest version at https://nodejs.org/.', + }) + + result.off() + + t.equal(process.listenerCount('uncaughtException'), 0) + t.equal(process.listenerCount('unhandledRejection'), 0) +}) diff --git a/test/lib/load-all-commands.js b/test/lib/load-all-commands.js index 1742376a36e69..d3846434489ce 100644 --- a/test/lib/load-all-commands.js +++ b/test/lib/load-all-commands.js @@ -6,20 +6,30 @@ const t = require('tap') const util = require('util') const { load: loadMockNpm } = require('../fixtures/mock-npm.js') const { commands } = require('../../lib/utils/cmd-list.js') +const BaseCommand = require('../../lib/base-command.js') const isAsyncFn = (v) => typeof v === 'function' && /^\[AsyncFunction:/.test(util.inspect(v)) t.test('load each command', async t => { + const counts = { + completion: 0, + ignoreImplicitWorkspace: 0, + workspaces: 0, + noParams: 0, + } + for (const cmd of commands) { - t.test(cmd, async t => { + await t.test(cmd, async t => { const { npm, outputs, cmd: impl } = await loadMockNpm(t, { command: cmd, config: { usage: true }, }) const ctor = impl.constructor - if (impl.completion) { - t.type(impl.completion, 'function', 'completion, if present, is a function') + t.notOk(impl.completion, 'completion is static, not on instance') + if (ctor.completion) { + t.ok(isAsyncFn(ctor.completion), 'completion is async function') + counts.completion++ } // exec fn @@ -28,7 +38,15 @@ t.test('load each command', async t => { // workspaces t.type(ctor.ignoreImplicitWorkspace, 'boolean', 'ctor has ignoreImplictWorkspace boolean') + if (ctor.ignoreImplicitWorkspace !== BaseCommand.ignoreImplicitWorkspace) { + counts.ignoreImplicitWorkspace++ + } + t.type(ctor.workspaces, 'boolean', 'ctor has workspaces boolean') + if (ctor.workspaces !== BaseCommand.workspaces) { + counts.workspaces++ + } + if (ctor.workspaces) { t.ok(isAsyncFn(impl.execWorkspaces), 'execWorkspaces is async') t.ok(impl.exec.length <= 1, 'execWorkspaces fn has 0 or 1 args') @@ -38,13 +56,32 @@ t.test('load each command', async t => { // name/desc t.ok(impl.description, 'implementation has a description') + t.equal(impl.description, ctor.description, 'description is same on instance and ctor') t.ok(impl.name, 'implementation has a name') + t.equal(impl.name, ctor.name, 'name is same on instance and ctor') t.equal(cmd, impl.name, 'command list and name are the same') + // params are optional + if (impl.params) { + t.equal(impl.params, ctor.params, 'params is same on instance and ctor') + t.ok(impl.params, 'implementation has a params') + } else { + counts.noParams++ + } + // usage t.match(impl.usage, cmd, 'usage contains the command') await npm.exec(cmd, []) t.match(outputs[0][0], impl.usage, 'usage is what is output') + t.match(outputs[0][0], ctor.describeUsage, 'usage is what is output') + t.notOk(impl.describeUsage, 'describe usage is only static') }) } + + // make sure refactors dont move or rename these static properties since + // we guard against the tests for them above + t.ok(counts.completion > 0, 'has some completion functions') + t.ok(counts.ignoreImplicitWorkspace > 0, 'has some commands that change ignoreImplicitWorkspace') + t.ok(counts.workspaces > 0, 'has some commands that change workspaces') + t.ok(counts.noParams > 0, 'has some commands that do not have params') }) diff --git a/test/lib/npm.js b/test/lib/npm.js index 61b31be620028..162e8c83ca4a4 100644 --- a/test/lib/npm.js +++ b/test/lib/npm.js @@ -2,7 +2,7 @@ const t = require('tap') const { resolve, dirname, join } = require('path') const fs = require('fs') const { load: loadMockNpm } = require('../fixtures/mock-npm.js') -const mockGlobals = require('../fixtures/mock-globals') +const mockGlobals = require('@npmcli/mock-globals') const { commands } = require('../../lib/utils/cmd-list.js') t.test('not yet loaded', async t => { @@ -105,10 +105,6 @@ t.test('npm.load', async t => { mockGlobals(t, { process: { platform: 'win32' } }) t.equal(npm.bin, npm.globalBin, 'bin is global bin in windows mode') t.equal(npm.dir, npm.globalDir, 'dir is global dir in windows mode') - - const tmp = npm.tmp - t.match(tmp, String, 'npm.tmp is a string') - t.equal(tmp, npm.tmp, 'getter only generates it once') }) await t.test('forceful loading', async t => { @@ -127,7 +123,7 @@ t.test('npm.load', async t => { await t.test('node is a symlink', async t => { const node = process.platform === 'win32' ? 'node.exe' : 'node' - const { npm, logs, outputs, prefix } = await loadMockNpm(t, { + const { Npm, npm, logs, outputs, prefix } = await loadMockNpm(t, { prefixDir: { bin: t.fixture('symlink', dirname(process.execPath)), }, @@ -168,8 +164,8 @@ t.test('npm.load', async t => { t.equal(npm.command, 'll', 'command set to first npm command') t.equal(npm.flatOptions.npmCommand, 'll', 'npmCommand flatOption set') - const ll = await npm.cmd('ll') - t.same(outputs, [[ll.usage]], 'print usage') + const ll = Npm.cmd('ll') + t.same(outputs, [[ll.describeUsage]], 'print usage') npm.config.set('usage', false) outputs.length = 0 @@ -202,7 +198,6 @@ t.test('npm.load', async t => { await t.test('--no-workspaces with --workspace', async t => { const { npm } = await loadMockNpm(t, { - load: false, prefixDir: { packages: { a: { @@ -554,14 +549,14 @@ t.test('output clears progress and console.logs the message', async t => { }) t.test('aliases and typos', async t => { - const { npm } = await loadMockNpm(t, { load: false }) - await t.rejects(npm.cmd('thisisnotacommand'), { code: 'EUNKNOWNCOMMAND' }) - await t.rejects(npm.cmd(''), { code: 'EUNKNOWNCOMMAND' }) - await t.rejects(npm.cmd('birthday'), { code: 'EUNKNOWNCOMMAND' }) - await t.resolves(npm.cmd('it'), { name: 'install-test' }) - await t.resolves(npm.cmd('installTe'), { name: 'install-test' }) - await t.resolves(npm.cmd('access'), { name: 'access' }) - await t.resolves(npm.cmd('auth'), { name: 'owner' }) + const { Npm } = await loadMockNpm(t, { init: false }) + t.throws(() => Npm.cmd('thisisnotacommand'), { code: 'EUNKNOWNCOMMAND' }) + t.throws(() => Npm.cmd(''), { code: 'EUNKNOWNCOMMAND' }) + t.throws(() => Npm.cmd('birthday'), { code: 'EUNKNOWNCOMMAND' }) + t.match(Npm.cmd('it').name, 'install-test') + t.match(Npm.cmd('installTe').name, 'install-test') + t.match(Npm.cmd('access').name, 'access') + t.match(Npm.cmd('auth').name, 'owner') }) t.test('explicit workspace rejection', async t => { @@ -663,30 +658,28 @@ t.test('implicit workspace accept', async t => { t.test('usage', async t => { t.test('with browser', async t => { - mockGlobals(t, { process: { platform: 'posix' } }) - const { npm } = await loadMockNpm(t) - const usage = await npm.usage + const { npm } = await loadMockNpm(t, { globals: { process: { platform: 'posix' } } }) + const usage = npm.usage npm.config.set('viewer', 'browser') - const browserUsage = await npm.usage + const browserUsage = npm.usage t.notMatch(usage, '(in a browser)') t.match(browserUsage, '(in a browser)') }) t.test('windows always uses browser', async t => { - mockGlobals(t, { process: { platform: 'win32' } }) - const { npm } = await loadMockNpm(t) - const usage = await npm.usage + const { npm } = await loadMockNpm(t, { globals: { process: { platform: 'win32' } } }) + const usage = npm.usage npm.config.set('viewer', 'browser') - const browserUsage = await npm.usage + const browserUsage = npm.usage t.match(usage, '(in a browser)') t.match(browserUsage, '(in a browser)') }) t.test('includes commands', async t => { const { npm } = await loadMockNpm(t) - const usage = await npm.usage + const usage = npm.usage npm.config.set('long', true) - const longUsage = await npm.usage + const longUsage = npm.usage const lastCmd = commands[commands.length - 1] for (const cmd of commands) { @@ -719,7 +712,7 @@ t.test('usage', async t => { for (const width of widths) { t.test(`column width ${width}`, async t => { mockGlobals(t, { 'process.stdout.columns': width }) - const usage = await npm.usage + const usage = npm.usage t.matchSnapshot(usage) }) } diff --git a/test/lib/utils/ansi-trim.js b/test/lib/utils/ansi-trim.js index de8d392937000..5a9e3b0c87cba 100644 --- a/test/lib/utils/ansi-trim.js +++ b/test/lib/utils/ansi-trim.js @@ -1,5 +1,8 @@ const t = require('tap') const ansiTrim = require('../../../lib/utils/ansi-trim.js') -const chalk = require('chalk') -t.equal(ansiTrim('foo'), 'foo', 'does nothing if no ansis') -t.equal(ansiTrim(chalk.red('foo')), 'foo', 'strips out ansis') + +t.test('basic', async t => { + const chalk = await import('chalk').then(v => v.default) + t.equal(ansiTrim('foo'), 'foo', 'does nothing if no ansis') + t.equal(ansiTrim(chalk.red('foo')), 'foo', 'strips out ansis') +}) diff --git a/test/lib/utils/audit-error.js b/test/lib/utils/audit-error.js index 1cb29a0857d75..f6be56a152f71 100644 --- a/test/lib/utils/audit-error.js +++ b/test/lib/utils/audit-error.js @@ -10,6 +10,8 @@ const auditError = async (t, { command, error, ...config } = {}) => { const mock = await mockNpm(t, { command, config, + exec: true, + prefixDir: { 'package.json': '{}', 'package-lock.json': '{}' }, }) const res = {} @@ -32,7 +34,8 @@ t.test('no error, not audit command', async t => { t.equal(result, false, 'no error') t.notOk(error, 'no error') - t.strictSame(output, '', 'no output') + t.match(output.trim(), /up to date/, 'install output') + t.match(output.trim(), /found 0 vulnerabilities/, 'install output') t.strictSame(logs, [], 'no warnings') }) @@ -53,7 +56,8 @@ t.test('error, not audit command', async t => { t.equal(result, true, 'had error') t.notOk(error, 'no error') - t.strictSame(output, '', 'no output') + t.match(output.trim(), /up to date/, 'install output') + t.match(output.trim(), /found 0 vulnerabilities/, 'install output') t.strictSame(logs, [], 'no warnings') }) @@ -62,7 +66,7 @@ t.test('error, audit command, not json', async t => { command: 'audit', error: { message: 'message', - body: Buffer.from('body'), + body: Buffer.from('body error text'), method: 'POST', uri: 'https://example.com/not/a/registry', headers: { @@ -75,7 +79,7 @@ t.test('error, audit command, not json', async t => { t.equal(result, undefined) t.ok(error, 'throws error') - t.strictSame(output, 'body', 'some output') + t.match(output, 'body error text', 'some output') t.strictSame(logs, [['audit', 'message']], 'some warnings') }) @@ -97,7 +101,7 @@ t.test('error, audit command, json', async t => { t.equal(result, undefined) t.ok(error, 'throws error') - t.strictSame(output, + t.match(output, '{\n' + ' "message": "message",\n' + ' "method": "POST",\n' + diff --git a/test/lib/utils/completion/installed-deep.js b/test/lib/utils/completion/installed-deep.js index 434d0214db4c8..0af26861ff83a 100644 --- a/test/lib/utils/completion/installed-deep.js +++ b/test/lib/utils/completion/installed-deep.js @@ -1,32 +1,6 @@ -const { resolve } = require('path') const t = require('tap') const installedDeep = require('../../../../lib/utils/completion/installed-deep.js') - -let prefix -let globalDir = 'MISSING_GLOBAL_DIR' -const _flatOptions = { - depth: Infinity, - global: false, - workspacesEnabled: true, - Arborist: require('@npmcli/arborist'), - get prefix () { - return prefix - }, -} -const npm = { - flatOptions: _flatOptions, - get prefix () { - return _flatOptions.prefix - }, - get globalDir () { - return globalDir - }, - config: { - get (key) { - return _flatOptions[key] - }, - }, -} +const mockNpm = require('../../../fixtures/mock-npm') const fixture = { 'package.json': JSON.stringify({ @@ -153,16 +127,23 @@ const globalFixture = { }, } -t.test('get list of package names', async t => { - const fix = t.testdir({ - local: fixture, - global: globalFixture, +const mockDeep = async (t, config) => { + const mock = await mockNpm(t, { + prefixDir: fixture, + globalPrefixDir: globalFixture, + config: { + depth: Infinity, + ...config, + }, }) - prefix = resolve(fix, 'local') - globalDir = resolve(fix, 'global/node_modules') + const res = await installedDeep(mock.npm) - const res = await installedDeep(npm, null) + return res +} + +t.test('get list of package names', async t => { + const res = await mockDeep(t) t.same( res, [ @@ -179,17 +160,7 @@ t.test('get list of package names', async t => { }) t.test('get list of package names as global', async t => { - const fix = t.testdir({ - local: fixture, - global: globalFixture, - }) - - prefix = resolve(fix, 'local') - globalDir = resolve(fix, 'global/node_modules') - - _flatOptions.global = true - - const res = await installedDeep(npm, null) + const res = await mockDeep(t, { global: true }) t.same( res, [ @@ -199,22 +170,10 @@ t.test('get list of package names as global', async t => { ], 'should return list of global packages with no extra flags' ) - _flatOptions.global = false - t.end() }) t.test('limit depth', async t => { - const fix = t.testdir({ - local: fixture, - global: globalFixture, - }) - - prefix = resolve(fix, 'local') - globalDir = resolve(fix, 'global/node_modules') - - _flatOptions.depth = 0 - - const res = await installedDeep(npm, null) + const res = await mockDeep(t, { depth: 0 }) t.same( res, [ @@ -229,23 +188,10 @@ t.test('limit depth', async t => { ], 'should print only packages up to the specified depth' ) - _flatOptions.depth = 0 - t.end() }) t.test('limit depth as global', async t => { - const fix = t.testdir({ - local: fixture, - global: globalFixture, - }) - - prefix = resolve(fix, 'local') - globalDir = resolve(fix, 'global/node_modules') - - _flatOptions.global = true - _flatOptions.depth = 0 - - const res = await installedDeep(npm, null) + const res = await mockDeep(t, { depth: 0, global: true }) t.same( res, [ @@ -256,7 +202,4 @@ t.test('limit depth as global', async t => { ], 'should reorder so that packages above that level depth goes last' ) - _flatOptions.global = false - _flatOptions.depth = 0 - t.end() }) diff --git a/test/lib/utils/completion/installed-shallow.js b/test/lib/utils/completion/installed-shallow.js index 5a65b6b6bfaef..3666803979cb3 100644 --- a/test/lib/utils/completion/installed-shallow.js +++ b/test/lib/utils/completion/installed-shallow.js @@ -1,13 +1,10 @@ const t = require('tap') -const { resolve } = require('path') const installed = require('../../../../lib/utils/completion/installed-shallow.js') +const mockNpm = require('../../../fixtures/mock-npm') -const flatOptions = { global: false } -const npm = { flatOptions } - -t.test('global not set, include globals with -g', async t => { - const dir = t.testdir({ - global: { +const mockShallow = async (t, config) => { + const res = await mockNpm(t, { + globalPrefixDir: { node_modules: { x: {}, '@scope': { @@ -15,7 +12,7 @@ t.test('global not set, include globals with -g', async t => { }, }, }, - local: { + prefixDir: { node_modules: { a: {}, '@scope': { @@ -23,10 +20,13 @@ t.test('global not set, include globals with -g', async t => { }, }, }, + config: { global: false, ...config }, }) - npm.globalDir = resolve(dir, 'global/node_modules') - npm.localDir = resolve(dir, 'local/node_modules') - flatOptions.global = false + return res +} + +t.test('global not set, include globals with -g', async t => { + const { npm } = await mockShallow(t) const opt = { conf: { argv: { remain: [] } } } const res = await installed(npm, opt) t.strictSame(res.sort(), [ @@ -35,64 +35,21 @@ t.test('global not set, include globals with -g', async t => { 'a', '@scope/b', ].sort()) - t.end() }) t.test('global set, include globals and not locals', async t => { - const dir = t.testdir({ - global: { - node_modules: { - x: {}, - '@scope': { - y: {}, - }, - }, - }, - local: { - node_modules: { - a: {}, - '@scope': { - b: {}, - }, - }, - }, - }) - npm.globalDir = resolve(dir, 'global/node_modules') - npm.localDir = resolve(dir, 'local/node_modules') - flatOptions.global = true + const { npm } = await mockShallow(t, { global: true }) const opt = { conf: { argv: { remain: [] } } } const res = await installed(npm, opt) t.strictSame(res.sort(), [ '@scope/y', 'x', ].sort()) - t.end() }) t.test('more than 3 items in argv, skip it', async t => { - const dir = t.testdir({ - global: { - node_modules: { - x: {}, - '@scope': { - y: {}, - }, - }, - }, - local: { - node_modules: { - a: {}, - '@scope': { - b: {}, - }, - }, - }, - }) - npm.globalDir = resolve(dir, 'global/node_modules') - npm.localDir = resolve(dir, 'local/node_modules') - flatOptions.global = false + const { npm } = await mockShallow(t) const opt = { conf: { argv: { remain: [1, 2, 3, 4, 5, 6] } } } const res = await installed(npm, opt) t.strictSame(res, null) - t.end() }) diff --git a/test/lib/utils/did-you-mean.js b/test/lib/utils/did-you-mean.js index d3cb3a24f0ae5..d111c2f002960 100644 --- a/test/lib/utils/did-you-mean.js +++ b/test/lib/utils/did-you-mean.js @@ -1,9 +1,8 @@ const t = require('tap') -const { load: loadMockNpm } = require('../../fixtures/mock-npm.js') const dym = require('../../../lib/utils/did-you-mean.js') + t.test('did-you-mean', async t => { - const { npm } = await loadMockNpm(t) t.test('with package.json', async t => { const testdir = t.testdir({ 'package.json': JSON.stringify({ @@ -17,27 +16,27 @@ t.test('did-you-mean', async t => { }), }) t.test('nistall', async t => { - const result = await dym(npm, testdir, 'nistall') + const result = await dym(testdir, 'nistall') t.match(result, 'npm install') }) t.test('sttest', async t => { - const result = await dym(npm, testdir, 'sttest') + const result = await dym(testdir, 'sttest') t.match(result, 'npm test') t.match(result, 'npm run posttest') }) t.test('npz', async t => { - const result = await dym(npm, testdir, 'npxx') + const result = await dym(testdir, 'npxx') t.match(result, 'npm exec npx') }) t.test('qwuijbo', async t => { - const result = await dym(npm, testdir, 'qwuijbo') + const result = await dym(testdir, 'qwuijbo') t.match(result, '') }) }) t.test('with no package.json', t => { const testdir = t.testdir({}) t.test('nistall', async t => { - const result = await dym(npm, testdir, 'nistall') + const result = await dym(testdir, 'nistall') t.match(result, 'npm install') }) t.end() @@ -49,7 +48,7 @@ t.test('did-you-mean', async t => { }), }) - const result = await dym(npm, testdir, 'nistall') + const result = await dym(testdir, 'nistall') t.match(result, 'npm install') }) }) diff --git a/test/lib/utils/display.js b/test/lib/utils/display.js index 7a99dcb679c09..b8f047668bfe4 100644 --- a/test/lib/utils/display.js +++ b/test/lib/utils/display.js @@ -1,7 +1,7 @@ const t = require('tap') const log = require('../../../lib/utils/log-shim') const mockLogs = require('../../fixtures/mock-logs') -const mockGlobals = require('../../fixtures/mock-globals') +const mockGlobals = require('@npmcli/mock-globals') const tmock = require('../../fixtures/tmock') const mockDisplay = (t, mocks) => { diff --git a/test/lib/utils/error-message.js b/test/lib/utils/error-message.js index 37b3bc6afeddc..1ba5865592edb 100644 --- a/test/lib/utils/error-message.js +++ b/test/lib/utils/error-message.js @@ -2,7 +2,7 @@ const t = require('tap') const { resolve } = require('path') const fs = require('fs/promises') const { load: _loadMockNpm } = require('../../fixtures/mock-npm.js') -const mockGlobals = require('../../fixtures/mock-globals.js') +const mockGlobals = require('@npmcli/mock-globals') const tmock = require('../../fixtures/tmock') const { cleanCwd, cleanDate } = require('../../fixtures/clean-snapshot.js') @@ -46,7 +46,9 @@ const loadMockNpm = async (t, { errorMocks, ...opts } = {}) => { t.test('just simple messages', async t => { const { errorMessage } = await loadMockNpm(t, { + prefixDir: { 'package-lock.json': '{}' }, command: 'audit', + exec: true, }) const codes = [ 'ENOAUDIT', diff --git a/test/lib/utils/exit-handler.js b/test/lib/utils/exit-handler.js index 8942d90922597..f553e1a2ea518 100644 --- a/test/lib/utils/exit-handler.js +++ b/test/lib/utils/exit-handler.js @@ -6,7 +6,7 @@ const { join, resolve } = require('path') const EventEmitter = require('events') const { format } = require('../../../lib/utils/log-file') const { load: loadMockNpm } = require('../../fixtures/mock-npm') -const mockGlobals = require('../../fixtures/mock-globals') +const mockGlobals = require('@npmcli/mock-globals') const { cleanCwd, cleanDate } = require('../../fixtures/clean-snapshot') const tmock = require('../../fixtures/tmock') @@ -40,7 +40,7 @@ t.cleanSnapshot = (path) => cleanDate(cleanCwd(path)) mockGlobals(t, { process: Object.assign(new EventEmitter(), { // these are process properties that are needed in the running code and tests - ...pick(process, 'execPath', 'stdout', 'stderr', 'cwd', 'chdir', 'env', 'umask'), + ...pick(process, 'execPath', 'stdout', 'stderr', 'stdin', 'cwd', 'chdir', 'env', 'umask'), argv: ['/node', ...process.argv.slice(1)], version: 'v1.0.0', kill: () => {}, @@ -53,13 +53,11 @@ mockGlobals(t, { }), }, { replace: true }) -const mockExitHandler = async (t, { init, load, testdir, config, mocks, files } = {}) => { +const mockExitHandler = async (t, { config, mocks, files, ...opts } = {}) => { const errors = [] const { npm, logMocks, ...rest } = await loadMockNpm(t, { - init, - load, - testdir, + ...opts, mocks: { '{ROOT}/package.json': { version: '1.0.0', @@ -592,13 +590,14 @@ t.test('exits uncleanly when only emitting exit event', async (t) => { t.match(logs.error, [['', 'Exit handler never called!']]) t.equal(process.exitCode, 1, 'exitCode coerced to 1') - t.end() }) t.test('do no fancy handling for shellouts', async t => { - const { exitHandler, npm, logs } = await mockExitHandler(t) - - await npm.cmd('exec') + const { exitHandler, logs } = await mockExitHandler(t, { + command: 'exec', + exec: true, + argv: ['-c', 'exit'], + }) const loudNoises = () => logs.filter(([level]) => ['warn', 'error'].includes(level)) @@ -614,7 +613,6 @@ t.test('do no fancy handling for shellouts', async t => { t.equal(process.exitCode, 1, 'got expected exit code') // should log some warnings and errors, because something weird happened t.strictNotSame(loudNoises(), [], 'bring the noise') - t.end() }) t.test('shellout with code=0 (extra weird?)', async t => { @@ -622,6 +620,4 @@ t.test('do no fancy handling for shellouts', async t => { t.equal(process.exitCode, 1, 'got expected exit code') t.strictNotSame(loudNoises(), [], 'bring the noise') }) - - t.end() }) diff --git a/test/lib/utils/explain-dep.js b/test/lib/utils/explain-dep.js index e5389fd26d796..06174f36a7ffc 100644 --- a/test/lib/utils/explain-dep.js +++ b/test/lib/utils/explain-dep.js @@ -1,269 +1,277 @@ const { resolve } = require('path') const t = require('tap') -const Chalk = require('chalk') const { explainNode, printNode } = require('../../../lib/utils/explain-dep.js') const { cleanCwd } = require('../../fixtures/clean-snapshot') -const testdir = t.testdirName -const color = new Chalk.Instance({ level: Chalk.level }) -const noColor = new Chalk.Instance({ level: 0 }) - t.cleanSnapshot = (str) => cleanCwd(str) -const cases = { - prodDep: { - name: 'prod-dep', - version: '1.2.3', - location: 'node_modules/prod-dep', - dependents: [ - { - type: 'prod', - name: 'prod-dep', - spec: '1.x', - from: { - location: '/path/to/project', +const getCases = (testdir) => { + const cases = { + prodDep: { + name: 'prod-dep', + version: '1.2.3', + location: 'node_modules/prod-dep', + dependents: [ + { + type: 'prod', + name: 'prod-dep', + spec: '1.x', + from: { + location: '/path/to/project', + }, }, - }, - ], - }, + ], + }, - deepDev: { - name: 'deep-dev', - version: '2.3.4', - location: 'node_modules/deep-dev', - dev: true, - dependents: [ - { - type: 'prod', - name: 'deep-dev', - spec: '2.x', - from: { - name: 'metadev', - version: '3.4.5', - location: 'node_modules/dev/node_modules/metadev', - dependents: [ - { - type: 'prod', - name: 'metadev', - spec: '3.x', - from: { - name: 'topdev', - version: '4.5.6', - location: 'node_modules/topdev', - dependents: [ - { - type: 'dev', - name: 'topdev', - spec: '4.x', - from: { - location: '/path/to/project', + deepDev: { + name: 'deep-dev', + version: '2.3.4', + location: 'node_modules/deep-dev', + dev: true, + dependents: [ + { + type: 'prod', + name: 'deep-dev', + spec: '2.x', + from: { + name: 'metadev', + version: '3.4.5', + location: 'node_modules/dev/node_modules/metadev', + dependents: [ + { + type: 'prod', + name: 'metadev', + spec: '3.x', + from: { + name: 'topdev', + version: '4.5.6', + location: 'node_modules/topdev', + dependents: [ + { + type: 'dev', + name: 'topdev', + spec: '4.x', + from: { + location: '/path/to/project', + }, }, - }, - ], + ], + }, }, - }, - ], + ], + }, }, - }, - ], - }, + ], + }, - optional: { - name: 'optdep', - version: '1.0.0', - location: 'node_modules/optdep', - optional: true, - dependents: [ - { - type: 'optional', - name: 'optdep', + optional: { + name: 'optdep', + version: '1.0.0', + location: 'node_modules/optdep', + optional: true, + dependents: [ + { + type: 'optional', + name: 'optdep', + spec: '1.0.0', + from: { + location: '/path/to/project', + }, + }, + ], + }, + + peer: { + name: 'peer', + version: '1.0.0', + location: 'node_modules/peer', + peer: true, + dependents: [ + { + type: 'peer', + name: 'peer', + spec: '1.0.0', + from: { + location: '/path/to/project', + }, + }, + ], + }, + + bundled: { + name: 'bundle-of-joy', + version: '1.0.0', + location: 'node_modules/bundle-of-joy', + bundled: true, + dependents: [ + { + type: 'prod', + name: 'prod-dep', + spec: '1.x', + bundled: true, + from: { + location: '/path/to/project', + }, + }, + ], + }, + + extraneous: { + name: 'extra-neos', + version: '1337.420.69-lol', + location: 'node_modules/extra-neos', + dependents: [], + extraneous: true, + }, + + overridden: { + name: 'overridden-root', + version: '1.0.0', + location: 'node_modules/overridden-root', + overridden: true, + dependents: [{ + type: 'prod', + name: 'overridden-dep', spec: '1.0.0', + rawSpec: '^2.0.0', + overridden: true, from: { location: '/path/to/project', }, - }, - ], - }, + }], + }, + } - peer: { - name: 'peer', + cases.manyDeps = { + name: 'manydep', version: '1.0.0', - location: 'node_modules/peer', - peer: true, dependents: [ { - type: 'peer', - name: 'peer', + type: 'prod', + name: 'manydep', spec: '1.0.0', + from: cases.prodDep, + }, + { + type: 'optional', + name: 'manydep', + spec: '1.x', + from: cases.optional, + }, + { + type: 'prod', + name: 'manydep', + spec: '1.0.x', + from: cases.extraneous, + }, + { + type: 'dev', + name: 'manydep', + spec: '*', + from: cases.deepDev, + }, + { + type: 'peer', + name: 'manydep', + spec: '>1.0.0-beta <1.0.1', + from: cases.peer, + }, + { + type: 'prod', + name: 'manydep', + spec: '>1.0.0-beta <1.0.1', from: { location: '/path/to/project', }, }, - ], - }, - - bundled: { - name: 'bundle-of-joy', - version: '1.0.0', - location: 'node_modules/bundle-of-joy', - bundled: true, - dependents: [ { type: 'prod', - name: 'prod-dep', - spec: '1.x', - bundled: true, + name: 'manydep', + spec: '1', from: { - location: '/path/to/project', + name: 'a package with a pretty long name', + version: '1.2.3', + dependents: { + location: '/path/to/project', + }, }, }, - ], - }, - - extraneous: { - name: 'extra-neos', - version: '1337.420.69-lol', - location: 'node_modules/extra-neos', - dependents: [], - extraneous: true, - }, - - overridden: { - name: 'overridden-root', - version: '1.0.0', - location: 'node_modules/overridden-root', - overridden: true, - dependents: [{ - type: 'prod', - name: 'overridden-dep', - spec: '1.0.0', - rawSpec: '^2.0.0', - overridden: true, - from: { - location: '/path/to/project', - }, - }], - }, -} - -cases.manyDeps = { - name: 'manydep', - version: '1.0.0', - dependents: [ - { - type: 'prod', - name: 'manydep', - spec: '1.0.0', - from: cases.prodDep, - }, - { - type: 'optional', - name: 'manydep', - spec: '1.x', - from: cases.optional, - }, - { - type: 'prod', - name: 'manydep', - spec: '1.0.x', - from: cases.extraneous, - }, - { - type: 'dev', - name: 'manydep', - spec: '*', - from: cases.deepDev, - }, - { - type: 'peer', - name: 'manydep', - spec: '>1.0.0-beta <1.0.1', - from: cases.peer, - }, - { - type: 'prod', - name: 'manydep', - spec: '>1.0.0-beta <1.0.1', - from: { - location: '/path/to/project', - }, - }, - { - type: 'prod', - name: 'manydep', - spec: '1', - from: { - name: 'a package with a pretty long name', - version: '1.2.3', - dependents: { - location: '/path/to/project', + { + type: 'prod', + name: 'manydep', + spec: '1', + from: { + name: 'another package with a pretty long name', + version: '1.2.3', + dependents: { + location: '/path/to/project', + }, }, }, - }, - { - type: 'prod', - name: 'manydep', - spec: '1', - from: { - name: 'another package with a pretty long name', - version: '1.2.3', - dependents: { - location: '/path/to/project', + { + type: 'prod', + name: 'manydep', + spec: '1', + from: { + name: 'yet another a package with a pretty long name', + version: '1.2.3', + dependents: { + location: '/path/to/project', + }, }, }, - }, - { - type: 'prod', - name: 'manydep', - spec: '1', - from: { - name: 'yet another a package with a pretty long name', - version: '1.2.3', - dependents: { - location: '/path/to/project', - }, + ], + } + + cases.workspaces = { + name: 'a', + version: '1.0.0', + location: 'a', + isWorkspace: true, + dependents: [], + linksIn: [ + { + name: 'a', + version: '1.0.0', + location: 'node_modules/a', + isWorkspace: true, + dependents: [ + { + type: 'workspace', + name: 'a', + spec: `file:${resolve(testdir, 'ws-project', 'a')}`, + from: { location: resolve(testdir, 'ws-project') }, + }, + ], }, - }, - ], -} + ], + } -cases.workspaces = { - name: 'a', - version: '1.0.0', - location: 'a', - isWorkspace: true, - dependents: [], - linksIn: [ - { - name: 'a', - version: '1.0.0', - location: 'node_modules/a', - isWorkspace: true, - dependents: [ - { - type: 'workspace', - name: 'a', - spec: `file:${resolve(testdir, 'ws-project', 'a')}`, - from: { location: resolve(testdir, 'ws-project') }, - }, - ], - }, - ], + return cases } -for (const [name, expl] of Object.entries(cases)) { - t.test(name, t => { - t.matchSnapshot(printNode(expl, color), 'print color') - t.matchSnapshot(printNode(expl, noColor), 'print nocolor') - t.matchSnapshot(explainNode(expl, Infinity, color), 'explain color deep') - t.matchSnapshot(explainNode(expl, 2, noColor), 'explain nocolor shallow') - t.end() - }) -} +t.test('basic', async t => { + const { Chalk } = await import('chalk') + const color = new Chalk({ level: 3 }) + const noColor = new Chalk({ level: 0 }) + + const testdir = t.testdir() + const cases = getCases(testdir) + + for (const [name, expl] of Object.entries(getCases(testdir))) { + t.test(name, t => { + t.matchSnapshot(printNode(expl, color), 'print color') + t.matchSnapshot(printNode(expl, noColor), 'print nocolor') + t.matchSnapshot(explainNode(expl, Infinity, color), 'explain color deep') + t.matchSnapshot(explainNode(expl, 2, noColor), 'explain nocolor shallow') + t.end() + }) + } -// make sure that we show the last one if it's the only one that would -// hit the ... -cases.manyDeps.dependents.pop() -t.matchSnapshot(explainNode(cases.manyDeps, 2, noColor), 'ellipses test one') -cases.manyDeps.dependents.pop() -t.matchSnapshot(explainNode(cases.manyDeps, 2, noColor), 'ellipses test two') + // make sure that we show the last one if it's the only one that would + // hit the ... + cases.manyDeps.dependents.pop() + t.matchSnapshot(explainNode(cases.manyDeps, 2, noColor), 'ellipses test one') + cases.manyDeps.dependents.pop() + t.matchSnapshot(explainNode(cases.manyDeps, 2, noColor), 'ellipses test two') +}) diff --git a/test/lib/utils/explain-eresolve.js b/test/lib/utils/explain-eresolve.js index 0f60556ef2ac9..157cc97a5a3cb 100644 --- a/test/lib/utils/explain-eresolve.js +++ b/test/lib/utils/explain-eresolve.js @@ -1,29 +1,31 @@ const t = require('tap') -const Chalk = require('chalk') const { explain, report } = require('../../../lib/utils/explain-eresolve.js') const cases = require('../../fixtures/eresolve-explanations.js') -const color = new Chalk.Instance({ level: Chalk.level }) -const noColor = new Chalk.Instance({ level: 0 }) +t.test('basic', async t => { + const { Chalk } = await import('chalk') + const color = new Chalk({ level: 3 }) + const noColor = new Chalk({ level: 0 }) -for (const [name, expl] of Object.entries(cases)) { + for (const [name, expl] of Object.entries(cases)) { // no sense storing the whole contents of each object in the snapshot // we can trust that JSON.stringify still works just fine. - expl.toJSON = () => ({ name, json: true }) + expl.toJSON = () => ({ name, json: true }) - t.test(name, t => { - const colorReport = report(expl, color, noColor) - t.matchSnapshot(colorReport.explanation, 'report with color') - t.matchSnapshot(colorReport.file, 'report from color') + t.test(name, t => { + const colorReport = report(expl, color, noColor) + t.matchSnapshot(colorReport.explanation, 'report with color') + t.matchSnapshot(colorReport.file, 'report from color') - const noColorReport = report(expl, noColor, noColor) - t.matchSnapshot(noColorReport.explanation, 'report with no color') - t.equal(noColorReport.file, colorReport.file, 'same report written for object') + const noColorReport = report(expl, noColor, noColor) + t.matchSnapshot(noColorReport.explanation, 'report with no color') + t.equal(noColorReport.file, colorReport.file, 'same report written for object') - t.matchSnapshot(explain(expl, color, 2), 'explain with color, depth of 2') - t.matchSnapshot(explain(expl, noColor, 6), 'explain with no color, depth of 6') + t.matchSnapshot(explain(expl, color, 2), 'explain with color, depth of 2') + t.matchSnapshot(explain(expl, noColor, 6), 'explain with no color, depth of 6') - t.end() - }) -} + t.end() + }) + } +}) diff --git a/test/lib/utils/open-url-prompt.js b/test/lib/utils/open-url-prompt.js index faf2ab32587af..c889313e162c7 100644 --- a/test/lib/utils/open-url-prompt.js +++ b/test/lib/utils/open-url-prompt.js @@ -1,138 +1,120 @@ const t = require('tap') -const mockGlobals = require('../../fixtures/mock-globals.js') const EventEmitter = require('events') const tmock = require('../../fixtures/tmock') - -const OUTPUT = [] -const output = (...args) => OUTPUT.push(args) -const npm = { - _config: { - json: false, - browser: true, - }, - config: { - get: k => npm._config[k], - set: (k, v) => { - npm._config[k] = v +const mockNpm = require('../../fixtures/mock-npm') + +const mockOpenUrlPrompt = async (t, { + questionShouldResolve = true, + openUrlPromptInterrupted = false, + openerResult = null, + isTTY = true, + emitter = null, + url: openUrl = 'https://www.npmjs.com', + ...config +}) => { + const mock = await mockNpm(t, { + globals: { + 'process.stdin.isTTY': isTTY, + 'process.stdout.isTTY': isTTY, }, - }, - output, -} - -let openerUrl = null -let openerOpts = null -let openerResult = null - -let questionShouldResolve = true -let openUrlPromptInterrupted = false + config, + }) -const readline = { - createInterface: () => ({ - question: (_q, cb) => { - if (questionShouldResolve === true) { - cb() - } + let openerUrl = null + let openerOpts = null + + const openUrlPrompt = tmock(t, '{LIB}/utils/open-url-prompt.js', { + '@npmcli/promise-spawn': { + open: async (url, options) => { + openerUrl = url + openerOpts = options + if (openerResult) { + throw openerResult + } + }, }, - close: () => {}, - on: (_signal, cb) => { - if (openUrlPromptInterrupted && _signal === 'SIGINT') { - cb() - } + readline: { + createInterface: () => ({ + question: (_q, cb) => { + if (questionShouldResolve === true) { + cb() + } + }, + close: () => {}, + on: (_signal, cb) => { + if (openUrlPromptInterrupted && _signal === 'SIGINT') { + cb() + } + }, + }), }, - }), -} + }) -const openUrlPrompt = tmock(t, '{LIB}/utils/open-url-prompt.js', { - '@npmcli/promise-spawn': { - open: async (url, options) => { - openerUrl = url - openerOpts = options - if (openerResult) { - throw openerResult - } - }, - }, - readline, -}) + let error + const args = [mock.npm, openUrl, 'npm home', 'prompt'] + if (emitter) { + mock.open = openUrlPrompt(...args, emitter) + } else { + await openUrlPrompt(...args).catch((er) => error = er) + } -mockGlobals(t, { - 'process.stdin.isTTY': true, - 'process.stdout.isTTY': true, -}) + return { + ...mock, + openerUrl, + openerOpts, + OUTPUT: mock.joinedOutput(), + emitter, + error, + } +} t.test('does not open a url in non-interactive environments', async t => { - t.teardown(() => { - openerUrl = null - openerOpts = null - OUTPUT.length = 0 - }) - - mockGlobals(t, { - 'process.stdin.isTTY': false, - 'process.stdout.isTTY': false, - }) + const { openerUrl, openerOpts } = await mockOpenUrlPrompt(t, { isTTY: false }) - await openUrlPrompt(npm, 'https://www.npmjs.com', 'npm home', 'prompt') t.equal(openerUrl, null, 'did not open') t.same(openerOpts, null, 'did not open') }) t.test('opens a url', async t => { - t.teardown(() => { - openerUrl = null - openerOpts = null - OUTPUT.length = 0 - npm._config.browser = true - }) + const { OUTPUT, openerUrl, openerOpts } = await mockOpenUrlPrompt(t, { browser: true }) - npm._config.browser = 'browser' - await openUrlPrompt(npm, 'https://www.npmjs.com', 'npm home', 'prompt') t.equal(openerUrl, 'https://www.npmjs.com', 'opened the given url') - t.same(openerOpts, { command: 'browser' }, 'passed command as null (the default)') + t.same(openerOpts, { command: null }, 'passed command as null (the default)') t.matchSnapshot(OUTPUT) }) +t.test('opens a url with browser string', async t => { + const { openerUrl, openerOpts } = await mockOpenUrlPrompt(t, { browser: 'firefox' }) + + t.equal(openerUrl, 'https://www.npmjs.com', 'opened the given url') + // FIXME: browser string is parsed as a boolean in config layer + // this is a bug that should be fixed or the config should not allow it + t.same(openerOpts, { command: null }, 'passed command as null (the default)') +}) + t.test('prints json output', async t => { - t.teardown(() => { - openerUrl = null - openerOpts = null - OUTPUT.length = 0 - npm._config.json = false - }) + const { OUTPUT } = await mockOpenUrlPrompt(t, { json: true }) - npm._config.json = true - await openUrlPrompt(npm, 'https://www.npmjs.com', 'npm home', 'prompt') t.matchSnapshot(OUTPUT) }) t.test('returns error for non-https url', async t => { - t.teardown(() => { - openerUrl = null - openerOpts = null - OUTPUT.length = 0 + const { error, OUTPUT, openerUrl, openerOpts } = await mockOpenUrlPrompt(t, { + url: 'ftp://www.npmjs.com', }) - await t.rejects( - openUrlPrompt(npm, 'ftp://www.npmjs.com', 'npm home', 'prompt'), - /Invalid URL/, - 'got the correct error' - ) + + t.match(error, /Invalid URL/, 'got the correct error') t.equal(openerUrl, null, 'did not open') t.same(openerOpts, null, 'did not open') - t.same(OUTPUT, [], 'printed no output') + t.same(OUTPUT, '', 'printed no output') }) t.test('does not open url if canceled', async t => { - t.teardown(() => { - openerUrl = null - openerOpts = null - OUTPUT.length = 0 - questionShouldResolve = true - }) - - questionShouldResolve = false const emitter = new EventEmitter() - - const open = openUrlPrompt(npm, 'https://www.npmjs.com', 'npm home', 'prompt', emitter) + const { openerUrl, openerOpts, open } = await mockOpenUrlPrompt(t, { + questionShouldResolve: false, + emitter, + }) emitter.emit('abort') @@ -143,41 +125,21 @@ t.test('does not open url if canceled', async t => { }) t.test('returns error when opener errors', async t => { - t.teardown(() => { - openerUrl = null - openerOpts = null - openerResult = null - OUTPUT.length = 0 + const { error, openerUrl } = await mockOpenUrlPrompt(t, { + openerResult: new Error('Opener failed'), }) - openerResult = new Error('Opener failed') - - await t.rejects( - openUrlPrompt(npm, 'https://www.npmjs.com', 'npm home', 'prompt'), - /Opener failed/, - 'got the correct error' - ) + t.match(error, /Opener failed/, 'got the correct error') t.equal(openerUrl, 'https://www.npmjs.com', 'did not open') }) t.test('throws "canceled" error on SIGINT', async t => { - t.teardown(() => { - openerUrl = null - openerOpts = null - OUTPUT.length = 0 - questionShouldResolve = true - openUrlPromptInterrupted = false - }) - - questionShouldResolve = false - openUrlPromptInterrupted = true const emitter = new EventEmitter() + const { open } = await mockOpenUrlPrompt(t, { + questionShouldResolve: false, + openUrlPromptInterrupted: true, + emitter, + }) - const open = openUrlPrompt(npm, 'https://www.npmjs.com', 'npm home', 'prompt', emitter) - - try { - await open - } catch (err) { - t.equal(err.message, 'canceled') - } + await t.rejects(open, /canceled/, 'message is canceled') }) diff --git a/test/lib/utils/open-url.js b/test/lib/utils/open-url.js index 28a11b3609c67..0ce1b57aa5f9f 100644 --- a/test/lib/utils/open-url.js +++ b/test/lib/utils/open-url.js @@ -1,197 +1,143 @@ const t = require('tap') const tmock = require('../../fixtures/tmock') +const mockNpm = require('../../fixtures/mock-npm') -const OUTPUT = [] -const output = (...args) => OUTPUT.push(args) -const npm = { - _config: { - json: false, - browser: true, - }, - config: { - get: k => npm._config[k], - set: (k, v) => { - npm._config[k] = v - }, - }, - output, -} +const mockOpenUrl = async (t, args, { openerResult, ...config } = {}) => { + let openerUrl = null + let openerOpts = null + + const open = async (url, options) => { + openerUrl = url + openerOpts = options + if (openerResult) { + throw openerResult + } + } + + const mock = await mockNpm(t, { config }) + + const openUrl = tmock(t, '{LIB}/utils/open-url.js', { + '@npmcli/promise-spawn': { open }, + }) -let openerUrl = null -let openerOpts = null -let openerResult = null + const openWithNpm = (...a) => openUrl(mock.npm, ...a) -const open = async (url, options) => { - openerUrl = url - openerOpts = options - if (openerResult) { - throw openerResult + if (args) { + await openWithNpm(...args) } -} -const openUrl = tmock(t, '{LIB}/utils/open-url.js', { - '@npmcli/promise-spawn': { - open, - }, -}) + return { + ...mock, + openUrl: openWithNpm, + openerUrl: () => openerUrl, + openerOpts: () => openerOpts, + } +} t.test('opens a url', async t => { - t.teardown(() => { - openerUrl = null - openerOpts = null - OUTPUT.length = 0 - }) - await openUrl(npm, 'https://www.npmjs.com', 'npm home') - t.equal(openerUrl, 'https://www.npmjs.com', 'opened the given url') - t.same(openerOpts, { command: null }, 'passed command as null (the default)') - t.same(OUTPUT, [], 'printed no output') + const { openerUrl, openerOpts, joinedOutput } = await mockOpenUrl(t, + ['https://www.npmjs.com', 'npm home']) + t.equal(openerUrl(), 'https://www.npmjs.com', 'opened the given url') + t.same(openerOpts(), { command: null }, 'passed command as null (the default)') + t.same(joinedOutput(), '', 'printed no output') }) t.test('returns error for non-https url', async t => { - t.teardown(() => { - openerUrl = null - openerOpts = null - OUTPUT.length = 0 - }) + const { openUrl, openerUrl, openerOpts, joinedOutput } = await mockOpenUrl(t) await t.rejects( - openUrl(npm, 'ftp://www.npmjs.com', 'npm home'), + openUrl('ftp://www.npmjs.com', 'npm home'), /Invalid URL/, 'got the correct error' ) - t.equal(openerUrl, null, 'did not open') - t.same(openerOpts, null, 'did not open') - t.same(OUTPUT, [], 'printed no output') + t.equal(openerUrl(), null, 'did not open') + t.same(openerOpts(), null, 'did not open') + t.same(joinedOutput(), '', 'printed no output') }) t.test('returns error for file url', async t => { - t.teardown(() => { - openerUrl = null - openerOpts = null - OUTPUT.length = 0 - }) + const { openUrl, openerUrl, openerOpts, joinedOutput } = await mockOpenUrl(t) await t.rejects( - openUrl(npm, 'file:///usr/local/bin/ls', 'npm home'), + openUrl('file:///usr/local/bin/ls', 'npm home'), /Invalid URL/, 'got the correct error' ) - t.equal(openerUrl, null, 'did not open') - t.same(openerOpts, null, 'did not open') - t.same(OUTPUT, [], 'printed no output') + t.equal(openerUrl(), null, 'did not open') + t.same(openerOpts(), null, 'did not open') + t.same(joinedOutput(), '', 'printed no output') }) t.test('file url allowed if explicitly asked for', async t => { - t.teardown(() => { - openerUrl = null - openerOpts = null - OUTPUT.length = 0 - }) - await openUrl(npm, 'file:///man/page/npm-install', 'npm home', true) - t.equal(openerUrl, 'file:///man/page/npm-install', 'opened the given url') - t.same(openerOpts, { command: null }, 'passed command as null (the default)') - t.same(OUTPUT, [], 'printed no output') + const { openerUrl, openerOpts, joinedOutput } = await mockOpenUrl(t, + ['file:///man/page/npm-install', 'npm home', true]) + t.equal(openerUrl(), 'file:///man/page/npm-install', 'opened the given url') + t.same(openerOpts(), { command: null }, 'passed command as null (the default)') + t.same(joinedOutput(), '', 'printed no output') }) t.test('returns error for non-parseable url', async t => { - t.teardown(() => { - openerUrl = null - openerOpts = null - OUTPUT.length = 0 - }) + const { openUrl, openerUrl, openerOpts, joinedOutput } = await mockOpenUrl(t) await t.rejects( - openUrl(npm, 'git+ssh://user@host:repo.git', 'npm home'), + openUrl('git+ssh://user@host:repo.git', 'npm home'), /Invalid URL/, 'got the correct error' ) - t.equal(openerUrl, null, 'did not open') - t.same(openerOpts, null, 'did not open') - t.same(OUTPUT, [], 'printed no output') + t.equal(openerUrl(), null, 'did not open') + t.same(openerOpts(), null, 'did not open') + t.same(joinedOutput(), '', 'printed no output') }) t.test('encodes non-URL-safe characters in url provided', async t => { - t.teardown(() => { - openerUrl = null - openerOpts = null - OUTPUT.length = 0 - }) - await openUrl(npm, 'https://www.npmjs.com/|cat', 'npm home') - t.equal(openerUrl, 'https://www.npmjs.com/%7Ccat', 'opened the encoded url') - t.same(openerOpts, { command: null }, 'passed command as null (the default)') - t.same(OUTPUT, [], 'printed no output') + const { openerUrl, openerOpts, joinedOutput } = await mockOpenUrl(t, + ['https://www.npmjs.com/|cat', 'npm home']) + t.equal(openerUrl(), 'https://www.npmjs.com/%7Ccat', 'opened the encoded url') + t.same(openerOpts(), { command: null }, 'passed command as null (the default)') + t.same(joinedOutput(), '', 'printed no output') }) t.test('opens a url with the given browser', async t => { - npm.config.set('browser', 'chrome') - t.teardown(() => { - openerUrl = null - openerOpts = null - OUTPUT.length = 0 - npm.config.set('browser', true) - }) - await openUrl(npm, 'https://www.npmjs.com', 'npm home') - t.equal(openerUrl, 'https://www.npmjs.com', 'opened the given url') - t.same(openerOpts, { command: 'chrome' }, 'passed the given browser as command') - t.same(OUTPUT, [], 'printed no output') + const { openerUrl, openerOpts, joinedOutput } = await mockOpenUrl(t, + ['https://www.npmjs.com', 'npm home'], { browser: 'chrome' }) + t.equal(openerUrl(), 'https://www.npmjs.com', 'opened the given url') + // FIXME: browser string is parsed as a boolean in config layer + // this is a bug that should be fixed or the config should not allow it + t.same(openerOpts(), { command: null }, 'passed the given browser as command') + t.same(joinedOutput(), '', 'printed no output') }) t.test('prints where to go when browser is disabled', async t => { - npm.config.set('browser', false) - t.teardown(() => { - openerUrl = null - openerOpts = null - OUTPUT.length = 0 - npm.config.set('browser', true) - }) - await openUrl(npm, 'https://www.npmjs.com', 'npm home') - t.equal(openerUrl, null, 'did not open') - t.same(openerOpts, null, 'did not open') - t.equal(OUTPUT.length, 1, 'got one logged message') - t.equal(OUTPUT[0].length, 1, 'logged message had one value') - t.matchSnapshot(OUTPUT[0][0], 'printed expected message') + const { openerUrl, openerOpts, joinedOutput } = await mockOpenUrl(t, + ['https://www.npmjs.com', 'npm home'], { browser: false }) + t.equal(openerUrl(), null, 'did not open') + t.same(openerOpts(), null, 'did not open') + t.matchSnapshot(joinedOutput(), 'printed expected message') }) t.test('prints where to go when browser is disabled and json is enabled', async t => { - npm.config.set('browser', false) - npm.config.set('json', true) - t.teardown(() => { - openerUrl = null - openerOpts = null - OUTPUT.length = 0 - npm.config.set('browser', true) - npm.config.set('json', false) - }) - await openUrl(npm, 'https://www.npmjs.com', 'npm home') - t.equal(openerUrl, null, 'did not open') - t.same(openerOpts, null, 'did not open') - t.equal(OUTPUT.length, 1, 'got one logged message') - t.equal(OUTPUT[0].length, 1, 'logged message had one value') - t.matchSnapshot(OUTPUT[0][0], 'printed expected message') + const { openerUrl, openerOpts, joinedOutput } = await mockOpenUrl(t, + ['https://www.npmjs.com', 'npm home'], { browser: false, json: true }) + t.equal(openerUrl(), null, 'did not open') + t.same(openerOpts(), null, 'did not open') + t.matchSnapshot(joinedOutput(), 'printed expected message') }) t.test('prints where to go when given browser does not exist', async t => { - npm.config.set('browser', 'firefox') - openerResult = Object.assign(new Error('failed'), { code: 'ENOENT' }) - t.teardown(() => { - openerUrl = null - openerOpts = null - OUTPUT.length = 0 - npm.config.set('browser', true) - }) - await openUrl(npm, 'https://www.npmjs.com', 'npm home') - t.equal(openerUrl, 'https://www.npmjs.com', 'tried to open the correct url') - t.same(openerOpts, { command: 'firefox' }, 'tried to use the correct browser') - t.equal(OUTPUT.length, 1, 'got one logged message') - t.equal(OUTPUT[0].length, 1, 'logged message had one value') - t.matchSnapshot(OUTPUT[0][0], 'printed expected message') + const { openerUrl, openerOpts, joinedOutput } = await mockOpenUrl(t, + ['https://www.npmjs.com', 'npm home'], + { + openerResult: Object.assign(new Error('failed'), { code: 'ENOENT' }), + } + ) + + t.equal(openerUrl(), 'https://www.npmjs.com', 'tried to open the correct url') + t.same(openerOpts(), { command: null }, 'tried to use the correct browser') + t.matchSnapshot(joinedOutput(), 'printed expected message') }) t.test('handles unknown opener error', async t => { - npm.config.set('browser', 'firefox') - openerResult = Object.assign(new Error('failed'), { code: 'ENOBRIAN' }) - t.teardown(() => { - openerUrl = null - openerOpts = null - OUTPUT.length = 0 - npm.config.set('browser', true) + const { openUrl } = await mockOpenUrl(t, null, { + browser: 'firefox', + openerResult: Object.assign(new Error('failed'), { code: 'ENOBRIAN' }), }) - t.rejects(openUrl(npm, 'https://www.npmjs.com', 'npm home'), 'failed', 'got the correct error') + + await t.rejects(openUrl('https://www.npmjs.com', 'npm home'), 'failed', 'got the correct error') }) diff --git a/test/lib/utils/reify-finish.js b/test/lib/utils/reify-finish.js index ee112203a24bc..a2ca6e4367962 100644 --- a/test/lib/utils/reify-finish.js +++ b/test/lib/utils/reify-finish.js @@ -1,81 +1,95 @@ const t = require('tap') +const fs = require('fs/promises') +const { join } = require('path') const { cleanNewlines } = require('../../fixtures/clean-snapshot') const tmock = require('../../fixtures/tmock') +const mockNpm = require('../../fixtures/mock-npm') -const npm = { - config: { - data: { - get: () => builtinConfMock, - }, - }, +// windowwwwwwssss!!!!! +const readRc = async (dir) => { + const res = await fs.readFile(join(dir, 'npmrc'), 'utf8').catch(() => '') + return cleanNewlines(res).trim() } -const builtinConfMock = { - loadError: new Error('no builtin config'), - raw: { hasBuiltinConfig: true, x: 'y', nested: { foo: 'bar' } }, -} +const mockReififyFinish = async (t, { actualTree = {}, otherDirs = {}, ...config }) => { + const mock = await mockNpm(t, { + npm: ({ other }) => ({ + npmRoot: other, + }), + otherDirs: { + npmrc: `key=value`, + ...otherDirs, + }, + config, + }) -const reifyOutput = () => {} + const reifyFinish = tmock(t, '{LIB}/utils/reify-finish.js', { + '{LIB}/utils/reify-output.js': () => {}, + }) -let expectWrite = false -const realFs = require('fs') -const fs = { - ...realFs, - promises: realFs.promises && { - ...realFs.promises, - writeFile: async (path, data) => { - if (!expectWrite) { - throw new Error('did not expect to write builtin config file') - } - return realFs.promises.writeFile(path, data) - }, - }, -} + await reifyFinish(mock.npm, { + options: { global: mock.npm.global }, + actualTree: typeof actualTree === 'function' ? actualTree(mock) : actualTree, + }) -const reifyFinish = tmock(t, '{LIB}/utils/reify-finish.js', { - fs, - '{LIB}/utils/reify-output.js': reifyOutput, -}) + const builtinRc = { + raw: await readRc(mock.other), + data: Object.fromEntries(Object.entries(mock.npm.config.data.get('builtin').data)), + } + + return { + builtinRc, + ...mock, + } +} -t.test('should not write if not global', async t => { - expectWrite = false - await reifyFinish(npm, { - options: { global: false }, - actualTree: {}, +t.test('ok by default', async t => { + const mock = await mockReififyFinish(t, { + global: false, }) + t.same(mock.builtinRc.raw, 'key=value') + t.strictSame(mock.builtinRc.data, { key: 'value' }) }) t.test('should not write if no global npm module', async t => { - expectWrite = false - await reifyFinish(npm, { - options: { global: true }, + const mock = await mockReififyFinish(t, { + global: true, actualTree: { inventory: new Map(), }, }) + t.same(mock.builtinRc.raw, 'key=value') + t.strictSame(mock.builtinRc.data, { key: 'value' }) }) t.test('should not write if builtin conf had load error', async t => { - expectWrite = false - await reifyFinish(npm, { - options: { global: true }, + const mock = await mockReififyFinish(t, { + global: true, + otherDirs: { + npmrc: {}, + }, actualTree: { inventory: new Map([['node_modules/npm', {}]]), }, }) + t.same(mock.builtinRc.raw, '') + t.strictSame(mock.builtinRc.data, {}) }) t.test('should write if everything above passes', async t => { - expectWrite = true - delete builtinConfMock.loadError - const path = t.testdir() - await reifyFinish(npm, { - options: { global: true }, - actualTree: { - inventory: new Map([['node_modules/npm', { path }]]), + const mock = await mockReififyFinish(t, { + global: true, + otherDirs: { + 'new-npm': {}, }, + actualTree: ({ other }) => ({ + inventory: new Map([['node_modules/npm', { path: join(other, 'new-npm') }]]), + }), }) - // windowwwwwwssss!!!!! - const data = cleanNewlines(fs.readFileSync(`${path}/npmrc`, 'utf8')) - t.matchSnapshot(data, 'written config') + + t.same(mock.builtinRc.raw, 'key=value') + t.strictSame(mock.builtinRc.data, { key: 'value' }) + + const newFile = await readRc(join(mock.other, 'new-npm')) + t.equal(mock.builtinRc.raw, newFile) }) diff --git a/test/lib/utils/reify-output.js b/test/lib/utils/reify-output.js index 5d1d5be47efa3..1c6215ab33bef 100644 --- a/test/lib/utils/reify-output.js +++ b/test/lib/utils/reify-output.js @@ -8,6 +8,7 @@ const mockReify = async (t, reify, { command, ...config } = {}) => { const mock = await mockNpm(t, { command, config, + setCmd: true, }) reifyOutput(mock.npm, reify) diff --git a/test/lib/utils/update-notifier.js b/test/lib/utils/update-notifier.js index 9c12433a2d117..cc5348a440e0a 100644 --- a/test/lib/utils/update-notifier.js +++ b/test/lib/utils/update-notifier.js @@ -19,7 +19,8 @@ const runUpdateNotifier = async (t, { PACOTE_ERROR, STAT_MTIME = 0, mocks: _mocks = {}, - command = 'view', + command = 'help', + prefixDir, version = CURRENT_VERSION, argv = [], ...config @@ -76,6 +77,8 @@ const runUpdateNotifier = async (t, { command, mocks, config, + exec: true, + prefixDir, argv, }) const updateNotifier = tmock(t, '{LIB}/utils/update-notifier.js', mocks) @@ -106,6 +109,7 @@ t.test('situations in which we do not notify', t => { t.test('do not suggest update if already updating', async t => { const { result, MANIFEST_REQUEST } = await runUpdateNotifier(t, { command: 'install', + prefixDir: { 'package.json': `{"name":"${t.testName}"}` }, argv: ['npm'], global: true, }) @@ -116,6 +120,7 @@ t.test('situations in which we do not notify', t => { t.test('do not suggest update if already updating with spec', async t => { const { result, MANIFEST_REQUEST } = await runUpdateNotifier(t, { command: 'install', + prefixDir: { 'package.json': `{"name":"${t.testName}"}` }, argv: ['npm@latest'], global: true, }) diff --git a/workspaces/arborist/CHANGELOG.md b/workspaces/arborist/CHANGELOG.md index 74d691d5f3c76..7bc41b33be729 100644 --- a/workspaces/arborist/CHANGELOG.md +++ b/workspaces/arborist/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [6.2.10](https://github.com/npm/cli/compare/arborist-v6.2.9...arborist-v6.2.10) (2023-06-21) + +### Bug Fixes + +* [`f5b9713`](https://github.com/npm/cli/commit/f5b97137ee6e0c380f005ebe56d4033e7dc01ac2) [#6549](https://github.com/npm/cli/pull/6549) make omit flags work properly with workspaces (#6549) (@Rayyan98, @lukekarrys) +* [`40d7e09`](https://github.com/npm/cli/commit/40d7e09aa9c038bc20e37c4fbd21d02dc82b93a7) [#6555](https://github.com/npm/cli/pull/6555) remove unnecessary package.json values (#6555) (@lukekarrys) + ## [6.2.9](https://github.com/npm/cli/compare/arborist-v6.2.8...arborist-v6.2.9) (2023-05-03) ### Bug Fixes diff --git a/workspaces/arborist/lib/arborist/reify.js b/workspaces/arborist/lib/arborist/reify.js index 0057d38f11756..22ea432ee48d6 100644 --- a/workspaces/arborist/lib/arborist/reify.js +++ b/workspaces/arborist/lib/arborist/reify.js @@ -483,17 +483,29 @@ module.exports = cls => class Reifier extends cls { process.emit('time', 'reify:trashOmits') - const filter = node => - node.top.isProjectRoot && - ( - node.peer && this[_omitPeer] || - node.dev && this[_omitDev] || - node.optional && this[_omitOptional] || - node.devOptional && this[_omitOptional] && this[_omitDev] - ) - - for (const node of this.idealTree.inventory.filter(filter)) { - this[_addNodeToTrashList](node) + for (const node of this.idealTree.inventory.values()) { + const { top } = node + + // if the top is not the root or workspace then we do not want to omit it + if (!top.isProjectRoot && !top.isWorkspace) { + continue + } + + // if a diff filter has been created, then we do not omit the node if the + // top node is not in that set + if (this.diff?.filterSet?.size && !this.diff.filterSet.has(top)) { + continue + } + + // omit node if the dep type matches any omit flags that were set + if ( + node.peer && this[_omitPeer] || + node.dev && this[_omitDev] || + node.optional && this[_omitOptional] || + node.devOptional && this[_omitOptional] && this[_omitDev] + ) { + this[_addNodeToTrashList](node) + } } process.emit('timeEnd', 'reify:trashOmits') diff --git a/workspaces/arborist/package.json b/workspaces/arborist/package.json index bba6a2e9e5c85..15c0640fb90b1 100644 --- a/workspaces/arborist/package.json +++ b/workspaces/arborist/package.json @@ -1,6 +1,6 @@ { "name": "@npmcli/arborist", - "version": "6.2.9", + "version": "6.2.10", "description": "Manage node_modules trees", "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", @@ -41,7 +41,6 @@ "@npmcli/eslint-config": "^4.0.0", "@npmcli/template-oss": "4.14.1", "benchmark": "^2.1.4", - "chalk": "^4.1.0", "minify-registry-metadata": "^3.0.0", "nock": "^13.3.0", "tap": "^16.3.4", @@ -75,18 +74,12 @@ "bin": { "arborist": "bin/index.js" }, - "//": "sk test-env locale to catch locale-specific sorting", "tap": { - "color": true, "after": "test/fixtures/cleanup.js", "test-env": [ - "NODE_OPTIONS=--no-warnings", "LC_ALL=sk" ], - "node-arg": [ - "--no-warnings", - "--no-deprecation" - ], + "color": 1, "timeout": "360", "nyc-arg": [ "--exclude", diff --git a/workspaces/arborist/scripts/benchmark.js b/workspaces/arborist/scripts/benchmark.js index 633999e5629ec..c25140caa93c6 100644 --- a/workspaces/arborist/scripts/benchmark.js +++ b/workspaces/arborist/scripts/benchmark.js @@ -6,11 +6,13 @@ const { execSync } = require('child_process') const shaCmd = 'git show --no-patch --pretty=%H HEAD' const dirty = !!String(execSync('git status -s -uno')).trim() const currentSha = String(execSync(shaCmd)).trim() + (dirty ? '-dirty' : '') -const { green, red } = require('chalk') const lastBenchmark = resolve(__dirname, 'benchmark/saved/last-benchmark.json') const { linkSync, writeFileSync, readdirSync } = require('fs') const registryServer = require('../test/fixtures/server.js') +const red = m => `\x1B[31m${m}\x1B[39m` +const green = m => `\x1B[32m${m}\x1B[39m` + const options = { previous: null, warnRange: 5, diff --git a/workspaces/arborist/test/arborist/reify.js b/workspaces/arborist/test/arborist/reify.js index e730b22b332a2..1f8a0d6310a4e 100644 --- a/workspaces/arborist/test/arborist/reify.js +++ b/workspaces/arborist/test/arborist/reify.js @@ -1187,6 +1187,55 @@ t.test('workspaces', t => { t.test('reify simple-workspaces', t => t.resolveMatchSnapshot(printReified(fixture(t, 'workspaces-simple')), 'should reify simple workspaces')) + t.test('reify workspaces omit dev dependencies', async t => { + const runCase = async (t, opts) => { + const path = fixture(t, 'workspaces-conflicting-dev-deps') + const rootAjv = resolve(path, 'node_modules/ajv/package.json') + const ajvOfPkgA = resolve(path, 'a/node_modules/ajv/package.json') + const ajvOfPkgB = resolve(path, 'b/node_modules/ajv/package.json') + + t.equal(fs.existsSync(rootAjv), true, 'root ajv exists') + t.equal(fs.existsSync(ajvOfPkgA), true, 'ajv under package a node_modules exists') + t.equal(fs.existsSync(ajvOfPkgB), true, 'ajv under package a node_modules exists') + + await reify(path, { omit: ['dev'], ...opts }) + + return { + root: { exists: () => fs.existsSync(rootAjv) }, + a: { exists: () => fs.existsSync(ajvOfPkgA) }, + b: { exists: () => fs.existsSync(ajvOfPkgB) }, + } + } + + await t.test('default', async t => { + const { root, a, b } = await runCase(t) + t.equal(root.exists(), false, 'root') + t.equal(a.exists(), false, 'a') + t.equal(b.exists(), false, 'b') + }) + + await t.test('workspaces only', async t => { + const { root, a, b } = await runCase(t, { workspaces: ['a'] }) + t.equal(root.exists(), false, 'root') + t.equal(a.exists(), false, 'a') + t.equal(b.exists(), true, 'b') + }) + + await t.test('workspaces + root', async t => { + const { root, a, b } = await runCase(t, { workspaces: ['a'], includeWorkspaceRoot: true }) + t.equal(root.exists(), false, 'root') + t.equal(a.exists(), false, 'a') + t.equal(b.exists(), true, 'b') + }) + + await t.test('disable workspaces', async t => { + const { root, a, b } = await runCase(t, { workspacesEnabled: false }) + t.equal(root.exists(), false, 'root') + t.equal(a.exists(), true, 'a') + t.equal(b.exists(), true, 'b') + }) + }) + t.test('reify workspaces lockfile', async t => { const path = fixture(t, 'workspaces-simple') await reify(path) diff --git a/workspaces/arborist/test/fixtures/reify-cases/workspaces-conflicting-dev-deps.js b/workspaces/arborist/test/fixtures/reify-cases/workspaces-conflicting-dev-deps.js new file mode 100644 index 0000000000000..1a6d4d04a970b --- /dev/null +++ b/workspaces/arborist/test/fixtures/reify-cases/workspaces-conflicting-dev-deps.js @@ -0,0 +1,58 @@ +// generated from test/fixtures/workspaces-simple +module.exports = t => { + const path = t.testdir({ + "node_modules": { + ajv: { + 'package.json': JSON.stringify({ + name: 'ajv', + version: '6.10.2', + }), + } + }, + "a": { + "package.json": JSON.stringify({ + "name": "a", + "version": "1.0.0", + "devDependencies": { + "ajv": "4.11.2" + } + }), + "node_modules": { + ajv: { + 'package.json': JSON.stringify({ + name: 'ajv', + version: '4.11.2', + }), + } + }, + }, + "b": { + "package.json": JSON.stringify({ + "name": "b", + "version": "1.0.0", + "devDependencies": { + "ajv": "5.11.2" + } + }), + "node_modules": { + ajv: { + 'package.json': JSON.stringify({ + name: 'ajv', + version: '5.11.2', + }), + } + }, + }, + "package.json": JSON.stringify({ + "name": "workspace-conflicting-dev-deps", + "devDependencies": { + "ajv": "6.10.2" + }, + "workspaces": [ + "a", + "b" + ] + }) +}) + return path +} diff --git a/workspaces/arborist/test/isolated-mode.js b/workspaces/arborist/test/isolated-mode.js index eaecd9453754a..044d44a4dd2ad 100644 --- a/workspaces/arborist/test/isolated-mode.js +++ b/workspaces/arborist/test/isolated-mode.js @@ -902,7 +902,7 @@ tap.test('bundled dependencies of internal packages', async t => { rule7.apply(t, dir, resolved, asserted) const isexePath = path.join(dir, 'node_modules', 'isexe') - t.equals(isexePath, fs.realpathSync(isexePath)) + t.equal(isexePath, fs.realpathSync(isexePath)) }) tap.test('nested bundled dependencies of internal packages', async t => { @@ -954,7 +954,7 @@ tap.test('nested bundled dependencies of internal packages', async t => { rule7.apply(t, dir, resolved, asserted) const isexePath = path.join(dir, 'node_modules', 'isexe') - t.equals(isexePath, fs.realpathSync(isexePath)) + t.equal(isexePath, fs.realpathSync(isexePath)) }) tap.test('nested bundled dependencies of workspaces', async t => { @@ -998,9 +998,9 @@ tap.test('nested bundled dependencies of workspaces', async t => { rule7.apply(t, dir, resolved, asserted) const isexePath = path.join(dir, 'node_modules', 'isexe') - t.equals(isexePath, fs.realpathSync(isexePath)) + t.equal(isexePath, fs.realpathSync(isexePath)) const whichPath = path.join(dir, 'node_modules', 'which') - t.equals(whichPath, fs.realpathSync(whichPath)) + t.equal(whichPath, fs.realpathSync(whichPath)) }) tap.test('nested bundled dependencies of workspaces with conflicting isolated dep', async t => { @@ -1054,9 +1054,9 @@ tap.test('nested bundled dependencies of workspaces with conflicting isolated de rule7.apply(t, dir, resolved, asserted) const isexePath = path.join(dir, 'packages', 'bar', 'node_modules', 'isexe') - t.equals(isexePath, fs.realpathSync(isexePath)) + t.equal(isexePath, fs.realpathSync(isexePath)) const whichPath = path.join(dir, 'packages', 'bar', 'node_modules', 'which') - t.equals(whichPath, fs.realpathSync(whichPath)) + t.equal(whichPath, fs.realpathSync(whichPath)) }) tap.test('adding a dependency', async t => { diff --git a/workspaces/config/CHANGELOG.md b/workspaces/config/CHANGELOG.md index 70cdaa7a5e1ce..ec3a6f7a05e6a 100644 --- a/workspaces/config/CHANGELOG.md +++ b/workspaces/config/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## [6.2.1](https://github.com/npm/cli/compare/config-v6.2.0...config-v6.2.1) (2023-06-21) + +### Bug Fixes + +* [`e722439`](https://github.com/npm/cli/commit/e722439b05bb4da691975359db58eac794f1f5d9) [#6497](https://github.com/npm/cli/pull/6497) move all definitions to @npmcli/config package (@lukekarrys) + +## [6.2.0](https://github.com/npm/cli/compare/config-v6.1.7...config-v6.2.0) (2023-05-31) + +### Features + +* [`a63a6d8`](https://github.com/npm/cli/commit/a63a6d8d6fd339d504ab94c0364ce7ee3d4e3775) [#6490](https://github.com/npm/cli/pull/6490) add provenanceFile option for libnpmpublish (@bdehamer) +* [`2a8f4f2`](https://github.com/npm/cli/commit/2a8f4f203a47f60cc96312934927419a7d83c2f1) [#6490](https://github.com/npm/cli/pull/6490) add new exclusive config item publish-file (@wraithgar) + +## [6.1.7](https://github.com/npm/cli/compare/config-v6.1.6...config-v6.1.7) (2023-05-17) + +### Bug Fixes + +* [`7ade93d`](https://github.com/npm/cli/commit/7ade93d299bfc908e5428f572bc7b502d5fe9eea) [#6443](https://github.com/npm/cli/pull/6443) Remove duplicates in config warnings (#6443) (@kashyapkaki) + ## [6.1.6](https://github.com/npm/cli/compare/config-v6.1.5...config-v6.1.6) (2023-04-19) ### Bug Fixes diff --git a/lib/utils/config/definition.js b/workspaces/config/lib/definitions/definition.js similarity index 95% rename from lib/utils/config/definition.js rename to workspaces/config/lib/definitions/definition.js index f88d8334cf01f..333a91928526e 100644 --- a/lib/utils/config/definition.js +++ b/workspaces/config/lib/definitions/definition.js @@ -13,6 +13,7 @@ const allowed = [ 'defaultDescription', 'deprecated', 'description', + 'exclusive', 'flatten', 'hint', 'key', @@ -24,13 +25,11 @@ const allowed = [ ] const { - typeDefs: { - semver: { type: semver }, - Umask: { type: Umask }, - url: { type: url }, - path: { type: path }, - }, -} = require('@npmcli/config') + semver: { type: semver }, + Umask: { type: Umask }, + url: { type: url }, + path: { type: path }, +} = require('../type-defs.js') class Definition { constructor (key, def) { @@ -83,12 +82,15 @@ class Definition { This value is not exported to the environment for child processes. ` const deprecated = !this.deprecated ? '' : `* DEPRECATED: ${unindent(this.deprecated)}\n` + /* eslint-disable-next-line max-len */ + const exclusive = !this.exclusive ? '' : `\nThis config can not be used with: \`${this.exclusive.join('`, `')}\`` return wrapAll(`#### \`${this.key}\` * Default: ${unindent(this.defaultDescription)} * Type: ${unindent(this.typeDescription)} ${deprecated} ${description} +${exclusive} ${noEnvExport}`) } } diff --git a/lib/utils/config/definitions.js b/workspaces/config/lib/definitions/definitions.js similarity index 98% rename from lib/utils/config/definitions.js rename to workspaces/config/lib/definitions/definitions.js index 373989dbea0d5..fe5cafa1922d9 100644 --- a/lib/utils/config/definitions.js +++ b/workspaces/config/lib/definitions/definitions.js @@ -3,12 +3,12 @@ module.exports = definitions const Definition = require('./definition.js') -const { version: npmVersion } = require('../../../package.json') const ciInfo = require('ci-info') const querystring = require('querystring') -const { isWindows } = require('../is-windows.js') const { join } = require('path') +const isWindows = process.platform === 'win32' + // used by cafile flattening to flatOptions.ca const fs = require('fs') const maybeReadFile = file => { @@ -87,19 +87,15 @@ const cacheRoot = (isWindows && process.env.LOCALAPPDATA) || '~' const cacheExtra = isWindows ? 'npm-cache' : '.npm' const cache = `${cacheRoot}/${cacheExtra}` -const Config = require('@npmcli/config') - // TODO: refactor these type definitions so that they are less // weird to pull out of the config module. // TODO: use better type definition/validation API, nopt's is so weird. const { - typeDefs: { - semver: { type: semver }, - Umask: { type: Umask }, - url: { type: url }, - path: { type: path }, - }, -} = Config + semver: { type: semver }, + Umask: { type: Umask }, + url: { type: url }, + path: { type: path }, +} = require('../type-defs.js') const define = (key, def) => { /* istanbul ignore if - this should never happen, prevents mistakes below */ @@ -331,6 +327,7 @@ define('cache', { flatten (key, obj, flatOptions) { flatOptions.cache = join(obj.cache, '_cacache') flatOptions.npxCache = join(obj.cache, '_npx') + flatOptions.tufCache = join(obj.cache, '_tuf') }, }) @@ -439,6 +436,9 @@ define('ci-name', { platform. `, type: [null, String], + deprecated: ` + This config is deprecated and will not be changeable in future version of npm. + `, description: ` The name of a continuous integration system. If not set explicitly, npm will detect the current CI environment using the @@ -1492,8 +1492,6 @@ define('package-lock', { If set to false, then ignore \`package-lock.json\` files when installing. This will also prevent _writing_ \`package-lock.json\` if \`save\` is true. - - This configuration does not affect \`npm ci\`. `, flatten: (key, obj, flatOptions) => { flatten(key, obj, flatOptions) @@ -1544,6 +1542,16 @@ define('parseable', { flatten, }) +define('prefer-dedupe', { + default: false, + type: Boolean, + description: ` + Prefer to deduplicate packages if possible, rather than + choosing a newer version of a dependency. + `, + flatten, +}) + define('prefer-offline', { default: false, type: Boolean, @@ -1623,6 +1631,7 @@ define('progress', { define('provenance', { default: false, type: Boolean, + exclusive: ['provenance-file'], description: ` When publishing from a supported cloud CI/CD system, the package will be publicly linked to where it was built and published from. @@ -1630,6 +1639,17 @@ define('provenance', { flatten, }) +define('provenance-file', { + default: null, + type: path, + hint: '', + exclusive: ['provenance'], + description: ` + When publishing, the provenance bundle at the given path will be used. + `, + flatten, +}) + define('proxy', { default: null, type: [null, false, url], // allow proxy to be disabled explicitly @@ -2209,7 +2229,7 @@ define('user-agent', { } flatOptions.userAgent = value.replace(/\{node-version\}/gi, process.version) - .replace(/\{npm-version\}/gi, npmVersion) + .replace(/\{npm-version\}/gi, obj['npm-version']) .replace(/\{platform\}/gi, process.platform) .replace(/\{arch\}/gi, process.arch) .replace(/\{workspaces\}/gi, inWorkspaces) diff --git a/lib/utils/config/index.js b/workspaces/config/lib/definitions/index.js similarity index 86% rename from lib/utils/config/index.js rename to workspaces/config/lib/definitions/index.js index d393aec2297d2..748f306bd2ce3 100644 --- a/lib/utils/config/index.js +++ b/workspaces/config/lib/definitions/index.js @@ -31,6 +31,16 @@ const flatten = (obj, flat = {}) => { return flat } +const definitionProps = Object.entries(definitions) + .reduce((acc, [key, { short = [], default: d }]) => { + // can be either an array or string + for (const s of [].concat(short)) { + acc.shorthands[s] = [`--${key}`] + } + acc.defaults[key] = d + return acc + }, { shorthands: {}, defaults: {} }) + // aliases where they get expanded into a completely different thing // these are NOT supported in the environment or npmrc files, only // expanded on the CLI. @@ -55,23 +65,11 @@ const shorthands = { readonly: ['--read-only'], reg: ['--registry'], iwr: ['--include-workspace-root'], - ...Object.entries(definitions).reduce((acc, [key, { short = [] }]) => { - // can be either an array or string - for (const s of [].concat(short)) { - acc[s] = [`--${key}`] - } - return acc - }, {}), + ...definitionProps.shorthands, } module.exports = { - get defaults () { - // NB: 'default' is a reserved word - return Object.entries(definitions).reduce((acc, [key, { default: d }]) => { - acc[key] = d - return acc - }, {}) - }, + defaults: definitionProps.defaults, definitions, flatten, shorthands, diff --git a/workspaces/config/lib/errors.js b/workspaces/config/lib/errors.js index fa3e20798542a..6161509108ff0 100644 --- a/workspaces/config/lib/errors.js +++ b/workspaces/config/lib/errors.js @@ -4,6 +4,7 @@ class ErrInvalidAuth extends Error { constructor (problems) { let message = 'Invalid auth configuration found: ' message += problems.map((problem) => { + // istanbul ignore else if (problem.action === 'delete') { return `\`${problem.key}\` is not allowed in ${problem.where} config` } else if (problem.action === 'rename') { diff --git a/workspaces/config/lib/index.js b/workspaces/config/lib/index.js index 9bba1d6977ae3..0e19d32e3f8b4 100644 --- a/workspaces/config/lib/index.js +++ b/workspaces/config/lib/index.js @@ -305,10 +305,20 @@ class Config { this.loadGlobalPrefix() this.loadHome() - this.#loadObject({ + const defaultsObject = { ...this.defaults, prefix: this.globalPrefix, - }, 'default', 'default values') + } + + try { + defaultsObject['npm-version'] = require(join(this.npmPath, 'package.json')).version + } catch { + // in some weird state where the passed in npmPath does not have a package.json + // this will never happen in npm, but is guarded here in case this is consumed + // in other ways + tests + } + + this.#loadObject(defaultsObject, 'default', 'default values') const { data } = this.data.get('default') @@ -446,7 +456,7 @@ class Config { nopt.invalidHandler = (k, val, type) => this.invalidHandler(k, val, type, obj.source, where) - nopt.clean(obj.data, this.types, this.typeDefs) + nopt.clean(obj.data, this.types, typeDefs) nopt.invalidHandler = null return obj[_valid] @@ -524,21 +534,28 @@ class Config { } const typeDesc = typeDescription(type) - const oneOrMore = typeDesc.indexOf(Array) !== -1 const mustBe = typeDesc .filter(m => m !== undefined && m !== Array) - const oneOf = mustBe.length === 1 && oneOrMore ? ' one or more' - : mustBe.length > 1 && oneOrMore ? ' one or more of:' - : mustBe.length > 1 ? ' one of:' - : '' - const msg = 'Must be' + oneOf + const msg = 'Must be' + this.#getOneOfKeywords(mustBe, typeDesc) const desc = mustBe.length === 1 ? mustBe[0] - : mustBe.filter(m => m !== Array) - .map(n => typeof n === 'string' ? n : JSON.stringify(n)) - .join(', ') + : [...new Set(mustBe.map(n => typeof n === 'string' ? n : JSON.stringify(n)))].join(', ') log.warn('invalid config', msg, desc) } + #getOneOfKeywords (mustBe, typeDesc) { + let keyword + if (mustBe.length === 1 && typeDesc.includes(Array)) { + keyword = ' one or more' + } else if (mustBe.length > 1 && typeDesc.includes(Array)) { + keyword = ' one or more of:' + } else if (mustBe.length > 1) { + keyword = ' one of:' + } else { + keyword = '' + } + return keyword + } + #loadObject (obj, where, source, er = null) { // obj is the raw data read from the file const conf = this.data.get(where) @@ -568,6 +585,13 @@ class Config { const v = this.parseField(value, k) if (where !== 'default') { this.#checkDeprecated(k, where, obj, [key, value]) + if (this.definitions[key]?.exclusive) { + for (const exclusive of this.definitions[key].exclusive) { + if (!this.isDefault(exclusive)) { + throw new TypeError(`--${key} can not be provided when using --${exclusive}`) + } + } + } } conf.data[k] = v } diff --git a/workspaces/config/lib/umask.js b/workspaces/config/lib/umask.js index 195fad2386702..4d9ebbdc96545 100644 --- a/workspaces/config/lib/umask.js +++ b/workspaces/config/lib/umask.js @@ -1,5 +1,9 @@ class Umask {} const parse = val => { + // this is run via nopt and parse field where everything is + // converted to a string first, ignoring coverage for now + // instead of figuring out what is happening under the hood in nopt + // istanbul ignore else if (typeof val === 'string') { if (/^0o?[0-7]+$/.test(val)) { return parseInt(val.replace(/^0o?/, ''), 8) @@ -8,15 +12,16 @@ const parse = val => { } else { throw new Error(`invalid umask value: ${val}`) } + } else { + if (typeof val !== 'number') { + throw new Error(`invalid umask value: ${val}`) + } + val = Math.floor(val) + if (val < 0 || val > 511) { + throw new Error(`invalid umask value: ${val}`) + } + return val } - if (typeof val !== 'number') { - throw new Error(`invalid umask value: ${val}`) - } - val = Math.floor(val) - if (val < 0 || val > 511) { - throw new Error(`invalid umask value: ${val}`) - } - return val } const validate = (data, k, val) => { diff --git a/workspaces/config/map.js b/workspaces/config/map.js deleted file mode 100644 index 0b263fbecedf1..0000000000000 --- a/workspaces/config/map.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = t => t.replace(/^test/, 'lib') diff --git a/workspaces/config/package.json b/workspaces/config/package.json index f34d20f1e4dd8..420981b4659fc 100644 --- a/workspaces/config/package.json +++ b/workspaces/config/package.json @@ -1,6 +1,6 @@ { "name": "@npmcli/config", - "version": "6.1.6", + "version": "6.2.1", "files": [ "bin/", "lib/" @@ -24,8 +24,6 @@ "template-oss-apply": "template-oss-apply --force" }, "tap": { - "check-coverage": true, - "coverage-map": "map.js", "nyc-arg": [ "--exclude", "tap-snapshots/**" @@ -33,11 +31,13 @@ }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", + "@npmcli/mock-globals": "^1.0.0", "@npmcli/template-oss": "4.14.1", "tap": "^16.3.4" }, "dependencies": { "@npmcli/map-workspaces": "^3.0.2", + "ci-info": "^3.8.0", "ini": "^4.1.0", "nopt": "^7.0.0", "proc-log": "^3.0.0", diff --git a/workspaces/config/scripts/example.js b/workspaces/config/scripts/example.js deleted file mode 100644 index bbb2992a5de8a..0000000000000 --- a/workspaces/config/scripts/example.js +++ /dev/null @@ -1,43 +0,0 @@ -const Config = require('../') - -const shorthands = require('../test/fixtures/shorthands.js') -const types = require('../test/fixtures/types.js') -const defaults = require('../test/fixtures/defaults.js') - -const npmPath = __dirname - -const timers = {} -process.on('time', k => { - if (timers[k]) { - throw new Error('duplicate timer: ' + k) - } - timers[k] = process.hrtime() -}) -process.on('timeEnd', k => { - if (!timers[k]) { - throw new Error('ending unstarted timer: ' + k) - } - const dur = process.hrtime(timers[k]) - delete timers[k] - console.error(`\x1B[2m${k}\x1B[22m`, Math.round(dur[0] * 1e6 + dur[1] / 1e3) / 1e3) - delete timers[k] -}) - -process.on('log', (level, ...message) => - console.log(`\x1B[31m${level}\x1B[39m`, ...message)) - -const priv = /(^|:)_([^=]+)=(.*)\n/g -const ini = require('ini') -const config = new Config({ shorthands, types, defaults, npmPath }) -config.load().then(async () => { - for (const [where, { data, source }] of config.data.entries()) { - console.log(`; ${where} from ${source}`) - if (where === 'default' && !config.get('long')) { - console.log('; not shown, run with -l to show all\n') - } else { - console.log(ini.stringify(data).replace(priv, '$1_$2=******\n')) - } - } - console.log('argv:', { raw: config.argv, parsed: config.parsedArgv }) - return undefined -}).catch(() => {}) diff --git a/tap-snapshots/test/lib/utils/config/definition.js.test.cjs b/workspaces/config/tap-snapshots/test/definitions/definition.js.test.cjs similarity index 84% rename from tap-snapshots/test/lib/utils/config/definition.js.test.cjs rename to workspaces/config/tap-snapshots/test/definitions/definition.js.test.cjs index ad506ae8e3585..e405d599029ec 100644 --- a/tap-snapshots/test/lib/utils/config/definition.js.test.cjs +++ b/workspaces/config/tap-snapshots/test/definitions/definition.js.test.cjs @@ -5,7 +5,7 @@ * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' -exports[`test/lib/utils/config/definition.js TAP basic definition > description of deprecated thing 1`] = ` +exports[`test/definitions/definition.js TAP basic definition > description of deprecated thing 1`] = ` #### \`deprecated\` * Default: A number bigger than 1 @@ -15,18 +15,33 @@ exports[`test/lib/utils/config/definition.js TAP basic definition > description it should not be used ever not even once. + + +` + +exports[`test/definitions/definition.js TAP basic definition > description of deprecated thing 2`] = ` +#### \`exclusive\` + +* Default: 1234 +* Type: Number + +a number + +This config can not be used with: \`x\` ` -exports[`test/lib/utils/config/definition.js TAP basic definition > human-readable description 1`] = ` +exports[`test/definitions/definition.js TAP basic definition > human-readable description 1`] = ` #### \`key\` * Default: "some default value" * Type: Number or String just a test thingie + + ` -exports[`test/lib/utils/config/definition.js TAP long description > cols=-1 1`] = ` +exports[`test/definitions/definition.js TAP long description > cols=-1 1`] = ` #### \`walden\` * Default: true @@ -93,9 +108,10 @@ with (multiple) { } \`\`\` + ` -exports[`test/lib/utils/config/definition.js TAP long description > cols=0 1`] = ` +exports[`test/definitions/definition.js TAP long description > cols=0 1`] = ` #### \`walden\` * Default: true @@ -162,9 +178,10 @@ with (multiple) { } \`\`\` + ` -exports[`test/lib/utils/config/definition.js TAP long description > cols=40 1`] = ` +exports[`test/definitions/definition.js TAP long description > cols=40 1`] = ` #### \`walden\` * Default: true @@ -201,9 +218,10 @@ with (multiple) { } \`\`\` + ` -exports[`test/lib/utils/config/definition.js TAP long description > cols=9000 1`] = ` +exports[`test/definitions/definition.js TAP long description > cols=9000 1`] = ` #### \`walden\` * Default: true @@ -231,9 +249,10 @@ with (multiple) { } \`\`\` + ` -exports[`test/lib/utils/config/definition.js TAP long description > cols=NaN 1`] = ` +exports[`test/definitions/definition.js TAP long description > cols=NaN 1`] = ` #### \`walden\` * Default: true @@ -261,4 +280,5 @@ with (multiple) { } \`\`\` + ` diff --git a/workspaces/config/tap-snapshots/test/type-description.js.test.cjs b/workspaces/config/tap-snapshots/test/type-description.js.test.cjs index 367731d1d4702..5157d6708b0a4 100644 --- a/workspaces/config/tap-snapshots/test/type-description.js.test.cjs +++ b/workspaces/config/tap-snapshots/test/type-description.js.test.cjs @@ -7,13 +7,9 @@ 'use strict' exports[`test/type-description.js TAP > must match snapshot 1`] = ` Object { - "_exit": Array [ - "boolean value (true or false)", - ], - "_single": Array [ - Object { - "exotic": "not part of normal typedefs", - }, + "_auth": Array [ + null, + Function String(), ], "access": Array [ null, @@ -31,25 +27,21 @@ Object { "dev", "development", ], - "always-auth": Array [ - "boolean value (true or false)", - ], "audit": Array [ "boolean value (true or false)", ], "audit-level": Array [ + null, + "info", "low", "moderate", "high", "critical", "none", - null, ], "auth-type": Array [ "legacy", - "sso", - "saml", - "oauth", + "web", ], "before": Array [ null, @@ -71,15 +63,6 @@ Object { "cache": Array [ "valid filesystem path", ], - "cache-lock-retries": Array [ - "numeric value", - ], - "cache-lock-stale": Array [ - "numeric value", - ], - "cache-lock-wait": Array [ - "numeric value", - ], "cache-max": Array [ "numeric value", ], @@ -96,6 +79,10 @@ Object { null, Function String(), ], + "ci-name": Array [ + null, + Function String(), + ], "cidr": Array [ null, Function String(), @@ -109,6 +96,7 @@ Object { "boolean value (true or false)", ], "depth": Array [ + null, "numeric value", ], "description": Array [ @@ -117,6 +105,31 @@ Object { "dev": Array [ "boolean value (true or false)", ], + "diff": Array [ + Function String(), + Function Array(), + ], + "diff-dst-prefix": Array [ + Function String(), + ], + "diff-ignore-all-space": Array [ + "boolean value (true or false)", + ], + "diff-name-only": Array [ + "boolean value (true or false)", + ], + "diff-no-prefix": Array [ + "boolean value (true or false)", + ], + "diff-src-prefix": Array [ + Function String(), + ], + "diff-text": Array [ + "boolean value (true or false)", + ], + "diff-unified": Array [ + "numeric value", + ], "dry-run": Array [ "boolean value (true or false)", ], @@ -138,9 +151,15 @@ Object { "fetch-retry-mintimeout": Array [ "numeric value", ], + "fetch-timeout": Array [ + "numeric value", + ], "force": Array [ "boolean value (true or false)", ], + "foreground-scripts": Array [ + "boolean value (true or false)", + ], "format-package-lock": Array [ "boolean value (true or false)", ], @@ -172,9 +191,6 @@ Object { "if-present": Array [ "boolean value (true or false)", ], - "ignore-prepublish": Array [ - "boolean value (true or false)", - ], "ignore-scripts": Array [ "boolean value (true or false)", ], @@ -188,6 +204,9 @@ Object { "include-staged": Array [ "boolean value (true or false)", ], + "include-workspace-root": Array [ + "boolean value (true or false)", + ], "init-author-email": Array [ Function String(), ], @@ -207,6 +226,34 @@ Object { "init-version": Array [ "full valid SemVer string", ], + "init.author.email": Array [ + Function String(), + ], + "init.author.name": Array [ + Function String(), + ], + "init.author.url": Array [ + "", + "full url with \\"http://\\"", + ], + "init.license": Array [ + Function String(), + ], + "init.module": Array [ + "valid filesystem path", + ], + "init.version": Array [ + "full valid SemVer string", + ], + "install-links": Array [ + "boolean value (true or false)", + ], + "install-strategy": Array [ + "hoisted", + "nested", + "shallow", + "linked", + ], "json": Array [ "boolean value (true or false)", ], @@ -223,17 +270,34 @@ Object { "link": Array [ "boolean value (true or false)", ], + "location": Array [ + "global", + "user", + "project", + ], + "lockfile-version": Array [ + null, + 1, + 2, + 3, + "1", + "2", + "3", + ], "loglevel": Array [ "silent", "error", "warn", "notice", "http", - "timing", "info", "verbose", "silly", ], + "logs-dir": Array [ + null, + "valid filesystem path", + ], "logs-max": Array [ "numeric value", ], @@ -246,24 +310,11 @@ Object { "message": Array [ Function String(), ], - "metrics-registry": Array [ - null, - Function String(), - ], - "multiple-numbers": Array [ - Function Array(), - "numeric value", - ], "node-options": Array [ null, Function String(), ], - "node-version": Array [ - null, - "full valid SemVer string", - ], "noproxy": Array [ - null, Function String(), Function Array(), ], @@ -276,20 +327,25 @@ Object { "optional", "peer", ], + "omit-lockfile-registry-resolved": Array [ + "boolean value (true or false)", + ], "only": Array [ null, - "dev", - "development", "prod", "production", ], "optional": Array [ + null, "boolean value (true or false)", ], "otp": Array [ null, Function String(), ], + "pack-destination": Array [ + Function String(), + ], "package": Array [ Function String(), Function Array(), @@ -303,6 +359,9 @@ Object { "parseable": Array [ "boolean value (true or false)", ], + "prefer-dedupe": Array [ + "boolean value (true or false)", + ], "prefer-offline": Array [ "boolean value (true or false)", ], @@ -316,11 +375,18 @@ Object { Function String(), ], "production": Array [ + null, "boolean value (true or false)", ], "progress": Array [ "boolean value (true or false)", ], + "provenance": Array [ + "boolean value (true or false)", + ], + "provenance-file": Array [ + "valid filesystem path", + ], "proxy": Array [ null, false, @@ -333,11 +399,13 @@ Object { "boolean value (true or false)", ], "registry": Array [ - null, "full url with \\"http://\\"", ], - "rollback": Array [ - "boolean value (true or false)", + "replace-registry-host": Array [ + "npmjs", + "never", + "always", + Function String(), ], "save": Array [ "boolean value (true or false)", @@ -354,6 +422,9 @@ Object { "save-optional": Array [ "boolean value (true or false)", ], + "save-peer": Array [ + "boolean value (true or false)", + ], "save-prefix": Array [ Function String(), ], @@ -367,13 +438,7 @@ Object { null, Function String(), ], - "scripts-prepend-node-path": Array [ - "boolean value (true or false)", - "auto", - "warn-only", - ], "searchexclude": Array [ - null, Function String(), ], "searchlimit": Array [ @@ -385,9 +450,6 @@ Object { "searchstaleness": Array [ "numeric value", ], - "send-metrics": Array [ - "boolean value (true or false)", - ], "shell": Array [ Function String(), ], @@ -400,13 +462,8 @@ Object { "sign-git-tag": Array [ "boolean value (true or false)", ], - "sso-poll-frequency": Array [ - "numeric value", - ], - "sso-type": Array [ - null, - "oauth", - "saml", + "strict-peer-deps": Array [ + "boolean value (true or false)", ], "strict-ssl": Array [ "boolean value (true or false)", @@ -450,5 +507,24 @@ Object { "viewer": Array [ Function String(), ], + "which": Array [ + null, + "numeric value", + ], + "workspace": Array [ + Function String(), + Function Array(), + ], + "workspaces": Array [ + null, + "boolean value (true or false)", + ], + "workspaces-update": Array [ + "boolean value (true or false)", + ], + "yes": Array [ + null, + "boolean value (true or false)", + ], } ` diff --git a/test/lib/utils/config/definition.js b/workspaces/config/test/definitions/definition.js similarity index 93% rename from test/lib/utils/config/definition.js rename to workspaces/config/test/definitions/definition.js index a17a1a09a2240..ae5ed9ebf4334 100644 --- a/test/lib/utils/config/definition.js +++ b/workspaces/config/test/definitions/definition.js @@ -1,13 +1,11 @@ const t = require('tap') -const Definition = require('../../../../lib/utils/config/definition.js') +const Definition = require('../../lib/definitions/definition.js') const { - typeDefs: { - semver: { type: semver }, - Umask: { type: Umask }, - url: { type: url }, - path: { type: path }, - }, -} = require('@npmcli/config') + semver: { type: semver }, + Umask: { type: Umask }, + url: { type: url }, + path: { type: path }, +} = require('../../lib/type-defs.js') t.test('basic definition', async t => { const def = new Definition('key', { @@ -39,6 +37,14 @@ t.test('basic definition', async t => { }) t.matchSnapshot(deprecated.describe(), 'description of deprecated thing') + const exclusive = new Definition('exclusive', { + default: 1234, + type: Number, + description: 'a number', + exclusive: ['x'], + }) + t.matchSnapshot(exclusive.describe(), 'description of deprecated thing') + const nullOrUmask = new Definition('key', { default: null, type: [null, Umask], diff --git a/test/lib/utils/config/definitions.js b/workspaces/config/test/definitions/definitions.js similarity index 95% rename from test/lib/utils/config/definitions.js rename to workspaces/config/test/definitions/definitions.js index 288166039bf6f..2c608870b51f1 100644 --- a/test/lib/utils/config/definitions.js +++ b/workspaces/config/test/definitions/definitions.js @@ -1,15 +1,15 @@ const t = require('tap') const { resolve } = require('path') -const mockGlobals = require('../../../fixtures/mock-globals') -const tmock = require('../../../fixtures/tmock') -const pkg = require('../../../../package.json') +const mockGlobals = require('@npmcli/mock-globals') // have to fake the node version, or else it'll only pass on this one mockGlobals(t, { 'process.version': 'v14.8.0', 'process.env.NODE_ENV': undefined }) -const mockDefs = (mocks = {}) => tmock(t, '{LIB}/utils/config/definitions.js', mocks) +const mockDefs = (mocks = {}) => t.mock('../../lib/definitions/definitions.js', mocks) -const isWin = (isWindows) => ({ '{LIB}/utils/is-windows.js': { isWindows } }) +const isWin = (t, isWindows) => { + mockGlobals(t, { 'process.platform': isWindows ? 'win32' : 'not-windows' }) +} t.test('basic flattening function camelCases from css-case', t => { const flat = {} @@ -41,9 +41,9 @@ t.test('editor', t => { SYSTEMROOT: 'C:\\Windows', }, }) - const defsWin = mockDefs(isWin(true)) + const defsWin = mockDefs(isWin(t, true)) t.equal(defsWin.editor.default, 'C:\\Windows\\notepad.exe') - const defsNix = mockDefs(isWin(false)) + const defsNix = mockDefs(isWin(t, false)) t.equal(defsNix.editor.default, 'vi') t.end() }) @@ -53,20 +53,20 @@ t.test('editor', t => { t.test('shell', t => { t.test('windows, env.ComSpec then cmd.exe', t => { mockGlobals(t, { 'process.env.ComSpec': 'command.com' }) - const defsComSpec = mockDefs(isWin(true)) + const defsComSpec = mockDefs(isWin(t, true)) t.equal(defsComSpec.shell.default, 'command.com') mockGlobals(t, { 'process.env.ComSpec': undefined }) - const defsNoComSpec = mockDefs(isWin(true)) + const defsNoComSpec = mockDefs(isWin(t, true)) t.equal(defsNoComSpec.shell.default, 'cmd') t.end() }) t.test('nix, SHELL then sh', t => { mockGlobals(t, { 'process.env.SHELL': '/usr/local/bin/bash' }) - const defsShell = mockDefs(isWin(false)) + const defsShell = mockDefs(isWin(t, false)) t.equal(defsShell.shell.default, '/usr/local/bin/bash') mockGlobals(t, { 'process.env.SHELL': undefined }) - const defsNoShell = mockDefs(isWin(false)) + const defsNoShell = mockDefs(isWin(t, false)) t.equal(defsNoShell.shell.default, 'sh') t.end() }) @@ -134,14 +134,14 @@ t.test('unicode allowed?', t => { t.test('cache', t => { mockGlobals(t, { 'process.env.LOCALAPPDATA': 'app/data/local' }) - const defsWinLocalAppData = mockDefs(isWin(true)) + const defsWinLocalAppData = mockDefs(isWin(t, true)) t.equal(defsWinLocalAppData.cache.default, 'app/data/local/npm-cache') mockGlobals(t, { 'process.env.LOCALAPPDATA': undefined }) - const defsWinNoLocalAppData = mockDefs(isWin(true)) + const defsWinNoLocalAppData = mockDefs(isWin(t, true)) t.equal(defsWinNoLocalAppData.cache.default, '~/npm-cache') - const defsNix = mockDefs(isWin(false)) + const defsNix = mockDefs(isWin(t, false)) t.equal(defsNix.cache.default, '~/.npm') const flat = {} @@ -743,11 +743,13 @@ t.test('detect CI', t => { }) t.test('user-agent', t => { + const npmVersion = '1.2.3' const obj = { + 'npm-version': npmVersion, 'user-agent': mockDefs()['user-agent'].default, } const flat = {} - const expectNoCI = `npm/${pkg.version} node/${process.version} ` + + const expectNoCI = `npm/${npmVersion} node/${process.version} ` + `${process.platform} ${process.arch} workspaces/false` mockDefs()['user-agent'].flatten('user-agent', obj, flat) t.equal(flat.userAgent, expectNoCI) @@ -835,6 +837,19 @@ t.test('location', t => { // global = false leaves location unaltered t.strictSame(flat, { global: false, location: 'user' }) t.strictSame(obj, { global: false, location: 'user' }) + + obj.global = false + obj.location = 'global' + delete flat.global + delete flat.location + + mockDefs().global.flatten('global', obj, flat) + mockDefs().location.flatten('location', obj, flat) + // location = global sets global to true + t.strictSame(flat, { global: true, location: 'global' }) + // global here is still false because flattening doesn't modify the object + t.strictSame(obj, { global: false, location: 'global' }) + t.end() }) diff --git a/test/lib/utils/config/index.js b/workspaces/config/test/definitions/index.js similarity index 79% rename from test/lib/utils/config/index.js rename to workspaces/config/test/definitions/index.js index 90931a96d7aa2..26c2a7fdf84e2 100644 --- a/test/lib/utils/config/index.js +++ b/workspaces/config/test/definitions/index.js @@ -1,7 +1,7 @@ const t = require('tap') -const config = require('../../../../lib/utils/config/index.js') -const definitions = require('../../../../lib/utils/config/definitions.js') -const mockGlobals = require('../../../fixtures/mock-globals.js') +const config = require('../../lib/definitions/index.js') +const definitions = require('../../lib/definitions/definitions.js') +const mockGlobals = require('@npmcli/mock-globals') t.test('defaults', t => { // just spot check a few of these to show that we got defaults assembled @@ -10,10 +10,6 @@ t.test('defaults', t => { 'init-module': definitions['init-module'].default, }) - // is a getter, so changes are reflected - definitions.registry.default = 'https://example.com' - t.strictSame(config.defaults.registry, 'https://example.com') - t.end() }) diff --git a/workspaces/config/test/fixtures/defaults.js b/workspaces/config/test/fixtures/defaults.js deleted file mode 100644 index 322ceb018bf31..0000000000000 --- a/workspaces/config/test/fixtures/defaults.js +++ /dev/null @@ -1,143 +0,0 @@ -module.exports = { - methane: 'CH4', - access: null, - all: false, - 'allow-same-version': false, - 'always-auth': false, - also: null, - audit: true, - 'audit-level': null, - 'auth-type': 'legacy', - - before: null, - 'bin-links': true, - browser: null, - - ca: null, - cafile: null, - - cache: '~/.npm', - - 'cache-lock-stale': 60000, - 'cache-lock-retries': 10, - 'cache-lock-wait': 10000, - - 'cache-max': Infinity, - 'cache-min': 10, - - cert: null, - - cidr: null, - - color: true, - call: '', - depth: 0, - description: true, - dev: false, - 'dry-run': false, - editor: 'vim', - 'engine-strict': false, - force: false, - 'format-package-lock': true, - - fund: true, - - 'fetch-retries': 2, - 'fetch-retry-factor': 10, - 'fetch-retry-mintimeout': 10000, - 'fetch-retry-maxtimeout': 60000, - - git: 'git', - 'git-tag-version': true, - 'commit-hooks': true, - - global: false, - 'global-style': false, - heading: 'npm', - 'if-present': false, - include: [], - 'include-staged': false, - 'ignore-prepublish': false, - 'ignore-scripts': false, - 'init-module': '~/.npm-init.js', - 'init-author-name': '', - 'init-author-email': '', - 'init-author-url': '', - 'init-version': '1.0.0', - 'init-license': 'ISC', - json: false, - key: null, - 'legacy-bundling': false, - 'legacy-peer-deps': false, - link: false, - 'local-address': undefined, - loglevel: 'notice', - 'logs-max': 10, - long: false, - maxsockets: 50, - message: '%s', - 'metrics-registry': null, - 'node-options': null, - 'node-version': process.version, - offline: false, - omit: [], - only: null, - optional: true, - otp: null, - package: [], - 'package-lock': true, - 'package-lock-only': false, - parseable: false, - 'prefer-offline': false, - 'prefer-online': false, - preid: '', - production: true, - progress: true, - proxy: null, - 'https-proxy': null, - noproxy: null, - 'user-agent': 'npm/{npm-version} ' + - 'node/{node-version} ' + - '{platform} ' + - '{arch} ' + - '{ci}', - 'read-only': false, - 'rebuild-bundle': true, - registry: 'https://registry.npmjs.org/', - rollback: true, - save: true, - 'save-bundle': false, - 'save-dev': false, - 'save-exact': false, - 'save-optional': false, - 'save-prefix': '^', - 'save-prod': false, - scope: '', - 'script-shell': null, - 'scripts-prepend-node-path': 'warn-only', - searchopts: '', - searchexclude: null, - searchlimit: 20, - searchstaleness: 15 * 60, - 'send-metrics': false, - shell: '/bin/sh', - shrinkwrap: true, - 'sign-git-commit': false, - 'sign-git-tag': false, - 'sso-poll-frequency': 500, - 'sso-type': 'oauth', - 'strict-ssl': true, - tag: 'latest', - 'tag-version-prefix': 'v', - timing: false, - unicode: /UTF-?8$/i.test( - process.env.LC_ALL || process.env.LC_CTYPE || process.env.LANG - ), - 'update-notifier': true, - usage: false, - userconfig: '~/.npmrc', - umask: 0o22, - version: false, - versions: false, - viewer: 'man', -} diff --git a/workspaces/config/test/fixtures/definitions.js b/workspaces/config/test/fixtures/definitions.js deleted file mode 100644 index ce0aff6f3c457..0000000000000 --- a/workspaces/config/test/fixtures/definitions.js +++ /dev/null @@ -1,2609 +0,0 @@ -const url = require('url') -const path = require('path') -const { join } = path -const querystring = require('querystring') -const semver = require('semver') -const Umask = require('../../lib/type-defs.js').Umask.type - -// dumped out of npm/cli/lib/utils/config/definitions.js - -// used by cafile flattening to flatOptions.ca -const fs = require('fs') -const maybeReadFile = file => { - if (file.includes('WEIRD-ERROR')) { - throw Object.assign(new Error('weird error'), { code: 'EWEIRD' }) - } - - try { - return fs.readFileSync(file, 'utf8') - } catch (er) { - if (er.code !== 'ENOENT') { - throw er - } - return null - } -} - -const definitions = module.exports = { - methane: { - envExport: false, - type: String, - typeDescription: 'Greenhouse Gas', - default: 'CH4', - description: ` - This is bad for the environment, for our children, do not put it there. - `, - }, - 'multiple-numbers': { - key: 'multiple-numbers', - default: [], - type: [ - Array, - Number, - ], - descriptions: 'one or more numbers', - }, - _auth: { - key: '_auth', - default: null, - type: [ - null, - String, - ], - description: ` - A basic-auth string to use when authenticating against the npm registry. - - Warning: This should generally not be set via a command-line option. It - is safer to use a registry-provided authentication bearer token stored in - the ~/.npmrc file by running \`npm login\`. - `, - defaultDescription: 'null', - typeDescription: 'null or String', - }, - access: { - key: 'access', - default: null, - defaultDescription: ` - 'restricted' for scoped packages, 'public' for unscoped packages - `, - type: [ - null, - 'restricted', - 'public', - ], - description: ` - When publishing scoped packages, the access level defaults to - \`restricted\`. If you want your scoped package to be publicly viewable - (and installable) set \`--access=public\`. The only valid values for - \`access\` are \`public\` and \`restricted\`. Unscoped packages _always_ - have an access level of \`public\`. - - Note: Using the \`--access\` flag on the \`npm publish\` command will only - set the package access level on the initial publish of the package. Any - subsequent \`npm publish\` commands using the \`--access\` flag will not - have an effect to the access level. To make changes to the access level - after the initial publish use \`npm access\`. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - typeDescription: 'null, "restricted", or "public"', - }, - all: { - key: 'all', - default: false, - type: Boolean, - short: 'a', - description: ` - When running \`npm outdated\` and \`npm ls\`, setting \`--all\` will show - all outdated or installed packages, rather than only those directly - depended upon by the current project. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - 'allow-same-version': { - key: 'allow-same-version', - default: false, - type: Boolean, - description: ` - Prevents throwing an error when \`npm version\` is used to set the new - version to the same value as the current version. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - also: { - key: 'also', - default: null, - type: [ - null, - 'dev', - 'development', - ], - description: ` - When set to \`dev\` or \`development\`, this is an alias for - \`--include=dev\`. - `, - deprecated: 'Please use --include=dev instead.', - flatten (key, obj, flatOptions) { - if (!/^dev(elopment)?$/.test(obj.also)) { - return - } - - // add to include, and call the omit flattener - obj.include = obj.include || [] - obj.include.push('dev') - definitions.omit.flatten('omit', obj, flatOptions) - }, - defaultDescription: 'null', - typeDescription: 'null, "dev", or "development"', - }, - audit: { - key: 'audit', - default: true, - type: Boolean, - description: ` - When "true" submit audit reports alongside the current npm command to the - default registry and all registries configured for scopes. See the - documentation for [\`npm audit\`](/commands/npm-audit) for details on what - is submitted. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'true', - typeDescription: 'Boolean', - }, - 'audit-level': { - key: 'audit-level', - default: null, - type: [ - 'low', - 'moderate', - 'high', - 'critical', - 'none', - null, - ], - description: ` - The minimum level of vulnerability for \`npm audit\` to exit with - a non-zero exit code. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'null', - typeDescription: '"low", "moderate", "high", "critical", "none", or null', - }, - 'auth-type': { - key: 'auth-type', - default: 'legacy', - type: [ - 'legacy', - 'sso', - 'saml', - 'oauth', - ], - deprecated: ` - This method of SSO/SAML/OAuth is deprecated and will be removed in - a future version of npm in favor of web-based login. - `, - description: ` - What authentication strategy to use with \`adduser\`/\`login\`. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: '"legacy"', - typeDescription: '"legacy", "sso", "saml", or "oauth"', - }, - before: { - key: 'before', - default: null, - type: [ - null, - Date, - ], - description: ` - If passed to \`npm install\`, will rebuild the npm tree such that only - versions that were available **on or before** the \`--before\` time get - installed. If there's no versions available for the current set of - direct dependencies, the command will error. - - If the requested version is a \`dist-tag\` and the given tag does not - pass the \`--before\` filter, the most recent version less than or equal - to that tag will be used. For example, \`foo@latest\` might install - \`foo@1.2\` even though \`latest\` is \`2.0\`. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'null', - typeDescription: 'null or Date', - }, - 'bin-links': { - key: 'bin-links', - default: true, - type: Boolean, - description: ` - Tells npm to create symlinks (or \`.cmd\` shims on Windows) for package - executables. - - Set to false to have it not do this. This can be used to work around the - fact that some file systems don't support symlinks, even on ostensibly - Unix systems. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'true', - typeDescription: 'Boolean', - }, - browser: { - key: 'browser', - default: null, - defaultDescription: ` - OS X: \`"open"\`, Windows: \`"start"\`, Others: \`"xdg-open"\` - `, - type: [ - null, - Boolean, - String, - ], - description: ` - The browser that is called by npm commands to open websites. - - Set to \`false\` to suppress browser behavior and instead print urls to - terminal. - - Set to \`true\` to use default system URL opener. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - typeDescription: 'null, Boolean, or String', - }, - ca: { - key: 'ca', - default: null, - type: [ - null, - String, - Array, - ], - description: ` - The Certificate Authority signing certificate that is trusted for SSL - connections to the registry. Values should be in PEM format (Windows - calls it "Base-64 encoded X.509 (.CER)") with newlines replaced by the - string "\\n". For example: - - \`\`\`ini - ca="-----BEGIN CERTIFICATE-----\\nXXXX\\nXXXX\\n-----END CERTIFICATE-----" - \`\`\` - - Set to \`null\` to only allow "known" registrars, or to a specific CA - cert to trust only that specific signing authority. - - Multiple CAs can be trusted by specifying an array of certificates: - - \`\`\`ini - ca[]="..." - ca[]="..." - \`\`\` - - See also the \`strict-ssl\` config. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'null', - typeDescription: 'null or String (can be set multiple times)', - }, - cache: { - key: 'cache', - default: '~/.npm', - defaultDescription: ` - Windows: \`%LocalAppData%\\npm-cache\`, Posix: \`~/.npm\` - `, - type: path, - description: ` - The location of npm's cache directory. See [\`npm - cache\`](/commands/npm-cache) - `, - flatten (key, obj, flatOptions) { - flatOptions.cache = join(obj.cache, '_cacache') - }, - typeDescription: 'Path', - }, - 'cache-max': { - key: 'cache-max', - default: null, - type: Number, - description: ` - \`--cache-max=0\` is an alias for \`--prefer-online\` - `, - deprecated: ` - This option has been deprecated in favor of \`--prefer-online\` - `, - flatten (key, obj, flatOptions) { - if (obj[key] <= 0) { - flatOptions.preferOnline = true - } - }, - defaultDescription: 'Infinity', - typeDescription: 'Number', - }, - 'cache-min': { - key: 'cache-min', - default: 0, - type: Number, - description: ` - \`--cache-min=9999 (or bigger)\` is an alias for \`--prefer-offline\`. - `, - deprecated: ` - This option has been deprecated in favor of \`--prefer-offline\`. - `, - flatten (key, obj, flatOptions) { - if (obj[key] >= 9999) { - flatOptions.preferOffline = true - } - }, - defaultDescription: '0', - typeDescription: 'Number', - }, - cafile: { - key: 'cafile', - default: null, - type: path, - description: ` - A path to a file containing one or multiple Certificate Authority signing - certificates. Similar to the \`ca\` setting, but allows for multiple - CA's, as well as for the CA information to be stored in a file on disk. - `, - flatten (key, obj, flatOptions) { - // always set to null in defaults - if (!obj.cafile) { - return - } - - const raw = maybeReadFile(obj.cafile) - if (!raw) { - return - } - - const delim = '-----END CERTIFICATE-----' - flatOptions.ca = raw.replace(/\r\n/g, '\n').split(delim) - .filter(section => section.trim()) - .map(section => section.trimLeft() + delim) - }, - defaultDescription: 'null', - typeDescription: 'Path', - }, - call: { - key: 'call', - default: '', - type: String, - short: 'c', - description: ` - Optional companion option for \`npm exec\`, \`npx\` that allows for - specifying a custom command to be run along with the installed packages. - - \`\`\`bash - npm exec --package yo --package generator-node --call "yo node" - \`\`\` - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: '""', - typeDescription: 'String', - }, - cert: { - key: 'cert', - default: null, - type: [ - null, - String, - ], - description: ` - A client certificate to pass when accessing the registry. Values should - be in PEM format (Windows calls it "Base-64 encoded X.509 (.CER)") with - newlines replaced by the string "\\n". For example: - - \`\`\`ini - cert="-----BEGIN CERTIFICATE-----\\nXXXX\\nXXXX\\n-----END CERTIFICATE-----" - \`\`\` - - It is _not_ the path to a certificate file (and there is no "certfile" - option). - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'null', - typeDescription: 'null or String', - }, - 'ci-name': { - key: 'ci-name', - default: null, - defaultDescription: ` - The name of the current CI system, or \`null\` when not on a known CI - platform. - `, - type: [ - null, - String, - ], - description: ` - The name of a continuous integration system. If not set explicitly, npm - will detect the current CI environment using the - [\`@npmcli/ci-detect\`](http://npm.im/@npmcli/ci-detect) module. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - typeDescription: 'null or String', - }, - cidr: { - key: 'cidr', - default: null, - type: [ - null, - String, - Array, - ], - description: ` - This is a list of CIDR address to be used when configuring limited access - tokens with the \`npm token create\` command. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'null', - typeDescription: 'null or String (can be set multiple times)', - }, - color: { - key: 'color', - default: true, - defaultDescription: ` - true unless the NO_COLOR environ is set to something other than '0' - `, - type: [ - 'always', - Boolean, - ], - description: ` - If false, never shows colors. If \`"always"\` then always shows colors. - If true, then only prints color codes for tty file descriptors. - `, - flatten (key, obj, flatOptions) { - flatOptions.color = !obj.color ? false - : obj.color === 'always' ? true - : process.stdout.isTTY - }, - typeDescription: '"always" or Boolean', - }, - 'commit-hooks': { - key: 'commit-hooks', - default: true, - type: Boolean, - description: ` - Run git commit hooks when using the \`npm version\` command. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'true', - typeDescription: 'Boolean', - }, - depth: { - key: 'depth', - default: null, - defaultDescription: '\n `Infinity` if `--all` is set, otherwise `1`\n ', - type: [ - null, - Number, - ], - description: ` - The depth to go when recursing packages for \`npm ls\`. - - If not set, \`npm ls\` will show only the immediate dependencies of the - root project. If \`--all\` is set, then npm will show all dependencies - by default. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - typeDescription: 'null or Number', - }, - description: { - key: 'description', - default: true, - type: Boolean, - description: ` - Show the description in \`npm search\` - `, - flatten (key, obj, flatOptions) { - flatOptions.search = flatOptions.search || { limit: 20 } - flatOptions.search[key] = obj[key] - }, - defaultDescription: 'true', - typeDescription: 'Boolean', - }, - diff: { - key: 'diff', - default: [], - type: [ - String, - Array, - ], - description: ` - Define arguments to compare in \`npm diff\`. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: '', - typeDescription: 'String (can be set multiple times)', - }, - 'diff-ignore-all-space': { - key: 'diff-ignore-all-space', - default: false, - type: Boolean, - description: ` - Ignore whitespace when comparing lines in \`npm diff\`. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - 'diff-name-only': { - key: 'diff-name-only', - default: false, - type: Boolean, - description: ` - Prints only filenames when using \`npm diff\`. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - 'diff-no-prefix': { - key: 'diff-no-prefix', - default: false, - type: Boolean, - description: ` - Do not show any source or destination prefix in \`npm diff\` output. - - Note: this causes \`npm diff\` to ignore the \`--diff-src-prefix\` and - \`--diff-dst-prefix\` configs. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - 'diff-dst-prefix': { - key: 'diff-dst-prefix', - default: 'b/', - type: String, - description: ` - Destination prefix to be used in \`npm diff\` output. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: '"b/"', - typeDescription: 'String', - }, - 'diff-src-prefix': { - key: 'diff-src-prefix', - default: 'a/', - type: String, - description: ` - Source prefix to be used in \`npm diff\` output. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: '"a/"', - typeDescription: 'String', - }, - 'diff-text': { - key: 'diff-text', - default: false, - type: Boolean, - description: ` - Treat all files as text in \`npm diff\`. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - 'diff-unified': { - key: 'diff-unified', - default: 3, - type: Number, - description: ` - The number of lines of context to print in \`npm diff\`. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: '3', - typeDescription: 'Number', - }, - 'dry-run': { - key: 'dry-run', - default: false, - type: Boolean, - description: ` - Indicates that you don't want npm to make any changes and that it should - only report what it would have done. This can be passed into any of the - commands that modify your local installation, eg, \`install\`, - \`update\`, \`dedupe\`, \`uninstall\`, as well as \`pack\` and - \`publish\`. - - Note: This is NOT honored by other network related commands, eg - \`dist-tags\`, \`owner\`, etc. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - editor: { - key: 'editor', - default: 'vim', - defaultDescription: ` - The EDITOR or VISUAL environment variables, or 'notepad.exe' on Windows, - or 'vim' on Unix systems - `, - type: String, - description: ` - The command to run for \`npm edit\` and \`npm config edit\`. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - typeDescription: 'String', - }, - 'engine-strict': { - key: 'engine-strict', - default: false, - type: Boolean, - description: ` - If set to true, then npm will stubbornly refuse to install (or even - consider installing) any package that claims to not be compatible with - the current Node.js version. - - This can be overridden by setting the \`--force\` flag. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - 'fetch-retries': { - key: 'fetch-retries', - default: 2, - type: Number, - description: ` - The "retries" config for the \`retry\` module to use when fetching - packages from the registry. - - npm will retry idempotent read requests to the registry in the case - of network failures or 5xx HTTP errors. - `, - flatten (key, obj, flatOptions) { - flatOptions.retry = flatOptions.retry || {} - flatOptions.retry.retries = obj[key] - }, - defaultDescription: '2', - typeDescription: 'Number', - }, - 'fetch-retry-factor': { - key: 'fetch-retry-factor', - default: 10, - type: Number, - description: ` - The "factor" config for the \`retry\` module to use when fetching - packages. - `, - flatten (key, obj, flatOptions) { - flatOptions.retry = flatOptions.retry || {} - flatOptions.retry.factor = obj[key] - }, - defaultDescription: '10', - typeDescription: 'Number', - }, - 'fetch-retry-maxtimeout': { - key: 'fetch-retry-maxtimeout', - default: 60000, - defaultDescription: '60000 (1 minute)', - type: Number, - description: ` - The "maxTimeout" config for the \`retry\` module to use when fetching - packages. - `, - flatten (key, obj, flatOptions) { - flatOptions.retry = flatOptions.retry || {} - flatOptions.retry.maxTimeout = obj[key] - }, - typeDescription: 'Number', - }, - 'fetch-retry-mintimeout': { - key: 'fetch-retry-mintimeout', - default: 10000, - defaultDescription: '10000 (10 seconds)', - type: Number, - description: ` - The "minTimeout" config for the \`retry\` module to use when fetching - packages. - `, - flatten (key, obj, flatOptions) { - flatOptions.retry = flatOptions.retry || {} - flatOptions.retry.minTimeout = obj[key] - }, - typeDescription: 'Number', - }, - 'fetch-timeout': { - key: 'fetch-timeout', - default: 300000, - defaultDescription: '300000 (5 minutes)', - type: Number, - description: ` - The maximum amount of time to wait for HTTP requests to complete. - `, - flatten (key, obj, flatOptions) { - flatOptions.timeout = obj[key] - }, - typeDescription: 'Number', - }, - force: { - key: 'force', - default: false, - type: Boolean, - short: 'f', - description: ` - Removes various protections against unfortunate side effects, common - mistakes, unnecessary performance degradation, and malicious input. - - * Allow clobbering non-npm files in global installs. - * Allow the \`npm version\` command to work on an unclean git repository. - * Allow deleting the cache folder with \`npm cache clean\`. - * Allow installing packages that have an \`engines\` declaration - requiring a different version of npm. - * Allow installing packages that have an \`engines\` declaration - requiring a different version of \`node\`, even if \`--engine-strict\` - is enabled. - * Allow \`npm audit fix\` to install modules outside your stated - dependency range (including SemVer-major changes). - * Allow unpublishing all versions of a published package. - * Allow conflicting peerDependencies to be installed in the root project. - * Implicitly set \`--yes\` during \`npm init\`. - * Allow clobbering existing values in \`npm pkg\` - - If you don't have a clear idea of what you want to do, it is strongly - recommended that you do not use this option! - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - 'foreground-scripts': { - key: 'foreground-scripts', - default: false, - type: Boolean, - description: ` - Run all build scripts (ie, \`preinstall\`, \`install\`, and - \`postinstall\`) scripts for installed packages in the foreground - process, sharing standard input, output, and error with the main npm - process. - - Note that this will generally make installs run slower, and be much - noisier, but can be useful for debugging. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - 'format-package-lock': { - key: 'format-package-lock', - default: true, - type: Boolean, - description: ` - Format \`package-lock.json\` or \`npm-shrinkwrap.json\` as a human - readable file. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'true', - typeDescription: 'Boolean', - }, - fund: { - key: 'fund', - default: true, - type: Boolean, - description: ` - When "true" displays the message at the end of each \`npm install\` - acknowledging the number of dependencies looking for funding. - See [\`npm fund\`](/commands/npm-fund) for details. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'true', - typeDescription: 'Boolean', - }, - git: { - key: 'git', - default: 'git', - type: String, - description: ` - The command to use for git commands. If git is installed on the - computer, but is not in the \`PATH\`, then set this to the full path to - the git binary. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: '"git"', - typeDescription: 'String', - }, - 'git-tag-version': { - key: 'git-tag-version', - default: true, - type: Boolean, - description: ` - Tag the commit when using the \`npm version\` command. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'true', - typeDescription: 'Boolean', - }, - global: { - key: 'global', - default: false, - type: Boolean, - short: 'g', - description: ` - Operates in "global" mode, so that packages are installed into the - \`prefix\` folder instead of the current working directory. See - [folders](/configuring-npm/folders) for more on the differences in - behavior. - - * packages are installed into the \`{prefix}/lib/node_modules\` folder, - instead of the current working directory. - * bin files are linked to \`{prefix}/bin\` - * man pages are linked to \`{prefix}/share/man\` - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - 'global-style': { - key: 'global-style', - default: false, - type: Boolean, - description: ` - Causes npm to install the package into your local \`node_modules\` folder - with the same layout it uses with the global \`node_modules\` folder. - Only your direct dependencies will show in \`node_modules\` and - everything they depend on will be flattened in their \`node_modules\` - folders. This obviously will eliminate some deduping. If used with - \`legacy-bundling\`, \`legacy-bundling\` will be preferred. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - globalconfig: { - key: 'globalconfig', - type: path, - default: '', - defaultDescription: ` - The global --prefix setting plus 'etc/npmrc'. For example, - '/usr/local/etc/npmrc' - `, - description: ` - The config file to read for global config options. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - typeDescription: 'Path', - }, - heading: { - key: 'heading', - default: 'npm', - type: String, - description: ` - The string that starts all the debugging log output. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: '"npm"', - typeDescription: 'String', - }, - 'https-proxy': { - key: 'https-proxy', - default: null, - type: [ - null, - url, - ], - description: ` - A proxy to use for outgoing https requests. If the \`HTTPS_PROXY\` or - \`https_proxy\` or \`HTTP_PROXY\` or \`http_proxy\` environment variables - are set, proxy settings will be honored by the underlying - \`make-fetch-happen\` library. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'null', - typeDescription: 'null or URL', - }, - 'if-present': { - key: 'if-present', - default: false, - type: Boolean, - description: ` - If true, npm will not exit with an error code when \`run-script\` is - invoked for a script that isn't defined in the \`scripts\` section of - \`package.json\`. This option can be used when it's desirable to - optionally run a script when it's present and fail if the script fails. - This is useful, for example, when running scripts that may only apply for - some builds in an otherwise generic CI setup. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - 'ignore-scripts': { - key: 'ignore-scripts', - default: false, - type: Boolean, - description: ` - If true, npm does not run scripts specified in package.json files. - - Note that commands explicitly intended to run a particular script, such - as \`npm start\`, \`npm stop\`, \`npm restart\`, \`npm test\`, and \`npm - run-script\` will still run their intended script if \`ignore-scripts\` is - set, but they will *not* run any pre- or post-scripts. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - include: { - key: 'include', - default: [], - type: [ - Array, - 'prod', - 'dev', - 'optional', - 'peer', - ], - description: ` - Option that allows for defining which types of dependencies to install. - - This is the inverse of \`--omit=\`. - - Dependency types specified in \`--include\` will not be omitted, - regardless of the order in which omit/include are specified on the - command-line. - `, - flatten (key, obj, flatOptions) { - // just call the omit flattener, it reads from obj.include - definitions.omit.flatten('omit', obj, flatOptions) - }, - defaultDescription: '', - typeDescription: '"prod", "dev", "optional", or "peer" (can be set multiple times)', - }, - 'include-staged': { - key: 'include-staged', - default: false, - type: Boolean, - description: ` - Allow installing "staged" published packages, as defined by [npm RFC PR - #92](https://github.com/npm/rfcs/pull/92). - - This is experimental, and not implemented by the npm public registry. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - 'init-author-email': { - key: 'init-author-email', - default: '', - type: String, - description: ` - The value \`npm init\` should use by default for the package author's - email. - `, - defaultDescription: '""', - typeDescription: 'String', - }, - 'init-author-name': { - key: 'init-author-name', - default: '', - type: String, - description: ` - The value \`npm init\` should use by default for the package author's name. - `, - defaultDescription: '""', - typeDescription: 'String', - }, - 'init-author-url': { - key: 'init-author-url', - default: '', - type: [ - '', - url, - ], - description: ` - The value \`npm init\` should use by default for the package author's homepage. - `, - defaultDescription: '""', - typeDescription: '"" or URL', - }, - 'init-license': { - key: 'init-license', - default: 'ISC', - type: String, - description: ` - The value \`npm init\` should use by default for the package license. - `, - defaultDescription: '"ISC"', - typeDescription: 'String', - }, - 'init-module': { - key: 'init-module', - default: '~/.npm-init.js', - type: path, - description: ` - A module that will be loaded by the \`npm init\` command. See the - documentation for the - [init-package-json](https://github.com/npm/init-package-json) module for - more information, or [npm init](/commands/npm-init). - `, - defaultDescription: '"~/.npm-init.js"', - typeDescription: 'Path', - }, - 'init-version': { - key: 'init-version', - default: '1.0.0', - type: semver, - description: ` - The value that \`npm init\` should use by default for the package - version number, if not already set in package.json. - `, - defaultDescription: '"1.0.0"', - typeDescription: 'SemVer string', - }, - 'init.author.email': { - key: 'init.author.email', - default: '', - type: String, - deprecated: ` - Use \`--init-author-email\` instead.`, - description: ` - Alias for \`--init-author-email\` - `, - defaultDescription: '""', - typeDescription: 'String', - }, - 'init.author.name': { - key: 'init.author.name', - default: '', - type: String, - deprecated: ` - Use \`--init-author-name\` instead. - `, - description: ` - Alias for \`--init-author-name\` - `, - defaultDescription: '""', - typeDescription: 'String', - }, - 'init.author.url': { - key: 'init.author.url', - default: '', - type: [ - '', - url, - ], - deprecated: ` - Use \`--init-author-url\` instead. - `, - description: ` - Alias for \`--init-author-url\` - `, - defaultDescription: '""', - typeDescription: '"" or URL', - }, - 'init.license': { - key: 'init.license', - default: 'ISC', - type: String, - deprecated: ` - Use \`--init-license\` instead. - `, - description: ` - Alias for \`--init-license\` - `, - defaultDescription: '"ISC"', - typeDescription: 'String', - }, - 'init.module': { - key: 'init.module', - default: '~/.npm-init.js', - type: path, - deprecated: ` - Use \`--init-module\` instead. - `, - description: ` - Alias for \`--init-module\` - `, - defaultDescription: '"~/.npm-init.js"', - typeDescription: 'Path', - }, - 'init.version': { - key: 'init.version', - default: '1.0.0', - type: semver, - deprecated: ` - Use \`--init-version\` instead. - `, - description: ` - Alias for \`--init-version\` - `, - defaultDescription: '"1.0.0"', - typeDescription: 'SemVer string', - }, - json: { - key: 'json', - default: false, - type: Boolean, - description: ` - Whether or not to output JSON data, rather than the normal output. - - * In \`npm pkg set\` it enables parsing set values with JSON.parse() - before saving them to your \`package.json\`. - - Not supported by all npm commands. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - key: { - key: 'key', - default: null, - type: [ - null, - String, - ], - description: ` - A client key to pass when accessing the registry. Values should be in - PEM format with newlines replaced by the string "\\n". For example: - - \`\`\`ini - key="-----BEGIN PRIVATE KEY-----\\nXXXX\\nXXXX\\n-----END PRIVATE KEY-----" - \`\`\` - - It is _not_ the path to a key file (and there is no "keyfile" option). - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'null', - typeDescription: 'null or String', - }, - 'legacy-bundling': { - key: 'legacy-bundling', - default: false, - type: Boolean, - description: ` - Causes npm to install the package such that versions of npm prior to 1.4, - such as the one included with node 0.8, can install the package. This - eliminates all automatic deduping. If used with \`global-style\` this - option will be preferred. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - 'legacy-peer-deps': { - key: 'legacy-peer-deps', - default: false, - type: Boolean, - description: ` - Causes npm to completely ignore \`peerDependencies\` when building a - package tree, as in npm versions 3 through 6. - - If a package cannot be installed because of overly strict - \`peerDependencies\` that collide, it provides a way to move forward - resolving the situation. - - This differs from \`--omit=peer\`, in that \`--omit=peer\` will avoid - unpacking \`peerDependencies\` on disk, but will still design a tree such - that \`peerDependencies\` _could_ be unpacked in a correct place. - - Use of \`legacy-peer-deps\` is not recommended, as it will not enforce - the \`peerDependencies\` contract that meta-dependencies may rely on. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - link: { - key: 'link', - default: false, - type: Boolean, - description: ` - Used with \`npm ls\`, limiting output to only those packages that are - linked. - `, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - 'local-address': { - key: 'local-address', - default: null, - type: [ - null, - '127.0.0.1', - '::1', - 'fe80::1', - 'fe80::aede:48ff:fe00:1122', - 'fe80::18fe:6168:6908:4239', - '2600:1700:87d0:b28f:481:1fd0:2067:5a90', - '2600:1700:87d0:b28f:11be:d3f3:278c:ade9', - 'fd2e:635c:9594:10:109e:699c:6fdc:41b9', - 'fd2e:635c:9594:10:69ce:d360:4ab9:1632', - '192.168.103.122', - 'fe80::715:4a5e:3af5:99e5', - 'fe80::d32a:27b1:2ac:1155', - 'fe80::bbb2:6e76:3877:9f2f', - 'fe80::8e1f:15b0:b70:2d70', - ], - typeDescription: 'IP Address', - description: ` - The IP address of the local interface to use when making connections to - the npm registry. Must be IPv4 in versions of Node prior to 0.12. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'null', - }, - location: { - key: 'location', - default: 'user', - type: ['global', 'user', 'project'], - description: ` - When passed to \`npm config\` this refers to which config file to use. - `, - defaultDescription: ` - "user" unless \`--global\` is passed, which will also set this value to "global" - `, - typeDescription: '"global", "user", or "project"', - }, - loglevel: { - key: 'loglevel', - default: 'notice', - type: [ - 'silent', - 'error', - 'warn', - 'notice', - 'http', - 'timing', - 'info', - 'verbose', - 'silly', - ], - description: ` - What level of logs to report. All logs are written to a debug log, - with the path to that file printed if the execution of a command fails. - - Any logs of a higher level than the setting are shown. The default is - "notice". - - See also the \`foreground-scripts\` config. - `, - defaultDescription: '"notice"', - typeDescription: '"silent", "error", "warn", "notice", "http", "timing", "info", "verbose",' + - ' or "silly"', - }, - 'logs-max': { - key: 'logs-max', - default: 10, - type: Number, - description: ` - The maximum number of log files to store. - `, - defaultDescription: '10', - typeDescription: 'Number', - }, - long: { - key: 'long', - default: false, - type: Boolean, - short: 'l', - description: ` - Show extended information in \`ls\`, \`search\`, and \`help-search\`. - `, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - maxsockets: { - key: 'maxsockets', - default: null, - type: Number, - description: ` - The maximum number of connections to use per origin (protocol/host/port - combination). - `, - flatten (key, obj, flatOptions) { - flatOptions.maxSockets = obj[key] - }, - defaultDescription: 'Infinity', - typeDescription: 'Number', - }, - message: { - key: 'message', - default: '%s', - type: String, - short: 'm', - description: ` - Commit message which is used by \`npm version\` when creating version commit. - - Any "%s" in the message will be replaced with the version number. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: '"%s"', - typeDescription: 'String', - }, - 'node-options': { - key: 'node-options', - default: null, - type: [ - null, - String, - ], - description: ` - Options to pass through to Node.js via the \`NODE_OPTIONS\` environment - variable. This does not impact how npm itself is executed but it does - impact how lifecycle scripts are called. - `, - defaultDescription: 'null', - typeDescription: 'null or String', - }, - 'node-version': { - key: 'node-version', - default: 'v15.3.0', - defaultDescription: 'Node.js `process.version` value', - type: semver, - description: ` - The node version to use when checking a package's \`engines\` setting. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - typeDescription: 'SemVer string', - }, - noproxy: { - key: 'noproxy', - default: '', - defaultDescription: ` - The value of the NO_PROXY environment variable - `, - type: [ - String, - Array, - ], - description: ` - Domain extensions that should bypass any proxies. - - Also accepts a comma-delimited string. - `, - flatten (key, obj, flatOptions) { - flatOptions.noProxy = obj[key].join(',') - }, - typeDescription: 'String (can be set multiple times)', - }, - 'npm-version': { - key: 'npm-version', - default: '7.6.3', - defaultDescription: 'Output of `npm --version`', - type: semver, - description: ` - The npm version to use when checking a package's \`engines\` setting. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - typeDescription: 'SemVer string', - }, - offline: { - key: 'offline', - default: false, - type: Boolean, - description: ` - Force offline mode: no network requests will be done during install. To allow - the CLI to fill in missing cache data, see \`--prefer-offline\`. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - omit: { - key: 'omit', - default: [], - defaultDescription: ` - 'dev' if the \`NODE_ENV\` environment variable is set to 'production', - otherwise empty. - `, - type: [ - Array, - 'dev', - 'optional', - 'peer', - ], - description: ` - Dependency types to omit from the installation tree on disk. - - Note that these dependencies _are_ still resolved and added to the - \`package-lock.json\` or \`npm-shrinkwrap.json\` file. They are just - not physically installed on disk. - - If a package type appears in both the \`--include\` and \`--omit\` - lists, then it will be included. - - If the resulting omit list includes \`'dev'\`, then the \`NODE_ENV\` - environment variable will be set to \`'production'\` for all lifecycle - scripts. - `, - flatten (key, obj, flatOptions) { - const include = obj.include || [] - const omit = flatOptions.omit || [] - flatOptions.omit = omit.concat(obj[key]) - .filter(type => type && !include.includes(type)) - }, - typeDescription: '"dev", "optional", or "peer" (can be set multiple times)', - }, - only: { - key: 'only', - default: null, - type: [ - null, - 'prod', - 'production', - ], - deprecated: ` - Use \`--omit=dev\` to omit dev dependencies from the install. - `, - description: ` - When set to \`prod\` or \`production\`, this is an alias for - \`--omit=dev\`. - `, - flatten (key, obj, flatOptions) { - const value = obj[key] - if (!/^prod(uction)?$/.test(value)) { - return - } - - obj.omit = obj.omit || [] - obj.omit.push('dev') - definitions.omit.flatten('omit', obj, flatOptions) - }, - defaultDescription: 'null', - typeDescription: 'null, "prod", or "production"', - }, - optional: { - key: 'optional', - default: null, - type: [ - null, - Boolean, - ], - deprecated: ` - Use \`--omit=optional\` to exclude optional dependencies, or - \`--include=optional\` to include them. - - Default value does install optional deps unless otherwise omitted. - `, - description: ` - Alias for --include=optional or --omit=optional - `, - flatten (key, obj, flatOptions) { - const value = obj[key] - if (value === null) { - return - } else if (value === true) { - obj.include = obj.include || [] - obj.include.push('optional') - } else { - obj.omit = obj.omit || [] - obj.omit.push('optional') - } - definitions.omit.flatten('omit', obj, flatOptions) - }, - defaultDescription: 'null', - typeDescription: 'null or Boolean', - }, - otp: { - key: 'otp', - default: null, - type: [ - null, - String, - ], - description: ` - This is a one-time password from a two-factor authenticator. It's needed - when publishing or changing package permissions with \`npm access\`. - - If not set, and a registry response fails with a challenge for a one-time - password, npm will prompt on the command line for one. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'null', - typeDescription: 'null or String', - }, - package: { - key: 'package', - default: [], - type: [ - String, - Array, - ], - description: ` - The package to install for [\`npm exec\`](/commands/npm-exec) - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: '', - typeDescription: 'String (can be set multiple times)', - }, - 'package-lock': { - key: 'package-lock', - default: true, - type: Boolean, - description: ` - If set to false, then ignore \`package-lock.json\` files when installing. - This will also prevent _writing_ \`package-lock.json\` if \`save\` is - true. - - When package package-locks are disabled, automatic pruning of extraneous - modules will also be disabled. To remove extraneous modules with - package-locks disabled use \`npm prune\`. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'true', - typeDescription: 'Boolean', - }, - 'package-lock-only': { - key: 'package-lock-only', - default: false, - type: Boolean, - description: ` - If set to true, the current operation will only use the \`package-lock.json\`, - ignoring \`node_modules\`. - - For \`update\` this means only the \`package-lock.json\` will be updated, - instead of checking \`node_modules\` and downloading dependencies. - - For \`list\` this means the output will be based on the tree described by the - \`package-lock.json\`, rather than the contents of \`node_modules\`. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - parseable: { - key: 'parseable', - default: false, - type: Boolean, - short: 'p', - description: ` - Output parseable results from commands that write to standard output. For - \`npm search\`, this will be tab-separated table format. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - 'prefer-offline': { - key: 'prefer-offline', - default: false, - type: Boolean, - description: ` - If true, staleness checks for cached data will be bypassed, but missing - data will be requested from the server. To force full offline mode, use - \`--offline\`. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - 'prefer-online': { - key: 'prefer-online', - default: false, - type: Boolean, - description: ` - If true, staleness checks for cached data will be forced, making the CLI - look for updates immediately even for fresh package data. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - prefix: { - key: 'prefix', - type: path, - short: 'C', - default: '', - defaultDescription: ` - In global mode, the folder where the node executable is installed. In - local mode, the nearest parent folder containing either a package.json - file or a node_modules folder. - `, - description: ` - The location to install global items. If set on the command line, then - it forces non-global commands to run in the specified folder. - `, - typeDescription: 'Path', - }, - preid: { - key: 'preid', - default: '', - type: String, - description: ` - The "prerelease identifier" to use as a prefix for the "prerelease" part - of a semver. Like the \`rc\` in \`1.2.0-rc.8\`. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: '""', - typeDescription: 'String', - }, - production: { - key: 'production', - default: false, - type: Boolean, - deprecated: 'Use `--omit=dev` instead.', - description: 'Alias for `--omit=dev`', - flatten (key, obj, flatOptions) { - const value = obj[key] - if (!value) { - return - } - - obj.omit = obj.omit || [] - obj.omit.push('dev') - definitions.omit.flatten('omit', obj, flatOptions) - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - progress: { - key: 'progress', - default: true, - defaultDescription: '\n `true` unless running in a known CI system\n ', - type: Boolean, - description: ` - When set to \`true\`, npm will display a progress bar during time - intensive operations, if \`process.stderr\` is a TTY. - - Set to \`false\` to suppress the progress bar. - `, - typeDescription: 'Boolean', - }, - proxy: { - key: 'proxy', - default: null, - type: [ - null, - false, - url, - ], - description: ` - A proxy to use for outgoing http requests. If the \`HTTP_PROXY\` or - \`http_proxy\` environment variables are set, proxy settings will be - honored by the underlying \`request\` library. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'null', - typeDescription: 'null, false, or URL', - }, - 'read-only': { - key: 'read-only', - default: false, - type: Boolean, - description: ` - This is used to mark a token as unable to publish when configuring - limited access tokens with the \`npm token create\` command. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - 'rebuild-bundle': { - key: 'rebuild-bundle', - default: true, - type: Boolean, - description: ` - Rebuild bundled dependencies after installation. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'true', - typeDescription: 'Boolean', - }, - registry: { - key: 'registry', - default: 'https://registry.npmjs.org/', - type: [null, url], - description: ` - The base URL of the npm registry. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: '"https://registry.npmjs.org/"', - typeDescription: 'URL', - }, - save: { - key: 'save', - default: true, - type: Boolean, - short: 'S', - description: ` - Save installed packages to a \`package.json\` file as dependencies. - - When used with the \`npm rm\` command, removes the dependency from - \`package.json\`. - - Will also prevent writing to \`package-lock.json\` if set to \`false\`. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'true', - typeDescription: 'Boolean', - }, - 'save-bundle': { - key: 'save-bundle', - default: false, - type: Boolean, - short: 'B', - description: ` - If a package would be saved at install time by the use of \`--save\`, - \`--save-dev\`, or \`--save-optional\`, then also put it in the - \`bundleDependencies\` list. - - Ignore if \`--save-peer\` is set, since peerDependencies cannot be bundled. - `, - flatten (key, obj, flatOptions) { - // XXX update arborist to just ignore it if resulting saveType is peer - // otherwise this won't have the expected effect: - // - // npm config set save-peer true - // npm i foo --save-bundle --save-prod <-- should bundle - flatOptions.saveBundle = obj['save-bundle'] && !obj['save-peer'] - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - 'save-dev': { - key: 'save-dev', - default: false, - type: Boolean, - short: 'D', - description: ` - Save installed packages to a package.json file as \`devDependencies\`. - `, - flatten (key, obj, flatOptions) { - if (!obj[key]) { - if (flatOptions.saveType === 'dev') { - delete flatOptions.saveType - } - return - } - - flatOptions.saveType = 'dev' - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - 'save-exact': { - key: 'save-exact', - default: false, - type: Boolean, - short: 'E', - description: ` - Dependencies saved to package.json will be configured with an exact - version rather than using npm's default semver range operator. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - 'save-optional': { - key: 'save-optional', - default: false, - type: Boolean, - short: 'O', - description: ` - Save installed packages to a package.json file as - \`optionalDependencies\`. - `, - flatten (key, obj, flatOptions) { - if (!obj[key]) { - if (flatOptions.saveType === 'optional') { - delete flatOptions.saveType - } else if (flatOptions.saveType === 'peerOptional') { - flatOptions.saveType = 'peer' - } - return - } - - if (flatOptions.saveType === 'peerOptional') { - return - } - - if (flatOptions.saveType === 'peer') { - flatOptions.saveType = 'peerOptional' - } else { - flatOptions.saveType = 'optional' - } - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - 'save-peer': { - key: 'save-peer', - default: false, - type: Boolean, - description: ` - Save installed packages to a package.json file as \`peerDependencies\` - `, - flatten (key, obj, flatOptions) { - if (!obj[key]) { - if (flatOptions.saveType === 'peer') { - delete flatOptions.saveType - } else if (flatOptions.saveType === 'peerOptional') { - flatOptions.saveType = 'optional' - } - return - } - - if (flatOptions.saveType === 'peerOptional') { - return - } - - if (flatOptions.saveType === 'optional') { - flatOptions.saveType = 'peerOptional' - } else { - flatOptions.saveType = 'peer' - } - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - 'save-prefix': { - key: 'save-prefix', - default: '^', - type: String, - description: ` - Configure how versions of packages installed to a package.json file via - \`--save\` or \`--save-dev\` get prefixed. - - For example if a package has version \`1.2.3\`, by default its version is - set to \`^1.2.3\` which allows minor upgrades for that package, but after - \`npm config set save-prefix='~'\` it would be set to \`~1.2.3\` which - only allows patch upgrades. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: '"^"', - typeDescription: 'String', - }, - 'save-prod': { - key: 'save-prod', - default: false, - type: Boolean, - short: 'P', - description: ` - Save installed packages into \`dependencies\` specifically. This is - useful if a package already exists in \`devDependencies\` or - \`optionalDependencies\`, but you want to move it to be a non-optional - production dependency. - - This is the default behavior if \`--save\` is true, and neither - \`--save-dev\` or \`--save-optional\` are true. - `, - flatten (key, obj, flatOptions) { - if (!obj[key]) { - if (flatOptions.saveType === 'prod') { - delete flatOptions.saveType - } - return - } - - flatOptions.saveType = 'prod' - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - scope: { - key: 'scope', - default: '', - defaultDescription: ` - the scope of the current project, if any, or "" - `, - type: String, - description: ` - Associate an operation with a scope for a scoped registry. - - Useful when logging in to or out of a private registry: - - \`\`\` - # log in, linking the scope to the custom registry - npm login --scope=@mycorp --registry=https://registry.mycorp.com - - # log out, removing the link and the auth token - npm logout --scope=@mycorp - \`\`\` - - This will cause \`@mycorp\` to be mapped to the registry for future - installation of packages specified according to the pattern - \`@mycorp/package\`. - - This will also cause \`npm init\` to create a scoped package. - - \`\`\` - # accept all defaults, and create a package named "@foo/whatever", - # instead of just named "whatever" - npm init --scope=@foo --yes - \`\`\` - `, - flatten (key, obj, flatOptions) { - const value = obj[key] - flatOptions.projectScope = value && !/^@/.test(value) ? `@${value}` : value - }, - typeDescription: 'String', - }, - 'script-shell': { - key: 'script-shell', - default: null, - defaultDescription: ` - '/bin/sh' on POSIX systems, 'cmd.exe' on Windows - `, - type: [ - null, - String, - ], - description: ` - The shell to use for scripts run with the \`npm exec\`, - \`npm run\` and \`npm init \` commands. - `, - flatten (key, obj, flatOptions) { - flatOptions.scriptShell = obj[key] || undefined - }, - typeDescription: 'null or String', - }, - searchexclude: { - key: 'searchexclude', - default: '', - type: String, - description: ` - Space-separated options that limit the results from search. - `, - flatten (key, obj, flatOptions) { - flatOptions.search = flatOptions.search || { limit: 20 } - flatOptions.search.exclude = obj[key] - }, - defaultDescription: '""', - typeDescription: 'String', - }, - searchlimit: { - key: 'searchlimit', - default: 20, - type: Number, - description: ` - Number of items to limit search results to. Will not apply at all to - legacy searches. - `, - flatten (key, obj, flatOptions) { - flatOptions.search = flatOptions.search || {} - flatOptions.search.limit = obj[key] - }, - defaultDescription: '20', - typeDescription: 'Number', - }, - searchopts: { - key: 'searchopts', - default: '', - type: String, - description: ` - Space-separated options that are always passed to search. - `, - flatten (key, obj, flatOptions) { - flatOptions.search = flatOptions.search || { limit: 20 } - flatOptions.search.opts = querystring.parse(obj[key]) - }, - defaultDescription: '""', - typeDescription: 'String', - }, - searchstaleness: { - key: 'searchstaleness', - default: 900, - type: Number, - description: ` - The age of the cache, in seconds, before another registry request is made - if using legacy search endpoint. - `, - flatten (key, obj, flatOptions) { - flatOptions.search = flatOptions.search || { limit: 20 } - flatOptions.search.staleness = obj[key] - }, - defaultDescription: '900', - typeDescription: 'Number', - }, - shell: { - key: 'shell', - default: '/usr/local/bin/bash', - defaultDescription: ` - SHELL environment variable, or "bash" on Posix, or "cmd.exe" on Windows - `, - type: String, - description: ` - The shell to run for the \`npm explore\` command. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - typeDescription: 'String', - }, - shrinkwrap: { - key: 'shrinkwrap', - default: true, - type: Boolean, - deprecated: ` - Use the --package-lock setting instead. - `, - description: ` - Alias for --package-lock - `, - flatten (key, obj, flatOptions) { - obj['package-lock'] = obj.shrinkwrap - definitions['package-lock'].flatten('package-lock', obj, flatOptions) - }, - defaultDescription: 'true', - typeDescription: 'Boolean', - }, - 'sign-git-commit': { - key: 'sign-git-commit', - default: false, - type: Boolean, - description: ` - If set to true, then the \`npm version\` command will commit the new - package version using \`-S\` to add a signature. - - Note that git requires you to have set up GPG keys in your git configs - for this to work properly. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - 'sign-git-tag': { - key: 'sign-git-tag', - default: false, - type: Boolean, - description: ` - If set to true, then the \`npm version\` command will tag the version - using \`-s\` to add a signature. - - Note that git requires you to have set up GPG keys in your git configs - for this to work properly. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - 'sso-poll-frequency': { - key: 'sso-poll-frequency', - default: 500, - type: Number, - deprecated: ` - The --auth-type method of SSO/SAML/OAuth will be removed in a future - version of npm in favor of web-based login. - `, - description: ` - When used with SSO-enabled \`auth-type\`s, configures how regularly the - registry should be polled while the user is completing authentication. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: '500', - typeDescription: 'Number', - }, - 'sso-type': { - key: 'sso-type', - default: 'oauth', - type: [ - null, - 'oauth', - 'saml', - ], - deprecated: ` - The --auth-type method of SSO/SAML/OAuth will be removed in a future - version of npm in favor of web-based login. - `, - description: ` - If \`--auth-type=sso\`, the type of SSO type to use. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: '"oauth"', - typeDescription: 'null, "oauth", or "saml"', - }, - 'strict-peer-deps': { - key: 'strict-peer-deps', - default: false, - type: Boolean, - description: ` - If set to \`true\`, and \`--legacy-peer-deps\` is not set, then _any_ - conflicting \`peerDependencies\` will be treated as an install failure, - even if npm could reasonably guess the appropriate resolution based on - non-peer dependency relationships. - - By default, conflicting \`peerDependencies\` deep in the dependency graph - will be resolved using the nearest non-peer dependency specification, - even if doing so will result in some packages receiving a peer dependency - outside the range set in their package's \`peerDependencies\` object. - - When such and override is performed, a warning is printed, explaining the - conflict and the packages involved. If \`--strict-peer-deps\` is set, - then this warning is treated as a failure. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - 'strict-ssl': { - key: 'strict-ssl', - default: true, - type: Boolean, - description: ` - Whether or not to do SSL key validation when making requests to the - registry via https. - - See also the \`ca\` config. - `, - flatten (key, obj, flatOptions) { - flatOptions.strictSSL = obj[key] - }, - defaultDescription: 'true', - typeDescription: 'Boolean', - }, - tag: { - key: 'tag', - default: 'latest', - type: String, - description: ` - If you ask npm to install a package and don't tell it a specific version, - then it will install the specified tag. - - Also the tag that is added to the package@version specified by the \`npm - tag\` command, if no explicit tag is given. - - When used by the \`npm diff\` command, this is the tag used to fetch the - tarball that will be compared with the local files by default. - `, - flatten (key, obj, flatOptions) { - flatOptions.defaultTag = obj[key] - }, - defaultDescription: '"latest"', - typeDescription: 'String', - }, - 'tag-version-prefix': { - key: 'tag-version-prefix', - default: 'v', - type: String, - description: ` - If set, alters the prefix used when tagging a new version when performing - a version increment using \`npm-version\`. To remove the prefix - altogether, set it to the empty string: \`""\`. - - Because other tools may rely on the convention that npm version tags look - like \`v1.0.0\`, _only use this property if it is absolutely necessary_. - In particular, use care when overriding this setting for public packages. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: '"v"', - typeDescription: 'String', - }, - timing: { - key: 'timing', - default: false, - type: Boolean, - description: ` - If true, writes an \`npm-debug\` log to \`_logs\` and timing information - to \`_timing.json\`, both in your cache, even if the command completes - successfully. \`_timing.json\` is a newline delimited list of JSON - objects. - - You can quickly view it with this [json](https://npm.im/json) command - line: \`npm exec -- json -g < ~/.npm/_timing.json\`. - `, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - tmp: { - key: 'tmp', - default: '/var/folders/zc/5n20yjzn7mn7cz_qckj3b3440000gn/T', - defaultDescription: ` - The value returned by the Node.js \`os.tmpdir()\` method - - `, - type: path, - deprecated: ` - This setting is no longer used. npm stores temporary files in a special - location in the cache, and they are managed by - [\`cacache\`](http://npm.im/cacache). - `, - description: ` - Historically, the location where temporary files were stored. No longer - relevant. - `, - typeDescription: 'Path', - }, - umask: { - key: 'umask', - default: 0, - type: Umask, - description: ` - The "umask" value to use when setting the file creation mode on files and - folders. - - Folders and executables are given a mode which is \`0o777\` masked - against this value. Other files are given a mode which is \`0o666\` - masked against this value. - - Note that the underlying system will _also_ apply its own umask value to - files and folders that are created, and npm does not circumvent this, but - rather adds the \`--umask\` config to it. - - Thus, the effective default umask value on most POSIX systems is 0o22, - meaning that folders and executables are created with a mode of 0o755 and - other files are created with a mode of 0o644. - `, - flatten: (key, obj, flatOptions) => { - const camel = key.replace(/-([a-z])/g, (_0, _1) => _1.toUpperCase()) - flatOptions[camel] = obj[key] - }, - defaultDescription: '0', - typeDescription: 'Octal numeric string in range 0000..0777 (0..511)', - }, - unicode: { - key: 'unicode', - default: true, - defaultDescription: ` - false on windows, true on mac/unix systems with a unicode locale, as - defined by the \`LC_ALL\`, \`LC_CTYPE\`, or \`LANG\` environment variables. - `, - type: Boolean, - description: ` - When set to true, npm uses unicode characters in the tree output. When - false, it uses ascii characters instead of unicode glyphs. - `, - typeDescription: 'Boolean', - }, - 'update-notifier': { - key: 'update-notifier', - default: true, - type: Boolean, - description: ` - Set to false to suppress the update notification when using an older - version of npm than the latest. - `, - defaultDescription: 'true', - typeDescription: 'Boolean', - }, - usage: { - key: 'usage', - default: false, - type: Boolean, - short: [ - '?', - 'H', - 'h', - ], - description: ` - Show short usage output about the command specified. - `, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - 'user-agent': { - key: 'user-agent', - default: 'npm/{npm-version} node/{node-version} {platform} {arch} {ci}', - type: String, - description: ` - Sets the User-Agent request header. The following fields are replaced - with their actual counterparts: - - * \`{npm-version}\` - The npm version in use - * \`{node-version}\` - The Node.js version in use - * \`{platform}\` - The value of \`process.platform\` - * \`{arch}\` - The value of \`process.arch\` - * \`{workspaces}\` - Set to \`true\` if the \`workspaces\` or \`workspace\` - options are set. - * \`{ci}\` - The value of the \`ci-name\` config, if set, prefixed with - \`ci/\`, or an empty string if \`ci-name\` is empty. - `, - flatten (key, obj, flatOptions) { - const value = obj[key] - const ciName = obj['ci-name'] - flatOptions.userAgent = - value.replace(/\{node-version\}/gi, obj['node-version']) - .replace(/\{npm-version\}/gi, obj['npm-version']) - .replace(/\{platform\}/gi, process.platform) - .replace(/\{arch\}/gi, process.arch) - .replace(/\{ci\}/gi, ciName ? `ci/${ciName}` : '') - .trim() - }, - defaultDescription: '"npm/{npm-version} node/{node-version} {platform} {arch} {ci}"', - typeDescription: 'String', - }, - userconfig: { - key: 'userconfig', - default: '~/.npmrc', - type: path, - description: ` - The location of user-level configuration settings. - - This may be overridden by the \`npm_config_userconfig\` environment - variable or the \`--userconfig\` command line option, but may _not_ - be overridden by settings in the \`globalconfig\` file. - `, - defaultDescription: '"~/.npmrc"', - typeDescription: 'Path', - }, - version: { - key: 'version', - default: false, - type: Boolean, - short: 'v', - description: ` - If true, output the npm version and exit successfully. - - Only relevant when specified explicitly on the command line. - `, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - versions: { - key: 'versions', - default: false, - type: Boolean, - description: ` - If true, output the npm version as well as node's \`process.versions\` - map and the version in the current working directory's \`package.json\` - file if one exists, and exit successfully. - - Only relevant when specified explicitly on the command line. - `, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, - viewer: { - key: 'viewer', - default: 'man', - defaultDescription: '\n "man" on Posix, "browser" on Windows\n ', - type: String, - description: ` - The program to use to view help content. - - Set to \`"browser"\` to view html help content in the default web browser. - `, - typeDescription: 'String', - }, - workspace: { - key: 'workspace', - default: [], - type: [String, Array], - short: 'w', - envExport: false, - description: ` - Enable running a command in the context of the configured workspaces of the - current project while filtering by running only the workspaces defined by - this configuration option. - - Valid values for the \`workspace\` config are either: - - * Workspace names - * Path to a workspace directory - * Path to a parent workspace directory (will result in selecting all - workspaces within that folder) - - When set for the \`npm init\` command, this may be set to the folder of - a workspace which does not yet exist, to create the folder and set it - up as a brand new workspace within the project. - `, - defaultDescription: '', - typeDescription: 'String (can be set multiple times)', - flatten: (key, obj, flatOptions) => { - definitions['user-agent'].flatten('user-agent', obj, flatOptions) - }, - }, - yes: { - key: 'yes', - default: false, - type: Boolean, - short: 'y', - description: ` - Automatically answer "yes" to any prompts that npm might print on - the command line. - `, - defaultDescription: 'false', - typeDescription: 'Boolean', - }, -} diff --git a/workspaces/config/test/fixtures/flatten.js b/workspaces/config/test/fixtures/flatten.js deleted file mode 100644 index 588d05bf0d77d..0000000000000 --- a/workspaces/config/test/fixtures/flatten.js +++ /dev/null @@ -1,33 +0,0 @@ -// use the defined flattening function, and copy over any scoped -// registries and registry-specific "nerfdart" configs verbatim -// -// TODO: make these getters so that we only have to make dirty -// the thing that changed, and then flatten the fields that -// could have changed when a config.set is called. -// -// TODO: move nerfdart auth stuff into a nested object that -// is only passed along to paths that end up calling npm-registry-fetch. -const definitions = require('./definitions.js') -const flatten = (obj, flat = {}) => { - for (const [key, val] of Object.entries(obj)) { - const def = definitions[key] - if (def && def.flatten) { - def.flatten(key, obj, flat) - } else if (/@.*:registry$/i.test(key) || /^\/\//.test(key)) { - flat[key] = val - } - } - - // XXX make this the bin/npm-cli.js file explicitly instead - // otherwise using npm programmatically is a bit of a pain. - flat.npmBin = require.main ? require.main.filename - : /* istanbul ignore next - not configurable property */ undefined - flat.nodeBin = process.env.NODE || process.execPath - - // XXX should this be sha512? is it even relevant? - flat.hashAlgorithm = 'sha1' - - return flat -} - -module.exports = flatten diff --git a/workspaces/config/test/fixtures/shorthands.js b/workspaces/config/test/fixtures/shorthands.js deleted file mode 100644 index 5c460c6617175..0000000000000 --- a/workspaces/config/test/fixtures/shorthands.js +++ /dev/null @@ -1,41 +0,0 @@ -module.exports = { - 'enjoy-by': ['--before'], - a: ['--all'], - c: ['--call'], - s: ['--loglevel', 'silent'], - d: ['--loglevel', 'info'], - dd: ['--loglevel', 'verbose'], - ddd: ['--loglevel', 'silly'], - noreg: ['--no-registry'], - N: ['--no-registry'], - reg: ['--registry'], - 'no-reg': ['--no-registry'], - silent: ['--loglevel', 'silent'], - verbose: ['--loglevel', 'verbose'], - quiet: ['--loglevel', 'warn'], - q: ['--loglevel', 'warn'], - h: ['--usage'], - H: ['--usage'], - '?': ['--usage'], - help: ['--usage'], - v: ['--version'], - f: ['--force'], - desc: ['--description'], - 'no-desc': ['--no-description'], - local: ['--no-global'], - l: ['--long'], - m: ['--message'], - p: ['--parseable'], - porcelain: ['--parseable'], - readonly: ['--read-only'], - g: ['--global'], - S: ['--save'], - D: ['--save-dev'], - E: ['--save-exact'], - O: ['--save-optional'], - P: ['--save-prod'], - y: ['--yes'], - n: ['--no-yes'], - B: ['--save-bundle'], - C: ['--prefix'], -} diff --git a/workspaces/config/test/fixtures/types.js b/workspaces/config/test/fixtures/types.js deleted file mode 100644 index 924433e3ec67c..0000000000000 --- a/workspaces/config/test/fixtures/types.js +++ /dev/null @@ -1,152 +0,0 @@ -const { - String: { type: String }, - Boolean: { type: Boolean }, - url: { type: url }, - Number: { type: Number }, - path: { type: path }, - Date: { type: Date }, - semver: { type: semver }, - Umask: { type: Umask }, -} = require('../../lib/type-defs.js') - -const { networkInterfaces } = require('os') -const getLocalAddresses = () => { - try { - return Object.values(networkInterfaces()).map( - int => int.map(({ address }) => address) - ).reduce((set, addrs) => set.concat(addrs), [undefined]) - } catch (e) { - return [undefined] - } -} - -module.exports = { - access: [null, 'restricted', 'public'], - all: Boolean, - 'allow-same-version': Boolean, - 'always-auth': Boolean, - also: [null, 'dev', 'development'], - audit: Boolean, - 'audit-level': ['low', 'moderate', 'high', 'critical', 'none', null], - 'auth-type': ['legacy', 'sso', 'saml', 'oauth'], - before: [null, Date], - 'bin-links': Boolean, - browser: [null, Boolean, String], - ca: [null, String, Array], - cafile: path, - cache: path, - 'cache-lock-stale': Number, - 'cache-lock-retries': Number, - 'cache-lock-wait': Number, - 'cache-max': Number, - 'cache-min': Number, - cert: [null, String], - cidr: [null, String, Array], - color: ['always', Boolean], - call: String, - depth: Number, - description: Boolean, - dev: Boolean, - 'dry-run': Boolean, - editor: String, - 'engine-strict': Boolean, - force: Boolean, - fund: Boolean, - 'format-package-lock': Boolean, - 'fetch-retries': Number, - 'fetch-retry-factor': Number, - 'fetch-retry-mintimeout': Number, - 'fetch-retry-maxtimeout': Number, - git: String, - 'git-tag-version': Boolean, - 'commit-hooks': Boolean, - global: Boolean, - globalconfig: path, - 'global-style': Boolean, - 'https-proxy': [null, url], - 'user-agent': String, - heading: String, - 'if-present': Boolean, - include: [Array, 'prod', 'dev', 'optional', 'peer'], - 'include-staged': Boolean, - 'ignore-prepublish': Boolean, - 'ignore-scripts': Boolean, - 'init-module': path, - 'init-author-name': String, - 'init-author-email': String, - 'init-author-url': ['', url], - 'init-license': String, - 'init-version': semver, - json: Boolean, - key: [null, String], - 'legacy-bundling': Boolean, - 'legacy-peer-deps': Boolean, - link: Boolean, - 'local-address': getLocalAddresses(), - loglevel: ['silent', 'error', 'warn', 'notice', 'http', 'timing', 'info', 'verbose', 'silly'], - 'logs-max': Number, - long: Boolean, - 'multiple-numbers': [Array, Number], - maxsockets: Number, - message: String, - 'metrics-registry': [null, String], - 'node-options': [null, String], - 'node-version': [null, semver], - noproxy: [null, String, Array], - offline: Boolean, - omit: [Array, 'dev', 'optional', 'peer'], - only: [null, 'dev', 'development', 'prod', 'production'], - optional: Boolean, - otp: [null, String], - package: [String, Array], - 'package-lock': Boolean, - 'package-lock-only': Boolean, - parseable: Boolean, - 'prefer-offline': Boolean, - 'prefer-online': Boolean, - prefix: path, - preid: String, - production: Boolean, - progress: Boolean, - proxy: [null, false, url], // allow proxy to be disabled explicitly - 'read-only': Boolean, - 'rebuild-bundle': Boolean, - registry: [null, url], - rollback: Boolean, - save: Boolean, - 'save-bundle': Boolean, - 'save-dev': Boolean, - 'save-exact': Boolean, - 'save-optional': Boolean, - 'save-prefix': String, - 'save-prod': Boolean, - scope: String, - 'script-shell': [null, String], - 'scripts-prepend-node-path': [Boolean, 'auto', 'warn-only'], - searchopts: String, - searchexclude: [null, String], - searchlimit: Number, - searchstaleness: Number, - 'send-metrics': Boolean, - shell: String, - shrinkwrap: Boolean, - 'sign-git-commit': Boolean, - 'sign-git-tag': Boolean, - 'sso-poll-frequency': Number, - 'sso-type': [null, 'oauth', 'saml'], - 'strict-ssl': Boolean, - tag: String, - timing: Boolean, - tmp: path, - unicode: Boolean, - 'update-notifier': Boolean, - usage: Boolean, - userconfig: path, - umask: Umask, - version: Boolean, - 'tag-version-prefix': String, - versions: Boolean, - viewer: String, - _exit: Boolean, - _single: { exotic: 'not part of normal typedefs' }, -} diff --git a/workspaces/config/test/index.js b/workspaces/config/test/index.js index bd19ee48bef4f..520d554436ea8 100644 --- a/workspaces/config/test/index.js +++ b/workspaces/config/test/index.js @@ -11,14 +11,14 @@ Object.keys(process.env) delete process.env.PREFIX delete process.env.DESTDIR -const definitions = require('./fixtures/definitions.js') -const shorthands = require('./fixtures/shorthands.js') -const flatten = require('./fixtures/flatten.js') +const Definition = require('../lib/definitions/definition.js') +const createDef = (key, value) => ({ [key]: new Definition(key, { key, ...value }) }) + const typeDefs = require('../lib/type-defs.js') const { resolve, join, dirname } = require('path') -const Config = t.mock('../', { +const fsMocks = { 'fs/promises': { ...fs.promises, readFile: async (path, ...args) => { @@ -29,11 +29,25 @@ const Config = t.mock('../', { return fs.promises.readFile(path, ...args) }, }, -}) + fs: { + ...fs, + readFileSync: (path, ...args) => { + if (path.includes('WEIRD-ERROR')) { + throw Object.assign(new Error('weird error'), { code: 'EWEIRD' }) + } + + return fs.readFileSync(path, ...args) + }, + }, +} + +const { definitions, shorthands, flatten } = t.mock('../lib/definitions/index.js', fsMocks) +const Config = t.mock('../', fsMocks) // because we used t.mock above, the require cache gets blown and we lose our direct equality // on the typeDefs. to get around that, we require an un-mocked Config and assert against that const RealConfig = require('../') + t.equal(typeDefs, RealConfig.typeDefs, 'exposes type definitions') t.test('construct with no settings, get default values for stuff', t => { @@ -152,6 +166,7 @@ loglevel = yolo 'foo', '--also=dev', '--registry=hello', + '--proxy=hello', '--omit=cucumber', '--access=blueberry', '--multiple-numbers=what kind of fruit is not a number', @@ -239,9 +254,24 @@ loglevel = yolo env, argv, cwd: join(`${path}/project`), - shorthands, - definitions, + definitions: { + ...definitions, + ...createDef('multiple-numbers', { + default: [], + type: [Array, Number], + description: 'one or more numbers', + }), + ...createDef('methane', { + envExport: false, + type: String, + typeDescription: 'Greenhouse Gas', + default: 'CH4', + description: ` + This is bad for the environment, for our children, do not put it there. + `, + }), + }, }) t.equal(config.globalPrefix, null, 'globalPrefix missing before load') @@ -348,6 +378,8 @@ loglevel = yolo t.strictSame(logs, [ ['warn', 'invalid config', 'registry="hello"', 'set in command line options'], ['warn', 'invalid config', 'Must be', 'full url with "https://"'], + ['warn', 'invalid config', 'proxy="hello"', 'set in command line options'], + ['warn', 'invalid config', 'Must be', 'full url with "https://"'], ['warn', 'invalid config', 'omit="cucumber"', 'set in command line options'], ['warn', 'invalid config', 'Must be one or more of:', 'dev, optional, peer'], ['warn', 'invalid config', 'access="blueberry"', 'set in command line options'], @@ -363,8 +395,7 @@ loglevel = yolo ['warn', 'invalid config', 'loglevel="yolo"', `set in ${resolve(path, 'project/.npmrc')}`], ['warn', 'invalid config', 'Must be one of:', - ['silent', 'error', 'warn', 'notice', 'http', 'timing', 'info', - 'verbose', 'silly'].join(', '), + ['silent', 'error', 'warn', 'notice', 'http', 'info', 'verbose', 'silly'].join(', '), ], ]) t.equal(config.valid, false) @@ -495,7 +526,14 @@ loglevel = yolo platform: 'posix', shorthands, - definitions, + definitions: { + ...definitions, + ...createDef('multiple-numbers', { + default: [], + type: [Array, Number], + description: 'one or more numbers', + }), + }, }) await config.load() @@ -535,6 +573,8 @@ loglevel = yolo t.strictSame(logs, [ ['warn', 'invalid config', 'registry="hello"', 'set in command line options'], ['warn', 'invalid config', 'Must be', 'full url with "https://"'], + ['warn', 'invalid config', 'proxy="hello"', 'set in command line options'], + ['warn', 'invalid config', 'Must be', 'full url with "https://"'], ['warn', 'invalid config', 'omit="cucumber"', 'set in command line options'], ['warn', 'invalid config', 'Must be one or more of:', 'dev, optional, peer'], ['warn', 'invalid config', 'access="blueberry"', 'set in command line options'], @@ -548,6 +588,7 @@ loglevel = yolo ['warn', 'invalid config', 'Must be', 'valid filesystem path'], ['warn', 'config', 'also', 'Please use --include=dev instead.'], ]) + logs.length = 0 }) t.end() @@ -637,9 +678,9 @@ t.test('ignore cafile if it does not load', async t => { }) t.test('raise error if reading ca file error other than ENOENT', async t => { - const cafile = resolve(__dirname, 'fixtures', 'WEIRD-ERROR') const dir = t.testdir({ - '.npmrc': `cafile = ${cafile}`, + '.npmrc': `cafile = ~/WEIRD-ERROR`, + 'WEIRD-ERROR': '', }) const config = new Config({ shorthands, @@ -1318,6 +1359,42 @@ t.test('workspaces', async (t) => { }) }) +t.test('exclusive options conflict', async t => { + const path = t.testdir() + const config = new Config({ + env: {}, + npmPath: __dirname, + argv: [ + process.execPath, + __filename, + '--truth=true', + '--lie=true', + ], + cwd: join(`${path}/project`), + shorthands, + definitions: { + ...definitions, + ...createDef('truth', { + default: false, + type: Boolean, + description: 'The Truth', + exclusive: ['lie'], + }), + ...createDef('lie', { + default: false, + type: Boolean, + description: 'A Lie', + exclusive: ['truth'], + }), + }, + flatten, + }) + await t.rejects(config.load(), { + name: 'TypeError', + message: '--lie can not be provided when using --truth', + }) +}) + t.test('env-replaced config from files is not clobbered when saving', async (t) => { const path = t.testdir() const opts = { @@ -1340,3 +1417,33 @@ t.test('env-replaced config from files is not clobbered when saving', async (t) const rc = readFileSync(`${path}/.npmrc`, 'utf8') t.match(rc, 'test=${TEST}', '${TEST} is present, not parsed') }) + +t.test('umask', async t => { + const mockUmask = async (t, umask) => { + const path = t.testdir() + const config = new Config({ + env: {}, + npmPath: __dirname, + argv: [ + process.execPath, + __filename, + `--umask=${umask}`, + ], + cwd: join(`${path}/project`), + shorthands, + definitions, + flatten, + }) + await config.load() + return config.get('umask') + } + + t.test('valid', async t => { + const umask = await mockUmask(t, '777') + t.equal(umask, 777) + }) + t.test('invalid', async t => { + const umask = await mockUmask(t, true) + t.equal(umask, 0) + }) +}) diff --git a/workspaces/config/test/parse-field.js b/workspaces/config/test/parse-field.js index 29e8ccd68b69b..3dbeeae5f698f 100644 --- a/workspaces/config/test/parse-field.js +++ b/workspaces/config/test/parse-field.js @@ -2,11 +2,14 @@ const parseField = require('../lib/parse-field.js') const t = require('tap') const { resolve } = require('path') +const defs = require('../lib/definitions/definitions.js') +const types = Object.entries(defs).map(([k, v]) => [k, v.type]) + t.strictSame(parseField({ a: 1 }, 'a'), { a: 1 }) const opts = { platform: 'posix', - types: require('./fixtures/types.js'), + types: Object.fromEntries(types), home: '/home/user', env: { foo: 'bar' }, } @@ -34,5 +37,6 @@ t.equal(parseField('1234', 'maxsockets', opts), 1234, 'number is parsed') t.equal(parseField('0888', 'umask', opts), '0888', 'invalid umask is not parsed (will warn later)') t.equal(parseField('0777', 'umask', opts), 0o777, 'valid umask is parsed') +t.equal(parseField('777', 'umask', opts), 777, 'valid umask is parsed') t.same(parseField('2020', 'before', opts), new Date('2020'), 'date is parsed') diff --git a/workspaces/config/test/set-envs.js b/workspaces/config/test/set-envs.js index c663c2236d203..74eba262aa161 100644 --- a/workspaces/config/test/set-envs.js +++ b/workspaces/config/test/set-envs.js @@ -1,16 +1,22 @@ const setEnvs = require('../lib/set-envs.js') +const mockGlobals = require('@npmcli/mock-globals') const { join } = require('path') const t = require('tap') -const defaults = require('./fixtures/defaults.js') -const definitions = require('./fixtures/definitions.js') const { execPath } = process const cwd = process.cwd() const globalPrefix = join(cwd, 'global') const localPrefix = join(cwd, 'local') const NODE = execPath +const mockDefinitions = (t) => { + mockGlobals(t, { 'process.env': { EDITOR: 'vim' } }) + const { definitions, defaults } = t.mock('../lib/definitions/index.js') + return { definitions, defaults } +} + t.test('set envs that are not defaults and not already in env', t => { + const { definitions, defaults } = mockDefinitions(t) const envConf = Object.create(defaults) const cliConf = Object.create(envConf) const extras = { @@ -61,6 +67,7 @@ t.test('set envs that are not defaults and not already in env', t => { }) t.test('set envs that are not defaults and not already in env, array style', t => { + const { definitions, defaults } = mockDefinitions(t) const envConf = Object.create(defaults) const cliConf = Object.create(envConf) const extras = { @@ -108,6 +115,7 @@ t.test('set envs that are not defaults and not already in env, array style', t = }) t.test('set envs that are not defaults and not already in env, boolean edition', t => { + const { definitions, defaults } = mockDefinitions(t) const envConf = Object.create(defaults) const cliConf = Object.create(envConf) const extras = { @@ -157,6 +165,7 @@ t.test('set envs that are not defaults and not already in env, boolean edition', }) t.test('dont set npm_execpath if require.main.filename is not set', t => { + const { definitions, defaults } = mockDefinitions(t) const { filename } = require.main t.teardown(() => require.main.filename = filename) require.main.filename = null @@ -180,6 +189,7 @@ t.test('dont set npm_execpath if require.main.filename is not set', t => { }) t.test('dont set configs marked as envExport:false', t => { + const { definitions, defaults } = mockDefinitions(t) const envConf = Object.create(defaults) const cliConf = Object.create(envConf) const extras = { @@ -205,7 +215,7 @@ t.test('dont set configs marked as envExport:false', t => { } setEnvs(config) t.strictSame(env, { ...extras }, 'no new environment vars to create') - cliConf.methane = 'CO2' + cliConf['include-workspace-root'] = true setEnvs(config) t.strictSame(env, { ...extras }, 'not exported, because envExport=false') t.end() diff --git a/workspaces/config/test/type-description.js b/workspaces/config/test/type-description.js index d487c118940ec..6b6c56e8c824e 100644 --- a/workspaces/config/test/type-description.js +++ b/workspaces/config/test/type-description.js @@ -1,8 +1,10 @@ const t = require('tap') const typeDescription = require('../lib/type-description.js') -const types = require('./fixtures/types.js') +const defs = require('../lib/definitions/definitions.js') + const descriptions = {} -for (const [name, type] of Object.entries(types)) { + +for (const [name, { type }] of Object.entries(defs)) { const desc = typeDescription(type) if (name === 'local-address') { t.strictSame(desc.sort(), type.filter(t => t !== undefined).sort()) @@ -12,3 +14,6 @@ for (const [name, type] of Object.entries(types)) { } t.matchSnapshot(descriptions) + +class Unknown {} +t.strictSame(typeDescription(Unknown), [Unknown], 'unknown class returns itself') diff --git a/workspaces/libnpmdiff/CHANGELOG.md b/workspaces/libnpmdiff/CHANGELOG.md index 5411b23b7c358..0cc4888a43d58 100644 --- a/workspaces/libnpmdiff/CHANGELOG.md +++ b/workspaces/libnpmdiff/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [5.0.18](https://github.com/npm/cli/compare/libnpmdiff-v5.0.17...libnpmdiff-v5.0.18) (2023-06-21) + +### Dependencies + +* [Workspace](https://github.com/npm/cli/releases/tag/arborist-v6.2.10): `@npmcli/arborist@6.2.10` + ## [5.0.17](https://github.com/npm/cli/compare/libnpmdiff-v5.0.16...libnpmdiff-v5.0.17) (2023-05-03) ### Dependencies diff --git a/workspaces/libnpmdiff/package.json b/workspaces/libnpmdiff/package.json index 9e2e96bae61c9..d785ba9131f8a 100644 --- a/workspaces/libnpmdiff/package.json +++ b/workspaces/libnpmdiff/package.json @@ -1,6 +1,6 @@ { "name": "libnpmdiff", - "version": "5.0.17", + "version": "5.0.18", "description": "The registry diff", "repository": { "type": "git", @@ -46,7 +46,7 @@ "tap": "^16.3.4" }, "dependencies": { - "@npmcli/arborist": "^6.2.9", + "@npmcli/arborist": "^6.2.10", "@npmcli/disparity-colors": "^3.0.0", "@npmcli/installed-package-contents": "^2.0.2", "binary-extensions": "^2.2.0", diff --git a/workspaces/libnpmexec/CHANGELOG.md b/workspaces/libnpmexec/CHANGELOG.md index f7b190c380f9c..03fef83ed90d2 100644 --- a/workspaces/libnpmexec/CHANGELOG.md +++ b/workspaces/libnpmexec/CHANGELOG.md @@ -1,5 +1,21 @@ # Changelog +## [6.0.1](https://github.com/npm/cli/compare/libnpmexec-v6.0.0...libnpmexec-v6.0.1) (2023-06-21) + +### Dependencies + +* [Workspace](https://github.com/npm/cli/releases/tag/arborist-v6.2.10): `@npmcli/arborist@6.2.10` + +## [6.0.0](https://github.com/npm/cli/compare/libnpmexec-v5.0.17...libnpmexec-v6.0.0) (2023-05-31) + +### ⚠️ BREAKING CHANGES + +* require passing in chalk instance + +### Features + +* [`9e7f5ac`](https://github.com/npm/cli/commit/9e7f5ac5caa8a8ad710cc726744dcaadd8efb040) require passing in chalk instance (@lukekarrys) + ## [5.0.17](https://github.com/npm/cli/compare/libnpmexec-v5.0.16...libnpmexec-v5.0.17) (2023-05-03) ### Dependencies diff --git a/workspaces/libnpmexec/README.md b/workspaces/libnpmexec/README.md index dc79d12cffc45..fb4a1e32b18df 100644 --- a/workspaces/libnpmexec/README.md +++ b/workspaces/libnpmexec/README.md @@ -31,7 +31,7 @@ await libexec({ - `call`: An alternative command to run when using `packages` option **String**, defaults to empty string. - `cache`: The path location to where the npm cache folder is placed **String** - `npxCache`: The path location to where the npx cache folder is placed **String** - - `color`: Output should use color? **Boolean**, defaults to `false` + - `chalk`: Chalk instance to use for colors? **Required** - `localBin`: Location to the `node_modules/.bin` folder of the local project to start scanning for bin files **String**, defaults to `./node_modules/.bin`. **libexec** will walk up the directory structure looking for `node_modules/.bin` folders in parent folders that might satisfy the current `arg` and will use that bin if found. - `locationMsg`: Overrides "at location" message when entering interactive mode **String** - `globalBin`: Location to the global space bin folder, same as: `$(npm bin -g)` **String**, defaults to empty string. diff --git a/workspaces/libnpmexec/lib/run-script.js b/workspaces/libnpmexec/lib/run-script.js index ba60395468d62..89dcf2e653036 100644 --- a/workspaces/libnpmexec/lib/run-script.js +++ b/workspaces/libnpmexec/lib/run-script.js @@ -1,4 +1,3 @@ -const chalk = require('chalk') const ciInfo = require('ci-info') const runScript = require('@npmcli/run-script') const readPackageJson = require('read-package-json-fast') @@ -6,12 +5,6 @@ const npmlog = require('npmlog') const log = require('proc-log') const noTTY = require('./no-tty.js') -const nocolor = { - reset: s => s, - bold: s => s, - dim: s => s, -} - const run = async ({ args, call, @@ -25,8 +18,6 @@ const run = async ({ }) => { // turn list of args into command string const script = call || args.shift() || scriptShell - const color = !!flatOptions.color - const colorize = color ? chalk : nocolor // do the fakey runScript dance // still should work if no package.json in cwd @@ -49,14 +40,14 @@ const run = async ({ return log.warn('exec', 'Interactive mode disabled in CI environment') } - locationMsg = locationMsg || ` at location:\n${colorize.dim(runPath)}` + locationMsg = locationMsg || ` at location:\n${flatOptions.chalk.dim(runPath)}` output(`${ - colorize.reset('\nEntering npm script environment') + flatOptions.chalk.reset('\nEntering npm script environment') }${ - colorize.reset(locationMsg) + flatOptions.chalk.reset(locationMsg) }${ - colorize.bold('\nType \'exit\' or ^D when finished\n') + flatOptions.chalk.bold('\nType \'exit\' or ^D when finished\n') }`) } } diff --git a/workspaces/libnpmexec/package.json b/workspaces/libnpmexec/package.json index e47e301ab7dd7..8a908625c887c 100644 --- a/workspaces/libnpmexec/package.json +++ b/workspaces/libnpmexec/package.json @@ -1,6 +1,6 @@ { "name": "libnpmexec", - "version": "5.0.17", + "version": "6.0.1", "files": [ "bin/", "lib/" @@ -42,7 +42,6 @@ "template-oss-apply": "template-oss-apply --force" }, "tap": { - "color": true, "files": "test/*.js", "nyc-arg": [ "--exclude", @@ -54,15 +53,14 @@ "@npmcli/mock-registry": "^1.0.0", "@npmcli/template-oss": "4.14.1", "bin-links": "^4.0.1", + "chalk": "^5.2.0", "just-extend": "^6.2.0", "just-safe-set": "^4.2.1", - "minify-registry-metadata": "^3.0.0", "tap": "^16.3.4" }, "dependencies": { - "@npmcli/arborist": "^6.2.9", + "@npmcli/arborist": "^6.2.10", "@npmcli/run-script": "^6.0.0", - "chalk": "^4.1.0", "ci-info": "^3.7.1", "npm-package-arg": "^10.1.0", "npmlog": "^7.0.1", diff --git a/workspaces/libnpmexec/test/run-script.js b/workspaces/libnpmexec/test/run-script.js index d360fc1a2025b..b3289c6b15c4b 100644 --- a/workspaces/libnpmexec/test/run-script.js +++ b/workspaces/libnpmexec/test/run-script.js @@ -1,18 +1,22 @@ const t = require('tap') -const baseOpts = { - args: [], - call: '', - color: false, - flatOptions: {}, - path: '', - runPath: '', - shell: process.platform === 'win32' - ? process.env.ComSpec || 'cmd' - : process.env.SHELL || 'sh', +const mockRunScript = async (t, mocks, { level = 0 } = {}) => { + const runScript = t.mock('../lib/run-script.js', mocks) + const { Chalk } = await import('chalk') + return (opts) => runScript({ + args: [], + call: '', + path: '', + runPath: '', + shell: process.platform === 'win32' + ? process.env.ComSpec || 'cmd' + : process.env.SHELL || 'sh', + ...opts, + flatOptions: { chalk: new Chalk({ level }) }, + }) } -t.test('disable, enable log progress', t => { +t.test('disable, enable log progress', async t => { t.plan(3) const path = t.testdir({ @@ -20,7 +24,7 @@ t.test('disable, enable log progress', t => { name: 'pkg', }), }) - const runScript = t.mock('../lib/run-script.js', { + const runScript = await mockRunScript(t, { 'ci-info': { isCI: false }, '@npmcli/run-script': async () => { t.ok('should call run-script') @@ -36,16 +40,18 @@ t.test('disable, enable log progress', t => { }, }) - runScript({ - ...baseOpts, - path, - }) + await runScript({ path }) }) -t.test('no package.json', t => { +t.test('no package.json', async t => { t.plan(1) - const runScript = t.mock('../lib/run-script.js', { + const path = t.testdir({ + 'package.json': JSON.stringify({ + name: 'pkg', + }), + }) + const runScript = await mockRunScript(t, { 'ci-info': { isCI: false }, '@npmcli/run-script': async () => { t.ok('should call run-script') @@ -53,28 +59,26 @@ t.test('no package.json', t => { '../lib/no-tty.js': () => false, }) - runScript(baseOpts) + await runScript({ path }) }) t.test('colorized interactive mode msg', async t => { t.plan(2) - const runScript = t.mock('../lib/run-script.js', { + const runScript = await mockRunScript(t, { 'ci-info': { isCI: false }, '@npmcli/run-script': async () => { t.ok('should call run-script') }, '../lib/no-tty.js': () => false, - }) + }, { level: 3 }) const OUTPUT = [] await runScript({ - ...baseOpts, output: msg => { OUTPUT.push(msg) }, runPath: '/foo/', - flatOptions: { color: true }, }) t.matchSnapshot(OUTPUT.join('\n'), 'should print colorized output') }) @@ -82,7 +86,7 @@ t.test('colorized interactive mode msg', async t => { t.test('no color interactive mode msg', async t => { t.plan(2) - const runScript = t.mock('../lib/run-script.js', { + const runScript = await mockRunScript(t, { 'ci-info': { isCI: false }, '@npmcli/run-script': async () => { t.ok('should call run-script') @@ -92,7 +96,6 @@ t.test('no color interactive mode msg', async t => { const OUTPUT = [] await runScript({ - ...baseOpts, output: msg => { OUTPUT.push(msg) }, @@ -101,10 +104,10 @@ t.test('no color interactive mode msg', async t => { t.matchSnapshot(OUTPUT.join('\n'), 'should print non-colorized output') }) -t.test('no tty', t => { +t.test('no tty', async t => { t.plan(1) - const runScript = t.mock('../lib/run-script.js', { + const runScript = await mockRunScript(t, { 'ci-info': { isCI: false }, '@npmcli/run-script': async () => { t.ok('should call run-script') @@ -112,13 +115,13 @@ t.test('no tty', t => { '../lib/no-tty.js': () => true, }) - runScript(baseOpts) + await runScript() }) -t.test('ci env', t => { +t.test('ci env', async t => { t.plan(2) - const runScript = t.mock('../lib/run-script.js', { + const runScript = await mockRunScript(t, { 'ci-info': { isCI: true }, '@npmcli/run-script': async () => { throw new Error('should not call run-script') @@ -136,5 +139,5 @@ t.test('ci env', t => { }, }) - runScript({ ...baseOpts }) + await runScript() }) diff --git a/workspaces/libnpmfund/CHANGELOG.md b/workspaces/libnpmfund/CHANGELOG.md index cc95e274957a3..1405eed478070 100644 --- a/workspaces/libnpmfund/CHANGELOG.md +++ b/workspaces/libnpmfund/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [4.0.18](https://github.com/npm/cli/compare/libnpmfund-v4.0.17...libnpmfund-v4.0.18) (2023-06-21) + +### Dependencies + +* [Workspace](https://github.com/npm/cli/releases/tag/arborist-v6.2.10): `@npmcli/arborist@6.2.10` + ## [4.0.17](https://github.com/npm/cli/compare/libnpmfund-v4.0.16...libnpmfund-v4.0.17) (2023-05-03) ### Dependencies diff --git a/workspaces/libnpmfund/package.json b/workspaces/libnpmfund/package.json index 88cff7aa6bb11..447653152811e 100644 --- a/workspaces/libnpmfund/package.json +++ b/workspaces/libnpmfund/package.json @@ -1,6 +1,6 @@ { "name": "libnpmfund", - "version": "4.0.17", + "version": "4.0.18", "main": "lib/index.js", "files": [ "bin/", @@ -45,7 +45,7 @@ "tap": "^16.3.4" }, "dependencies": { - "@npmcli/arborist": "^6.2.9" + "@npmcli/arborist": "^6.2.10" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" diff --git a/workspaces/libnpmpack/CHANGELOG.md b/workspaces/libnpmpack/CHANGELOG.md index 4b4d4e8af89c6..b5858202d5ab2 100644 --- a/workspaces/libnpmpack/CHANGELOG.md +++ b/workspaces/libnpmpack/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [5.0.18](https://github.com/npm/cli/compare/libnpmpack-v5.0.17...libnpmpack-v5.0.18) (2023-06-21) + +### Dependencies + +* [Workspace](https://github.com/npm/cli/releases/tag/arborist-v6.2.10): `@npmcli/arborist@6.2.10` + ## [5.0.17](https://github.com/npm/cli/compare/libnpmpack-v5.0.16...libnpmpack-v5.0.17) (2023-05-03) ### Dependencies diff --git a/workspaces/libnpmpack/package.json b/workspaces/libnpmpack/package.json index 8589f5ddea892..294bb7a82ed5b 100644 --- a/workspaces/libnpmpack/package.json +++ b/workspaces/libnpmpack/package.json @@ -1,6 +1,6 @@ { "name": "libnpmpack", - "version": "5.0.17", + "version": "5.0.18", "description": "Programmatic API for the bits behind npm pack", "author": "GitHub Inc.", "main": "lib/index.js", @@ -36,7 +36,7 @@ "bugs": "https://github.com/npm/libnpmpack/issues", "homepage": "https://npmjs.com/package/libnpmpack", "dependencies": { - "@npmcli/arborist": "^6.2.9", + "@npmcli/arborist": "^6.2.10", "@npmcli/run-script": "^6.0.0", "npm-package-arg": "^10.1.0", "pacote": "^15.0.8" diff --git a/workspaces/libnpmpublish/CHANGELOG.md b/workspaces/libnpmpublish/CHANGELOG.md index 14aaec31fdf23..106784026d86f 100644 --- a/workspaces/libnpmpublish/CHANGELOG.md +++ b/workspaces/libnpmpublish/CHANGELOG.md @@ -1,5 +1,31 @@ # Changelog +## [7.4.0](https://github.com/npm/cli/compare/libnpmpublish-v7.3.0...libnpmpublish-v7.4.0) (2023-06-21) + +### Features + +* [`7701105`](https://github.com/npm/cli/commit/770110535c07502e30619c3def8f35a522c36427) [#6526](https://github.com/npm/cli/pull/6526) Add GitLab CI provenance (#6375) (#6526) (@wraithgar, @wlynch) + +### Bug Fixes + +* [`29622c1`](https://github.com/npm/cli/commit/29622c1349b38173924058a1fb0ede9edf8a5f6f) [#6530](https://github.com/npm/cli/pull/6530) public package check in libnpmpublish (#6530) (@bdehamer) + +## [7.3.0](https://github.com/npm/cli/compare/libnpmpublish-v7.2.0...libnpmpublish-v7.3.0) (2023-05-31) + +### Features + +* [`a63a6d8`](https://github.com/npm/cli/commit/a63a6d8d6fd339d504ab94c0364ce7ee3d4e3775) [#6490](https://github.com/npm/cli/pull/6490) add provenanceFile option for libnpmpublish (@bdehamer) + +## [7.2.0](https://github.com/npm/cli/compare/libnpmpublish-v7.1.4...libnpmpublish-v7.2.0) (2023-05-17) + +### Features + +* [`bdab631`](https://github.com/npm/cli/commit/bdab631b9847013dc4e8d4083669acf6c7bfb457) [#6428](https://github.com/npm/cli/pull/6428) expose provenance transparency url (#6428) (@JamesHenry, @wraithgar) + +### Bug Fixes + +* [`f064696`](https://github.com/npm/cli/commit/f06469607b80faf72eb897ec3e33deebc6dc10fc) [#6437](https://github.com/npm/cli/pull/6437) Update publish /w provenance to ignore pkg vis 404 (#6437) (@feelepxyz) + ## [7.1.4](https://github.com/npm/cli/compare/libnpmpublish-v7.1.3...libnpmpublish-v7.1.4) (2023-05-03) ### Dependencies diff --git a/workspaces/libnpmpublish/README.md b/workspaces/libnpmpublish/README.md index 9c9c61d4b5965..90b1f7c68ab4f 100644 --- a/workspaces/libnpmpublish/README.md +++ b/workspaces/libnpmpublish/README.md @@ -51,6 +51,17 @@ A couple of options of note: token for the registry. For other ways to pass in auth details, see the n-r-f docs. +* `opts.provenance` - when running in a supported CI environment, will trigger + the generation of a signed provenance statement to be published alongside + the package. Mutually exclusive with the `provenanceFile` option. + +* `opts.provenanceFile` - specifies the path to an externally-generated + provenance statement to be published alongside the package. Mutually + exclusive with the `provenance` option. The specified file should be a + [Sigstore Bundle](https://github.com/sigstore/protobuf-specs/blob/main/protos/sigstore_bundle.proto) + containing a [DSSE](https://github.com/secure-systems-lab/dsse)-packaged + provenance statement. + #### `> libpub.publish(manifest, tarData, [opts]) -> Promise` Sends the package represented by the `manifest` and `tarData` to the diff --git a/workspaces/libnpmpublish/lib/provenance.js b/workspaces/libnpmpublish/lib/provenance.js index 1eb870da5f24f..19859e9dd6f61 100644 --- a/workspaces/libnpmpublish/lib/provenance.js +++ b/workspaces/libnpmpublish/lib/provenance.js @@ -1,71 +1,251 @@ const { sigstore } = require('sigstore') +const { readFile } = require('fs/promises') +const ci = require('ci-info') +const { env } = process const INTOTO_PAYLOAD_TYPE = 'application/vnd.in-toto+json' const INTOTO_STATEMENT_TYPE = 'https://in-toto.io/Statement/v0.1' const SLSA_PREDICATE_TYPE = 'https://slsa.dev/provenance/v0.2' -const BUILDER_ID = 'https://github.com/actions/runner' -const BUILD_TYPE_PREFIX = 'https://github.com/npm/cli/gha' -const BUILD_TYPE_VERSION = 'v2' +const GITHUB_BUILDER_ID = 'https://github.com/actions/runner' +const GITHUB_BUILD_TYPE_PREFIX = 'https://github.com/npm/cli/gha' +const GITHUB_BUILD_TYPE_VERSION = 'v2' + +const GITLAB_BUILD_TYPE_PREFIX = 'https://github.com/npm/cli/gitlab' +const GITLAB_BUILD_TYPE_VERSION = 'v0alpha1' const generateProvenance = async (subject, opts) => { - const { env } = process - /* istanbul ignore next - not covering missing env var case */ - const [workflowPath] = (env.GITHUB_WORKFLOW_REF || '') - .replace(env.GITHUB_REPOSITORY + '/', '') - .split('@') - const payload = { - _type: INTOTO_STATEMENT_TYPE, - subject, - predicateType: SLSA_PREDICATE_TYPE, - predicate: { - buildType: `${BUILD_TYPE_PREFIX}/${BUILD_TYPE_VERSION}`, - builder: { id: BUILDER_ID }, - invocation: { - configSource: { - uri: `git+${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}@${env.GITHUB_REF}`, - digest: { - sha1: env.GITHUB_SHA, + let payload + if (ci.GITHUB_ACTIONS) { + /* istanbul ignore next - not covering missing env var case */ + const [workflowPath] = (env.GITHUB_WORKFLOW_REF || '') + .replace(env.GITHUB_REPOSITORY + '/', '') + .split('@') + payload = { + _type: INTOTO_STATEMENT_TYPE, + subject, + predicateType: SLSA_PREDICATE_TYPE, + predicate: { + buildType: `${GITHUB_BUILD_TYPE_PREFIX}/${GITHUB_BUILD_TYPE_VERSION}`, + builder: { id: GITHUB_BUILDER_ID }, + invocation: { + configSource: { + uri: `git+${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}@${env.GITHUB_REF}`, + digest: { + sha1: env.GITHUB_SHA, + }, + entryPoint: workflowPath, + }, + parameters: {}, + environment: { + GITHUB_EVENT_NAME: env.GITHUB_EVENT_NAME, + GITHUB_REF: env.GITHUB_REF, + GITHUB_REPOSITORY: env.GITHUB_REPOSITORY, + GITHUB_REPOSITORY_ID: env.GITHUB_REPOSITORY_ID, + GITHUB_REPOSITORY_OWNER_ID: env.GITHUB_REPOSITORY_OWNER_ID, + GITHUB_RUN_ATTEMPT: env.GITHUB_RUN_ATTEMPT, + GITHUB_RUN_ID: env.GITHUB_RUN_ID, + GITHUB_SHA: env.GITHUB_SHA, + GITHUB_WORKFLOW_REF: env.GITHUB_WORKFLOW_REF, + GITHUB_WORKFLOW_SHA: env.GITHUB_WORKFLOW_SHA, }, - entryPoint: workflowPath, }, - parameters: {}, - environment: { - GITHUB_EVENT_NAME: env.GITHUB_EVENT_NAME, - GITHUB_REF: env.GITHUB_REF, - GITHUB_REPOSITORY: env.GITHUB_REPOSITORY, - GITHUB_REPOSITORY_ID: env.GITHUB_REPOSITORY_ID, - GITHUB_REPOSITORY_OWNER_ID: env.GITHUB_REPOSITORY_OWNER_ID, - GITHUB_RUN_ATTEMPT: env.GITHUB_RUN_ATTEMPT, - GITHUB_RUN_ID: env.GITHUB_RUN_ID, - GITHUB_SHA: env.GITHUB_SHA, - GITHUB_WORKFLOW_REF: env.GITHUB_WORKFLOW_REF, - GITHUB_WORKFLOW_SHA: env.GITHUB_WORKFLOW_SHA, + metadata: { + buildInvocationId: `${env.GITHUB_RUN_ID}-${env.GITHUB_RUN_ATTEMPT}`, + completeness: { + parameters: false, + environment: false, + materials: false, + }, + reproducible: false, }, + materials: [ + { + uri: `git+${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}@${env.GITHUB_REF}`, + digest: { + sha1: env.GITHUB_SHA, + }, + }, + ], }, - metadata: { - buildInvocationId: `${env.GITHUB_RUN_ID}-${env.GITHUB_RUN_ATTEMPT}`, - completeness: { - parameters: false, - environment: false, - materials: false, + } + } + if (ci.GITLAB) { + payload = { + _type: INTOTO_STATEMENT_TYPE, + subject, + predicateType: SLSA_PREDICATE_TYPE, + predicate: { + buildType: `${GITLAB_BUILD_TYPE_PREFIX}/${GITLAB_BUILD_TYPE_VERSION}`, + builder: { id: `${env.CI_PROJECT_URL}/-/runners/${env.CI_RUNNER_ID}` }, + invocation: { + configSource: { + uri: `git+${env.CI_PROJECT_URL}`, + digest: { + sha1: env.CI_COMMIT_SHA, + }, + entryPoint: env.CI_JOB_NAME, + }, + parameters: { + CI: env.CI, + CI_API_GRAPHQL_URL: env.CI_API_GRAPHQL_URL, + CI_API_V4_URL: env.CI_API_V4_URL, + CI_BUILD_BEFORE_SHA: env.CI_BUILD_BEFORE_SHA, + CI_BUILD_ID: env.CI_BUILD_ID, + CI_BUILD_NAME: env.CI_BUILD_NAME, + CI_BUILD_REF: env.CI_BUILD_REF, + CI_BUILD_REF_NAME: env.CI_BUILD_REF_NAME, + CI_BUILD_REF_SLUG: env.CI_BUILD_REF_SLUG, + CI_BUILD_STAGE: env.CI_BUILD_STAGE, + CI_COMMIT_BEFORE_SHA: env.CI_COMMIT_BEFORE_SHA, + CI_COMMIT_BRANCH: env.CI_COMMIT_BRANCH, + CI_COMMIT_REF_NAME: env.CI_COMMIT_REF_NAME, + CI_COMMIT_REF_PROTECTED: env.CI_COMMIT_REF_PROTECTED, + CI_COMMIT_REF_SLUG: env.CI_COMMIT_REF_SLUG, + CI_COMMIT_SHA: env.CI_COMMIT_SHA, + CI_COMMIT_SHORT_SHA: env.CI_COMMIT_SHORT_SHA, + CI_COMMIT_TIMESTAMP: env.CI_COMMIT_TIMESTAMP, + CI_COMMIT_TITLE: env.CI_COMMIT_TITLE, + CI_CONFIG_PATH: env.CI_CONFIG_PATH, + CI_DEFAULT_BRANCH: env.CI_DEFAULT_BRANCH, + CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX: + env.CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX, + CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX: env.CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX, + CI_DEPENDENCY_PROXY_SERVER: env.CI_DEPENDENCY_PROXY_SERVER, + CI_DEPENDENCY_PROXY_USER: env.CI_DEPENDENCY_PROXY_USER, + CI_JOB_ID: env.CI_JOB_ID, + CI_JOB_NAME: env.CI_JOB_NAME, + CI_JOB_NAME_SLUG: env.CI_JOB_NAME_SLUG, + CI_JOB_STAGE: env.CI_JOB_STAGE, + CI_JOB_STARTED_AT: env.CI_JOB_STARTED_AT, + CI_JOB_URL: env.CI_JOB_URL, + CI_NODE_TOTAL: env.CI_NODE_TOTAL, + CI_PAGES_DOMAIN: env.CI_PAGES_DOMAIN, + CI_PAGES_URL: env.CI_PAGES_URL, + CI_PIPELINE_CREATED_AT: env.CI_PIPELINE_CREATED_AT, + CI_PIPELINE_ID: env.CI_PIPELINE_ID, + CI_PIPELINE_IID: env.CI_PIPELINE_IID, + CI_PIPELINE_SOURCE: env.CI_PIPELINE_SOURCE, + CI_PIPELINE_URL: env.CI_PIPELINE_URL, + CI_PROJECT_CLASSIFICATION_LABEL: env.CI_PROJECT_CLASSIFICATION_LABEL, + CI_PROJECT_DESCRIPTION: env.CI_PROJECT_DESCRIPTION, + CI_PROJECT_ID: env.CI_PROJECT_ID, + CI_PROJECT_NAME: env.CI_PROJECT_NAME, + CI_PROJECT_NAMESPACE: env.CI_PROJECT_NAMESPACE, + CI_PROJECT_NAMESPACE_ID: env.CI_PROJECT_NAMESPACE_ID, + CI_PROJECT_PATH: env.CI_PROJECT_PATH, + CI_PROJECT_PATH_SLUG: env.CI_PROJECT_PATH_SLUG, + CI_PROJECT_REPOSITORY_LANGUAGES: env.CI_PROJECT_REPOSITORY_LANGUAGES, + CI_PROJECT_ROOT_NAMESPACE: env.CI_PROJECT_ROOT_NAMESPACE, + CI_PROJECT_TITLE: env.CI_PROJECT_TITLE, + CI_PROJECT_URL: env.CI_PROJECT_URL, + CI_PROJECT_VISIBILITY: env.CI_PROJECT_VISIBILITY, + CI_REGISTRY: env.CI_REGISTRY, + CI_REGISTRY_IMAGE: env.CI_REGISTRY_IMAGE, + CI_REGISTRY_USER: env.CI_REGISTRY_USER, + CI_RUNNER_DESCRIPTION: env.CI_RUNNER_DESCRIPTION, + CI_RUNNER_ID: env.CI_RUNNER_ID, + CI_RUNNER_TAGS: env.CI_RUNNER_TAGS, + CI_SERVER_HOST: env.CI_SERVER_HOST, + CI_SERVER_NAME: env.CI_SERVER_NAME, + CI_SERVER_PORT: env.CI_SERVER_PORT, + CI_SERVER_PROTOCOL: env.CI_SERVER_PROTOCOL, + CI_SERVER_REVISION: env.CI_SERVER_REVISION, + CI_SERVER_SHELL_SSH_HOST: env.CI_SERVER_SHELL_SSH_HOST, + CI_SERVER_SHELL_SSH_PORT: env.CI_SERVER_SHELL_SSH_PORT, + CI_SERVER_URL: env.CI_SERVER_URL, + CI_SERVER_VERSION: env.CI_SERVER_VERSION, + CI_SERVER_VERSION_MAJOR: env.CI_SERVER_VERSION_MAJOR, + CI_SERVER_VERSION_MINOR: env.CI_SERVER_VERSION_MINOR, + CI_SERVER_VERSION_PATCH: env.CI_SERVER_VERSION_PATCH, + CI_TEMPLATE_REGISTRY_HOST: env.CI_TEMPLATE_REGISTRY_HOST, + GITLAB_CI: env.GITLAB_CI, + GITLAB_FEATURES: env.GITLAB_FEATURES, + GITLAB_USER_ID: env.GITLAB_USER_ID, + GITLAB_USER_LOGIN: env.GITLAB_USER_LOGIN, + RUNNER_GENERATE_ARTIFACTS_METADATA: env.RUNNER_GENERATE_ARTIFACTS_METADATA, + }, + environment: { + name: env.CI_RUNNER_DESCRIPTION, + architecture: env.CI_RUNNER_EXECUTABLE_ARCH, + server: env.CI_SERVER_URL, + project: env.CI_PROJECT_PATH, + job: { + id: env.CI_JOB_ID, + }, + pipeline: { + id: env.CI_PIPELINE_ID, + ref: env.CI_CONFIG_PATH, + }, + }, }, - reproducible: false, - }, - materials: [ - { - uri: `git+${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}@${env.GITHUB_REF}`, - digest: { - sha1: env.GITHUB_SHA, + metadata: { + buildInvocationId: `${env.CI_JOB_URL}`, + completeness: { + parameters: true, + environment: true, + materials: false, }, + reproducible: false, }, - ], - }, + materials: [ + { + uri: `git+${env.CI_PROJECT_URL}`, + digest: { + sha1: env.CI_COMMIT_SHA, + }, + }, + ], + }, + } } - return sigstore.attest(Buffer.from(JSON.stringify(payload)), INTOTO_PAYLOAD_TYPE, opts) } +const verifyProvenance = async (subject, provenancePath) => { + let provenanceBundle + try { + provenanceBundle = JSON.parse(await readFile(provenancePath)) + } catch (err) { + err.message = `Invalid provenance provided: ${err.message}` + throw err + } + + const payload = extractProvenance(provenanceBundle) + if (!payload.subject || !payload.subject.length) { + throw new Error('No subject found in sigstore bundle payload') + } + if (payload.subject.length > 1) { + throw new Error('Found more than one subject in the sigstore bundle payload') + } + + const bundleSubject = payload.subject[0] + if (subject.name !== bundleSubject.name) { + throw new Error( + `Provenance subject ${bundleSubject.name} does not match the package: ${subject.name}` + ) + } + if (subject.digest.sha512 !== bundleSubject.digest.sha512) { + throw new Error('Provenance subject digest does not match the package') + } + + await sigstore.verify(provenanceBundle) + return provenanceBundle +} + +const extractProvenance = (bundle) => { + if (!bundle?.dsseEnvelope?.payload) { + throw new Error('No dsseEnvelope with payload found in sigstore bundle') + } + try { + return JSON.parse(Buffer.from(bundle.dsseEnvelope.payload, 'base64').toString('utf8')) + } catch (err) { + err.message = `Failed to parse payload from dsseEnvelope: ${err.message}` + throw err + } +} + module.exports = { generateProvenance, + verifyProvenance, } diff --git a/workspaces/libnpmpublish/lib/publish.js b/workspaces/libnpmpublish/lib/publish.js index 89ca01662cdb5..554eb9bec46f8 100644 --- a/workspaces/libnpmpublish/lib/publish.js +++ b/workspaces/libnpmpublish/lib/publish.js @@ -7,7 +7,7 @@ const { URL } = require('url') const ssri = require('ssri') const ciInfo = require('ci-info') -const { generateProvenance } = require('./provenance') +const { generateProvenance, verifyProvenance } = require('./provenance') const TLOG_BASE_URL = 'https://search.sigstore.dev/' @@ -42,15 +42,25 @@ Remove the 'private' field from the package.json to publish it.`), ) } - const metadata = await buildMetadata(reg, pubManifest, tarballData, spec, opts) + const { metadata, transparencyLogUrl } = await buildMetadata( + reg, + pubManifest, + tarballData, + spec, + opts + ) try { - return await npmFetch(spec.escapedName, { + const res = await npmFetch(spec.escapedName, { ...opts, method: 'PUT', body: metadata, ignoreBody: true, }) + if (transparencyLogUrl) { + res.transparencyLogUrl = transparencyLogUrl + } + return res } catch (err) { if (err.code !== 'E409') { throw err @@ -64,12 +74,17 @@ Remove the 'private' field from the package.json to publish it.`), query: { write: true }, }) const newMetadata = patchMetadata(current, metadata) - return npmFetch(spec.escapedName, { + const res = await npmFetch(spec.escapedName, { ...opts, method: 'PUT', body: newMetadata, ignoreBody: true, }) + /* istanbul ignore next */ + if (transparencyLogUrl) { + res.transparencyLogUrl = transparencyLogUrl + } + return res } } @@ -96,7 +111,7 @@ const patchManifest = (_manifest, opts) => { } const buildMetadata = async (registry, manifest, tarballData, spec, opts) => { - const { access, defaultTag, algorithms, provenance } = opts + const { access, defaultTag, algorithms, provenance, provenanceFile } = opts const root = { _id: manifest.name, name: manifest.name, @@ -138,48 +153,32 @@ const buildMetadata = async (registry, manifest, tarballData, spec, opts) => { } // Handle case where --provenance flag was set to true - if (provenance === true) { + let transparencyLogUrl + if (provenance === true || provenanceFile) { + let provenanceBundle const subject = { name: npa.toPurl(spec), digest: { sha512: integrity.sha512[0].hexDigest() }, } - // Ensure that we're running in GHA, currently the only supported build environment - if (ciInfo.name !== 'GitHub Actions') { - throw Object.assign( - new Error('Automatic provenance generation not supported outside of GitHub Actions'), - { code: 'EUSAGE' } - ) - } - - // Ensure that the GHA OIDC token is available - if (!process.env.ACTIONS_ID_TOKEN_REQUEST_URL) { - throw Object.assign( - /* eslint-disable-next-line max-len */ - new Error('Provenance generation in GitHub Actions requires "write" access to the "id-token" permission'), - { code: 'EUSAGE' } - ) - } - - const visibility = - await npmFetch.json(`${registry}/-/package/${spec.escapedName}/visibility`, opts) - if (!visibility.public && opts.provenance === true && opts.access !== 'public') { - throw Object.assign( - /* eslint-disable-next-line max-len */ - new Error("Can't generate provenance for new or private package, you must set `access` to public."), - { code: 'EUSAGE' } - ) - } - const provenanceBundle = await generateProvenance([subject], opts) - - /* eslint-disable-next-line max-len */ - log.notice('publish', 'Signed provenance statement with source and build information from GitHub Actions') - - const tlogEntry = provenanceBundle?.verificationMaterial?.tlogEntries[0] - /* istanbul ignore else */ - if (tlogEntry) { - const logUrl = `${TLOG_BASE_URL}?logIndex=${tlogEntry.logIndex}` - log.notice('publish', `Provenance statement published to transparency log: ${logUrl}`) + if (provenance === true) { + await ensureProvenanceGeneration(registry, spec, opts) + provenanceBundle = await generateProvenance([subject], opts) + + /* eslint-disable-next-line max-len */ + log.notice('publish', `Signed provenance statement with source and build information from ${ciInfo.name}`) + + const tlogEntry = provenanceBundle?.verificationMaterial?.tlogEntries[0] + /* istanbul ignore else */ + if (tlogEntry) { + transparencyLogUrl = `${TLOG_BASE_URL}?logIndex=${tlogEntry.logIndex}` + log.notice( + 'publish', + `Provenance statement published to transparency log: ${transparencyLogUrl}` + ) + } + } else { + provenanceBundle = await verifyProvenance(subject, provenanceFile) } const serializedBundle = JSON.stringify(provenanceBundle) @@ -190,7 +189,10 @@ const buildMetadata = async (registry, manifest, tarballData, spec, opts) => { } } - return root + return { + metadata: root, + transparencyLogUrl, + } } const patchMetadata = (current, newData) => { @@ -238,4 +240,57 @@ const patchMetadata = (current, newData) => { return current } +// Check that all the prereqs are met for provenance generation +const ensureProvenanceGeneration = async (registry, spec, opts) => { + if (ciInfo.GITHUB_ACTIONS) { + // Ensure that the GHA OIDC token is available + if (!process.env.ACTIONS_ID_TOKEN_REQUEST_URL) { + throw Object.assign( + /* eslint-disable-next-line max-len */ + new Error('Provenance generation in GitHub Actions requires "write" access to the "id-token" permission'), + { code: 'EUSAGE' } + ) + } + } else if (ciInfo.GITLAB) { + // Ensure that the Sigstore OIDC token is available + if (!process.env.SIGSTORE_ID_TOKEN) { + throw Object.assign( + /* eslint-disable-next-line max-len */ + new Error('Provenance generation in GitLab CI requires "SIGSTORE_ID_TOKEN" with "sigstore" audience to be present in "id_tokens". For more info see:\nhttps://docs.gitlab.com/ee/ci/secrets/id_token_authentication.html'), + { code: 'EUSAGE' } + ) + } + } else { + throw Object.assign( + new Error('Automatic provenance generation not supported for provider: ' + ciInfo.name), + { code: 'EUSAGE' } + ) + } + + // Some registries (e.g. GH packages) require auth to check visibility, + // and always return 404 when no auth is supplied. In this case we assume + // the package is always private and require `--access public` to publish + // with provenance. + let visibility = { public: false } + if (opts.access !== 'public') { + try { + const res = await npmFetch + .json(`${registry}/-/package/${spec.escapedName}/visibility`, opts) + visibility = res + } catch (err) { + if (err.code !== 'E404') { + throw err + } + } + } + + if (!visibility.public && opts.provenance === true && opts.access !== 'public') { + throw Object.assign( + /* eslint-disable-next-line max-len */ + new Error("Can't generate provenance for new or private package, you must set `access` to public."), + { code: 'EUSAGE' } + ) + } +} + module.exports = publish diff --git a/workspaces/libnpmpublish/package.json b/workspaces/libnpmpublish/package.json index 2034ef85e4739..151f455afb6e8 100644 --- a/workspaces/libnpmpublish/package.json +++ b/workspaces/libnpmpublish/package.json @@ -1,6 +1,6 @@ { "name": "libnpmpublish", - "version": "7.1.4", + "version": "7.4.0", "description": "Programmatic API for the bits behind npm publish and unpublish", "author": "GitHub Inc.", "main": "lib/index.js", @@ -24,6 +24,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", + "@npmcli/mock-globals": "^1.0.0", "@npmcli/mock-registry": "^1.0.0", "@npmcli/template-oss": "4.14.1", "lodash.clonedeep": "^4.5.0", diff --git a/workspaces/libnpmpublish/test/publish.js b/workspaces/libnpmpublish/test/publish.js index 065765807b889..d83f6e7a58ace 100644 --- a/workspaces/libnpmpublish/test/publish.js +++ b/workspaces/libnpmpublish/test/publish.js @@ -8,7 +8,7 @@ const ssri = require('ssri') const t = require('tap') const MockRegistry = require('@npmcli/mock-registry') -const mockGlobals = require('../../../test/fixtures/mock-globals.js') +const mockGlobals = require('@npmcli/mock-globals') // TODO use registry.manifest (requires json date wrangling for nock) @@ -511,6 +511,7 @@ t.test('publish includes access', async t => { }) t.ok(ret, 'publish succeeded') + t.notOk(ret.transparencyLogUrl, 'no transparencyLogUrl for non-provenance publish') }) t.test('refuse if package is unscoped plus `restricted` access', async t => { @@ -775,7 +776,6 @@ t.test('publish existing package with provenance in gha', async t => { .post('/api/v1/log/entries') .reply(201, rekorEntry) - registry.getVisibility({ spec, visibility: { public: true } }) registry.nock.put(`/${spec.escapedName}`, body => { const bundleAttachment = body._attachments['@npmcli/libnpmpublish-test-1.0.0.sigstore'] const bundle = JSON.parse(bundleAttachment.data) @@ -804,6 +804,11 @@ t.test('publish existing package with provenance in gha', async t => { rekorURL: rekorURL, }) t.ok(ret, 'publish succeeded') + t.equal( + ret.transparencyLogUrl, + 'https://search.sigstore.dev/?logIndex=2513258', + 'has appropriate transparencyLogUrl property' + ) t.match(log, [ ['notice', 'publish', 'Signed provenance statement with source and build information from GitHub Actions'], @@ -849,6 +854,78 @@ t.test('publish new/private package with provenance in gha - no access', async t ) }) +t.test('publish new package with provenance in gha when visibility 404s - no access', async t => { + const oidcURL = 'https://mock.oidc' + const requestToken = 'decafbad' + mockGlobals(t, { + 'process.env': { + CI: true, + GITHUB_ACTIONS: true, + ACTIONS_ID_TOKEN_REQUEST_URL: oidcURL, + ACTIONS_ID_TOKEN_REQUEST_TOKEN: requestToken, + }, + }) + const { publish } = t.mock('..', { 'ci-info': t.mock('ci-info') }) + const registry = new MockRegistry({ + tap: t, + registry: opts.registry, + authorization: token, + strict: true, + }) + const manifest = { + name: '@npmcli/libnpmpublish-test', + version: '1.0.0', + description: 'test libnpmpublish package', + } + const spec = npa(manifest.name) + registry.getVisibility({ spec, responseCode: 404 }) + + await t.rejects( + publish(manifest, Buffer.from(''), { + ...opts, + access: null, + provenance: true, + }), + { code: 'EUSAGE' } + ) +}) + +t.test('publish new package with provenance in gha when visibility 500s - no access', async t => { + const oidcURL = 'https://mock.oidc' + const requestToken = 'decafbad' + mockGlobals(t, { + 'process.env': { + CI: true, + GITHUB_ACTIONS: true, + ACTIONS_ID_TOKEN_REQUEST_URL: oidcURL, + ACTIONS_ID_TOKEN_REQUEST_TOKEN: requestToken, + }, + }) + const { publish } = t.mock('..', { 'ci-info': t.mock('ci-info') }) + const registry = new MockRegistry({ + tap: t, + registry: opts.registry, + authorization: token, + strict: true, + }) + const manifest = { + name: '@npmcli/libnpmpublish-test', + version: '1.0.0', + description: 'test libnpmpublish package', + } + const spec = npa(manifest.name) + registry.getVisibility({ spec, responseCode: 500 }) + + await t.rejects( + publish(manifest, Buffer.from(''), { + ...opts, + access: null, + provenance: true, + }), + { code: 'E500' } + ) +}) + t.test('automatic provenance in unsupported environment', async t => { mockGlobals(t, { 'process.env': { @@ -903,3 +980,406 @@ t.test('automatic provenance with incorrect permissions', async t => { } ) }) + +t.test('user-supplied provenance - success', async t => { + const { publish } = t.mock('..', { + '../lib/provenance': t.mock('../lib/provenance', { + sigstore: { sigstore: { verify: () => {} } }, + }), + }) + + const registry = new MockRegistry({ + tap: t, + registry: opts.registry, + authorization: token, + }) + const manifest = { + name: '@npmcli/libnpmpublish-test', + version: '1.0.0', + description: 'test libnpmpublish package', + } + const spec = npa(manifest.name) + const packument = { + _id: manifest.name, + name: manifest.name, + description: manifest.description, + 'dist-tags': { + latest: '1.0.0', + }, + versions: { + '1.0.0': { + _id: `${manifest.name}@${manifest.version}`, + _nodeVersion: process.versions.node, + ...manifest, + dist: { + shasum, + integrity: integrity.sha512[0].toString(), + /* eslint-disable-next-line max-len */ + tarball: 'http://mock.reg/@npmcli/libnpmpublish-test/-/@npmcli/libnpmpublish-test-1.0.0.tgz', + }, + }, + }, + access: 'public', + _attachments: { + '@npmcli/libnpmpublish-test-1.0.0.tgz': { + content_type: 'application/octet-stream', + data: tarData.toString('base64'), + length: tarData.length, + }, + '@npmcli/libnpmpublish-test-1.0.0.sigstore': { + content_type: 'application/vnd.dev.sigstore.bundle+json;version=0.1', + data: /.*/, // Can't match against static value as signature is always different + length: 7927, + }, + }, + } + registry.nock.put(`/${spec.escapedName}`, body => { + return t.match(body, packument, 'posted packument matches expectations') + }).reply(201, {}) + const ret = await publish(manifest, tarData, { + ...opts, + provenanceFile: './test/fixtures/valid-bundle.json', + }) + t.ok(ret, 'publish succeeded') +}) + +t.test('user-supplied provenance - failure', async t => { + const { publish } = t.mock('..') + const manifest = { + name: '@npmcli/libnpmpublish-test', + version: '1.0.0', + description: 'test libnpmpublish package', + } + await t.rejects( + publish(manifest, Buffer.from(''), { + ...opts, + provenanceFile: './test/fixtures/bad-bundle.json', + }), + { message: /Invalid provenance provided/ } + ) +}) + +t.test('user-supplied provenance - bundle missing DSSE envelope', async t => { + const { publish } = t.mock('..') + const manifest = { + name: '@npmcli/libnpmpublish-test', + version: '1.0.0', + description: 'test libnpmpublish package', + } + await t.rejects( + publish(manifest, Buffer.from(''), { + ...opts, + provenanceFile: './test/fixtures/no-provenance-envelope-bundle.json', + }), + { message: /No dsseEnvelope with payload found/ } + ) +}) + +t.test('user-supplied provenance - bundle with invalid DSSE payload', async t => { + const { publish } = t.mock('..') + const manifest = { + name: '@npmcli/libnpmpublish-test', + version: '1.0.0', + description: 'test libnpmpublish package', + } + await t.rejects( + publish(manifest, Buffer.from(''), { + ...opts, + provenanceFile: './test/fixtures/bad-dsse-payload-bundle.json', + }), + { message: /Failed to parse payload/ } + ) +}) + +t.test('user-supplied provenance - provenance with missing subject', async t => { + const { publish } = t.mock('..') + const manifest = { + name: '@npmcli/libnpmpublish-test', + version: '1.0.0', + description: 'test libnpmpublish package', + } + await t.rejects( + publish(manifest, Buffer.from(''), { + ...opts, + provenanceFile: './test/fixtures/no-provenance-subject-bundle.json', + }), + { message: /No subject found/ } + ) +}) + +t.test('user-supplied provenance - provenance w/ multiple subjects', async t => { + const { publish } = t.mock('..') + const manifest = { + name: '@npmcli/libnpmpublish-test', + version: '1.0.0', + description: 'test libnpmpublish package', + } + await t.rejects( + publish(manifest, Buffer.from(''), { + ...opts, + provenanceFile: './test/fixtures/multi-subject-provenance-bundle.json', + }), + { message: /Found more than one subject/ } + ) +}) + +t.test('user-supplied provenance - provenance w/ mismatched subject name', async t => { + const { publish } = t.mock('..') + const manifest = { + name: '@npmcli/libnpmpublish-fail-test', + version: '1.0.0', + description: 'test libnpmpublish package', + } + await t.rejects( + publish(manifest, Buffer.from(''), { + ...opts, + provenanceFile: './test/fixtures/valid-bundle.json', + }), + { message: /Provenance subject/ } + ) +}) + +t.test('user-supplied provenance - provenance w/ mismatched package digest', async t => { + const { publish } = t.mock('..') + const manifest = { + name: '@npmcli/libnpmpublish-test', + version: '1.0.0', + description: 'test libnpmpublish package', + } + await t.rejects( + publish(manifest, Buffer.from(''), { + ...opts, + provenanceFile: './test/fixtures/digest-mismatch-provenance-bundle.json', + }), + { message: /Provenance subject digest does not match/ } + ) +}) + +t.test('publish existing package with provenance in gitlab', async t => { + // Environment variables + const jobName = 'job' + const repository = 'gitlab/foo' + const serverUrl = 'https://gitlab.com' + const sha = 'deadbeef' + const runnerID = 1 + + // Data for mocking the OIDC token request + const oidcClaims = { + iss: 'https://oauth2.sigstore.dev/auth', + email: 'foo@bar.com', + } + const idToken = `.${Buffer.from(JSON.stringify(oidcClaims)).toString('base64')}.` + + // Set-up GitLab environment variables + mockGlobals(t, { + 'process.env': { + CI: true, + GITLAB_CI: true, + GITHUB_ACTIONS: undefined, + SIGSTORE_ID_TOKEN: idToken, + CI_RUNNER_ID: runnerID, + CI_PROJECT_URL: `${serverUrl}/${repository}`, + CI_COMMIT_SHA: sha, + CI_JOB_NAME: jobName, + }, + }) + + const expectedSubject = { + name: 'pkg:npm/%40npmcli/libnpmpublish-test@1.0.0', + digest: { + sha512: integrity.sha512[0].hexDigest(), + }, + } + + const expectedConfigSource = { + uri: `git+${serverUrl}/${repository}`, + digest: { sha1: sha }, + entryPoint: jobName, + } + + const log = [] + const { publish } = t.mock('..', { + 'ci-info': t.mock('ci-info'), + 'proc-log': { notice: (...msg) => log.push(['notice', ...msg]) }, + }) + const registry = new MockRegistry({ + tap: t, + registry: opts.registry, + authorization: token, + }) + const manifest = { + name: '@npmcli/libnpmpublish-test', + version: '1.0.0', + description: 'test libnpmpublish package', + } + const spec = npa(manifest.name) + + // Data for mocking Fulcio certifcate request + const fulcioURL = 'https://mock.fulcio' + const leafCertificate = `-----BEGIN CERTIFICATE-----\nabc\n-----END CERTIFICATE-----\n` + const rootCertificate = `-----BEGIN CERTIFICATE-----\nxyz\n-----END CERTIFICATE-----\n` + const certificateResponse = { + signedCertificateEmbeddedSct: { + chain: { + certificates: [leafCertificate, rootCertificate], + }, + }, + } + + // Data for mocking Rekor upload + const rekorURL = 'https://mock.rekor' + const signature = 'ABC123' + const b64Cert = Buffer.from(leafCertificate).toString('base64') + const logIndex = 2513258 + const uuid = + '69e5a0c1663ee4452674a5c9d5050d866c2ee31e2faaf79913aea7cc27293cf6' + + const signatureBundle = { + kind: 'hashedrekord', + apiVersion: '0.0.1', + spec: { + signature: { + content: signature, + publicKey: { content: b64Cert }, + }, + }, + } + + const rekorEntry = { + [uuid]: { + body: Buffer.from(JSON.stringify(signatureBundle)).toString( + 'base64' + ), + integratedTime: 1654015743, + logID: + 'c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d', + logIndex, + verification: { + // eslint-disable-next-line max-len + signedEntryTimestamp: 'MEUCIQD6CD7ZNLUipFoxzmSL/L8Ewic4SRkXN77UjfJZ7d/wAAIgatokSuX9Rg0iWxAgSfHMtcsagtDCQalU5IvXdQ+yLEA=', + }, + }, + } + + const packument = { + _id: manifest.name, + name: manifest.name, + description: manifest.description, + 'dist-tags': { + latest: '1.0.0', + }, + versions: { + '1.0.0': { + _id: `${manifest.name}@${manifest.version}`, + _nodeVersion: process.versions.node, + ...manifest, + dist: { + shasum, + integrity: integrity.sha512[0].toString(), + // eslint-disable-next-line max-len + tarball: 'http://mock.reg/@npmcli/libnpmpublish-test/-/@npmcli/libnpmpublish-test-1.0.0.tgz', + }, + }, + }, + access: 'public', + _attachments: { + '@npmcli/libnpmpublish-test-1.0.0.tgz': { + content_type: 'application/octet-stream', + data: tarData.toString('base64'), + length: tarData.length, + }, + '@npmcli/libnpmpublish-test-1.0.0.sigstore': { + // Can't match data against static value as signature is always + // different. + // Can't match length because in github actions certain environment + // variables are present that are not present when running locally, + // changing the payload size. + content_type: 'application/vnd.dev.sigstore.bundle+json;version=0.1', + }, + }, + } + + const fulcioSrv = MockRegistry.tnock(t, fulcioURL) + fulcioSrv.matchHeader('Content-Type', 'application/json') + .post('/api/v2/signingCert', { + credentials: { oidcIdentityToken: idToken }, + publicKeyRequest: { + publicKey: { + algorithm: 'ECDSA', + content: /.+/i, + }, + proofOfPossession: /.+/i, + }, + }) + .reply(200, certificateResponse) + + const rekorSrv = MockRegistry.tnock(t, rekorURL) + rekorSrv + .matchHeader('Accept', 'application/json') + .matchHeader('Content-Type', 'application/json') + .post('/api/v1/log/entries') + .reply(201, rekorEntry) + + registry.nock.put(`/${spec.escapedName}`, body => { + const bundleAttachment = body._attachments['@npmcli/libnpmpublish-test-1.0.0.sigstore'] + const bundle = JSON.parse(bundleAttachment.data) + const provenance = JSON.parse(Buffer.from(bundle.dsseEnvelope.payload, 'base64').toString()) + + t.hasStrict(body, packument, 'posted packument matches expectations') + t.hasStrict(provenance.subject[0], + expectedSubject, + 'provenance subject matches expectations') + t.hasStrict(provenance.predicate.buildType, + 'https://github.com/npm/cli/gitlab/v0alpha1', + 'buildType matches expectations') + t.hasStrict(provenance.predicate.builder.id, + `${serverUrl}/${repository}/-/runners/${runnerID}`, + 'builder id matches expectations') + t.hasStrict(provenance.predicate.invocation.configSource, + expectedConfigSource, + 'configSource matches expectations') + return true + }).reply(201, {}) + + const ret = await publish(manifest, tarData, { + ...opts, + provenance: true, + fulcioURL: fulcioURL, + rekorURL: rekorURL, + }) + t.ok(ret, 'publish succeeded') + t.match(log, [ + ['notice', 'publish', + 'Signed provenance statement with source and build information from GitLab CI'], + ['notice', 'publish', + // eslint-disable-next-line max-len + `Provenance statement published to transparency log: https://search.sigstore.dev/?logIndex=${logIndex}`], + ]) +}) + +t.test('gitlab provenance, no token available', async t => { + mockGlobals(t, { + 'process.env': { + CI: true, + GITLAB_CI: true, + GITHUB_ACTIONS: undefined, + }, + }) + const manifest = { + name: '@npmcli/libnpmpublish-test', + version: '1.0.0', + description: 'test libnpmpublish package', + } + const { publish } = t.mock('..', { 'ci-info': t.mock('ci-info') }) + await t.rejects( + publish(manifest, Buffer.from(''), { + ...opts, + access: null, + provenance: true, + }), + { + message: /requires "SIGSTORE_ID_TOKEN"/, + code: 'EUSAGE', + } + ) +})