From feac87c7ed6113665bc144ee677017bc66138b70 Mon Sep 17 00:00:00 2001 From: reggi Date: Wed, 2 Oct 2024 13:24:08 -0400 Subject: [PATCH] deps: update @npmcli/map-workspaces@4.0.1 --- DEPENDENCIES.md | 14 +- node_modules/.gitignore | 20 + .../@npmcli/map-workspaces/lib/index.js | 34 +- .../node_modules/@npmcli/git/LICENSE | 15 + .../node_modules/@npmcli/git/lib/clone.js | 172 +++++ .../node_modules/@npmcli/git/lib/errors.js | 36 + .../node_modules/@npmcli/git/lib/find.js | 15 + .../node_modules/@npmcli/git/lib/index.js | 9 + .../node_modules/@npmcli/git/lib/is-clean.js | 6 + .../node_modules/@npmcli/git/lib/is.js | 4 + .../@npmcli/git/lib/lines-to-revs.js | 147 +++++ .../@npmcli/git/lib/make-error.js | 33 + .../node_modules/@npmcli/git/lib/opts.js | 57 ++ .../node_modules/@npmcli/git/lib/revs.js | 28 + .../node_modules/@npmcli/git/lib/spawn.js | 44 ++ .../node_modules/@npmcli/git/lib/utils.js | 3 + .../node_modules/@npmcli/git/lib/which.js | 18 + .../node_modules/@npmcli/git/package.json | 59 ++ .../@npmcli/name-from-folder/LICENSE | 15 + .../@npmcli/name-from-folder/lib/index.js | 7 + .../@npmcli/name-from-folder/package.json | 45 ++ .../node_modules/@npmcli/package-json/LICENSE | 18 + .../@npmcli/package-json/lib/index.js | 278 ++++++++ .../@npmcli/package-json/lib/normalize.js | 615 ++++++++++++++++++ .../@npmcli/package-json/lib/read-package.js | 39 ++ .../package-json/lib/update-dependencies.js | 75 +++ .../package-json/lib/update-scripts.js | 29 + .../package-json/lib/update-workspaces.js | 26 + .../@npmcli/package-json/package.json | 61 ++ .../@npmcli/promise-spawn/LICENSE | 15 + .../@npmcli/promise-spawn/lib/escape.js | 68 ++ .../@npmcli/promise-spawn/lib/index.js | 206 ++++++ .../@npmcli/promise-spawn/package.json | 51 ++ .../node_modules/hosted-git-info/LICENSE | 13 + .../hosted-git-info/lib/from-url.js | 122 ++++ .../node_modules/hosted-git-info/lib/hosts.js | 227 +++++++ .../node_modules/hosted-git-info/lib/index.js | 179 +++++ .../hosted-git-info/lib/parse-url.js | 78 +++ .../node_modules/hosted-git-info/package.json | 61 ++ .../map-workspaces/node_modules/ini/LICENSE | 15 + .../node_modules/ini/lib/ini.js | 280 ++++++++ .../node_modules/ini/package.json | 45 ++ .../map-workspaces/node_modules/isexe/LICENSE | 15 + .../node_modules/isexe/dist/cjs/index.js | 46 ++ .../node_modules/isexe/dist/cjs/options.js | 3 + .../node_modules/isexe/dist/cjs/package.json | 3 + .../node_modules/isexe/dist/cjs/posix.js | 67 ++ .../node_modules/isexe/dist/cjs/win32.js | 62 ++ .../node_modules/isexe/dist/mjs/index.js | 16 + .../node_modules/isexe/dist/mjs/options.js | 2 + .../node_modules/isexe/dist/mjs/package.json | 3 + .../node_modules/isexe/dist/mjs/posix.js | 62 ++ .../node_modules/isexe/dist/mjs/win32.js | 57 ++ .../node_modules/isexe/package.json | 96 +++ .../json-parse-even-better-errors/LICENSE.md | 25 + .../lib/index.js | 137 ++++ .../package.json | 50 ++ .../normalize-package-data/LICENSE | 15 + .../lib/extract_description.js | 24 + .../normalize-package-data/lib/fixer.js | 475 ++++++++++++++ .../lib/make_warning.js | 22 + .../normalize-package-data/lib/normalize.js | 48 ++ .../normalize-package-data/lib/safe_format.js | 11 + .../normalize-package-data/lib/typos.json | 25 + .../lib/warning_messages.json | 30 + .../normalize-package-data/package.json | 56 ++ .../node_modules/npm-install-checks/LICENSE | 27 + .../npm-install-checks/lib/current-env.js | 63 ++ .../npm-install-checks/lib/dev-engines.js | 145 +++++ .../npm-install-checks/lib/index.js | 90 +++ .../npm-install-checks/package.json | 52 ++ .../npm-normalize-package-bin/LICENSE | 15 + .../npm-normalize-package-bin/lib/index.js | 64 ++ .../npm-normalize-package-bin/package.json | 45 ++ .../node_modules/npm-package-arg/LICENSE | 15 + .../node_modules/npm-package-arg/lib/npa.js | 415 ++++++++++++ .../node_modules/npm-package-arg/package.json | 61 ++ .../node_modules/npm-pick-manifest/LICENSE.md | 16 + .../npm-pick-manifest/lib/index.js | 224 +++++++ .../npm-pick-manifest/package.json | 58 ++ .../node_modules/proc-log/LICENSE | 15 + .../node_modules/proc-log/lib/index.js | 153 +++++ .../node_modules/proc-log/package.json | 46 ++ .../validate-npm-package-name/LICENSE | 6 + .../validate-npm-package-name/lib/index.js | 105 +++ .../validate-npm-package-name/package.json | 61 ++ .../map-workspaces/node_modules/which/LICENSE | 15 + .../node_modules/which/bin/which.js | 52 ++ .../node_modules/which/lib/index.js | 111 ++++ .../node_modules/which/package.json | 52 ++ .../@npmcli/map-workspaces/package.json | 25 +- package-lock.json | 250 ++++++- package.json | 2 +- workspaces/arborist/package.json | 2 +- workspaces/config/package.json | 2 +- 95 files changed, 6764 insertions(+), 55 deletions(-) create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/LICENSE create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/clone.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/errors.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/find.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/index.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/is-clean.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/is.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/lines-to-revs.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/make-error.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/opts.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/revs.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/spawn.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/utils.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/which.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/package.json create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/@npmcli/name-from-folder/LICENSE create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/@npmcli/name-from-folder/lib/index.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/@npmcli/name-from-folder/package.json create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json/LICENSE create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json/lib/index.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json/lib/normalize.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json/lib/read-package.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json/lib/update-dependencies.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json/lib/update-scripts.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json/lib/update-workspaces.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json/package.json create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/@npmcli/promise-spawn/LICENSE create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/@npmcli/promise-spawn/lib/escape.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/@npmcli/promise-spawn/lib/index.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/@npmcli/promise-spawn/package.json create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/hosted-git-info/LICENSE create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/hosted-git-info/lib/from-url.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/hosted-git-info/lib/hosts.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/hosted-git-info/lib/index.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/hosted-git-info/lib/parse-url.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/hosted-git-info/package.json create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/ini/LICENSE create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/ini/lib/ini.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/ini/package.json create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/isexe/LICENSE create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/cjs/index.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/cjs/options.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/cjs/package.json create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/cjs/posix.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/cjs/win32.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/mjs/index.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/mjs/options.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/mjs/package.json create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/mjs/posix.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/mjs/win32.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/isexe/package.json create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/json-parse-even-better-errors/LICENSE.md create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/json-parse-even-better-errors/lib/index.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/json-parse-even-better-errors/package.json create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/LICENSE create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/lib/extract_description.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/lib/fixer.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/lib/make_warning.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/lib/normalize.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/lib/safe_format.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/lib/typos.json create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/lib/warning_messages.json create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/package.json create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/npm-install-checks/LICENSE create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/npm-install-checks/lib/current-env.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/npm-install-checks/lib/dev-engines.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/npm-install-checks/lib/index.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/npm-install-checks/package.json create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/npm-normalize-package-bin/LICENSE create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/npm-normalize-package-bin/lib/index.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/npm-normalize-package-bin/package.json create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/npm-package-arg/LICENSE create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/npm-package-arg/lib/npa.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/npm-package-arg/package.json create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/npm-pick-manifest/LICENSE.md create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/npm-pick-manifest/lib/index.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/npm-pick-manifest/package.json create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/proc-log/LICENSE create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/proc-log/lib/index.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/proc-log/package.json create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/validate-npm-package-name/LICENSE create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/validate-npm-package-name/lib/index.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/validate-npm-package-name/package.json create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/which/LICENSE create mode 100755 node_modules/@npmcli/map-workspaces/node_modules/which/bin/which.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/which/lib/index.js create mode 100644 node_modules/@npmcli/map-workspaces/node_modules/which/package.json diff --git a/DEPENDENCIES.md b/DEPENDENCIES.md index f612fd4a3834e..94a4dc466e3d0 100644 --- a/DEPENDENCIES.md +++ b/DEPENDENCIES.md @@ -207,7 +207,7 @@ graph LR; npmcli-installed-package-contents-->npm-bundled; npmcli-installed-package-contents-->npm-normalize-package-bin; npmcli-map-workspaces-->npmcli-name-from-folder["@npmcli/name-from-folder"]; - npmcli-map-workspaces-->read-package-json-fast; + npmcli-map-workspaces-->npmcli-package-json["@npmcli/package-json"]; npmcli-metavuln-calculator-->cacache; npmcli-metavuln-calculator-->json-parse-even-better-errors; npmcli-metavuln-calculator-->pacote; @@ -655,7 +655,7 @@ graph LR; npmcli-map-workspaces-->glob; npmcli-map-workspaces-->minimatch; npmcli-map-workspaces-->npmcli-name-from-folder["@npmcli/name-from-folder"]; - npmcli-map-workspaces-->read-package-json-fast; + npmcli-map-workspaces-->npmcli-package-json["@npmcli/package-json"]; npmcli-metavuln-calculator-->cacache; npmcli-metavuln-calculator-->json-parse-even-better-errors; npmcli-metavuln-calculator-->pacote; @@ -794,10 +794,10 @@ packages higher up the chain. - @npmcli/mock-registry, libnpmdiff, libnpmfund, libnpmpack - @npmcli/arborist - @npmcli/metavuln-calculator - - pacote, libnpmversion - - @npmcli/run-script, @npmcli/config, libnpmhook, libnpmorg, libnpmsearch, libnpmteam, init-package-json, npm-profile + - pacote, @npmcli/config, libnpmversion + - @npmcli/map-workspaces, @npmcli/run-script, libnpmhook, libnpmorg, libnpmsearch, libnpmteam, init-package-json, npm-profile - @npmcli/package-json, npm-registry-fetch - @npmcli/git, make-fetch-happen - - @npmcli/installed-package-contents, @npmcli/map-workspaces, cacache, npm-pick-manifest, promzard - - @npmcli/docs, @npmcli/fs, npm-bundled, read-package-json-fast, unique-filename, npm-install-checks, npm-package-arg, normalize-package-data, npm-packlist, bin-links, nopt, parse-conflict-json, @npmcli/mock-globals, 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, ini, hosted-git-info, proc-log, validate-npm-package-name, @npmcli/node-gyp, @npmcli/redact, @npmcli/agent, minipass-fetch, @npmcli/query, cmd-shim, read-cmd-shim, write-file-atomic, abbrev, proggy, minify-registry-metadata, mute-stream, npm-audit-report, npm-user-validate + - @npmcli/installed-package-contents, npm-pick-manifest, cacache, promzard + - @npmcli/docs, @npmcli/fs, npm-bundled, npm-install-checks, npm-package-arg, normalize-package-data, unique-filename, npm-packlist, bin-links, nopt, parse-conflict-json, read-package-json-fast, @npmcli/mock-globals, read + - @npmcli/eslint-config, @npmcli/template-oss, ignore-walk, semver, npm-normalize-package-bin, @npmcli/name-from-folder, @npmcli/promise-spawn, ini, hosted-git-info, proc-log, validate-npm-package-name, json-parse-even-better-errors, fs-minipass, ssri, unique-slug, @npmcli/node-gyp, @npmcli/redact, @npmcli/agent, minipass-fetch, @npmcli/query, cmd-shim, read-cmd-shim, write-file-atomic, abbrev, proggy, minify-registry-metadata, mute-stream, npm-audit-report, npm-user-validate diff --git a/node_modules/.gitignore b/node_modules/.gitignore index 255b995dde374..22bbea636b0ee 100644 --- a/node_modules/.gitignore +++ b/node_modules/.gitignore @@ -20,6 +20,26 @@ !/@npmcli/git !/@npmcli/installed-package-contents !/@npmcli/map-workspaces +!/@npmcli/map-workspaces/node_modules/ +/@npmcli/map-workspaces/node_modules/* +!/@npmcli/map-workspaces/node_modules/@npmcli/ +/@npmcli/map-workspaces/node_modules/@npmcli/* +!/@npmcli/map-workspaces/node_modules/@npmcli/git +!/@npmcli/map-workspaces/node_modules/@npmcli/name-from-folder +!/@npmcli/map-workspaces/node_modules/@npmcli/package-json +!/@npmcli/map-workspaces/node_modules/@npmcli/promise-spawn +!/@npmcli/map-workspaces/node_modules/hosted-git-info +!/@npmcli/map-workspaces/node_modules/ini +!/@npmcli/map-workspaces/node_modules/isexe +!/@npmcli/map-workspaces/node_modules/json-parse-even-better-errors +!/@npmcli/map-workspaces/node_modules/normalize-package-data +!/@npmcli/map-workspaces/node_modules/npm-install-checks +!/@npmcli/map-workspaces/node_modules/npm-normalize-package-bin +!/@npmcli/map-workspaces/node_modules/npm-package-arg +!/@npmcli/map-workspaces/node_modules/npm-pick-manifest +!/@npmcli/map-workspaces/node_modules/proc-log +!/@npmcli/map-workspaces/node_modules/validate-npm-package-name +!/@npmcli/map-workspaces/node_modules/which !/@npmcli/metavuln-calculator !/@npmcli/name-from-folder !/@npmcli/node-gyp diff --git a/node_modules/@npmcli/map-workspaces/lib/index.js b/node_modules/@npmcli/map-workspaces/lib/index.js index b20bf5de5d631..1b39d2e3f67e0 100644 --- a/node_modules/@npmcli/map-workspaces/lib/index.js +++ b/node_modules/@npmcli/map-workspaces/lib/index.js @@ -2,7 +2,7 @@ const path = require('path') const getName = require('@npmcli/name-from-folder') const { minimatch } = require('minimatch') -const rpj = require('read-package-json-fast') +const pkgJson = require('@npmcli/package-json') const { glob } = require('glob') function appendNegatedPatterns (allPatterns) { @@ -67,15 +67,7 @@ function getPatterns (workspaces) { } function getPackageName (pkg, pathname) { - const { name } = pkg - return name || getName(pathname) -} - -function pkgPathmame (opts) { - return (...args) => { - const cwd = opts.cwd ? opts.cwd : process.cwd() - return path.join.apply(null, [cwd, ...args]) - } + return pkg.name || getName(pathname) } // make sure glob pattern only matches folders @@ -101,16 +93,19 @@ async function mapWorkspaces (opts = {}) { code: 'EMAPWORKSPACESPKG', }) } + if (!opts.cwd) { + opts.cwd = process.cwd() + } const { workspaces = [] } = opts.pkg const { patterns, negatedPatterns } = getPatterns(workspaces) const results = new Map() - const seen = new Map() if (!patterns.length && !negatedPatterns.length) { return results } + const seen = new Map() const getGlobOpts = () => ({ ...opts, ignore: [ @@ -121,8 +116,6 @@ async function mapWorkspaces (opts = {}) { ], }) - const getPackagePathname = pkgPathmame(opts) - let matches = await glob(patterns.map((p) => getGlobPattern(p)), getGlobOpts()) // preserves glob@8 behavior matches = matches.sort((a, b) => a.localeCompare(b, 'en')) @@ -138,10 +131,8 @@ async function mapWorkspaces (opts = {}) { for (const match of orderedMatches) { let pkg - const packageJsonPathname = getPackagePathname(match, 'package.json') - try { - pkg = await rpj(packageJsonPathname) + pkg = await pkgJson.normalize(path.join(opts.cwd, match)) } catch (err) { if (err.code === 'ENOENT') { continue @@ -150,15 +141,14 @@ async function mapWorkspaces (opts = {}) { } } - const packagePathname = path.dirname(packageJsonPathname) - const name = getPackageName(pkg, packagePathname) + const name = getPackageName(pkg.content, pkg.path) let seenPackagePathnames = seen.get(name) if (!seenPackagePathnames) { seenPackagePathnames = new Set() seen.set(name, seenPackagePathnames) } - seenPackagePathnames.add(packagePathname) + seenPackagePathnames.add(pkg.path) } const errorMessageArray = ['must not have multiple workspaces with the same name'] @@ -200,6 +190,9 @@ mapWorkspaces.virtual = function (opts = {}) { code: 'EMAPWORKSPACESLOCKFILE', }) } + if (!opts.cwd) { + opts.cwd = process.cwd() + } const { packages = {} } = opts.lockfile const { workspaces = [] } = packages[''] || {} @@ -218,10 +211,9 @@ mapWorkspaces.virtual = function (opts = {}) { } } - const getPackagePathname = pkgPathmame(opts) for (const pattern of patterns) { for (const packageKey of minimatch.match(packageKeys, pattern)) { - const packagePathname = getPackagePathname(packageKey) + const packagePathname = path.join(opts.cwd, packageKey) const name = getPackageName(packages[packageKey], packagePathname) results.set(packagePathname, name) } diff --git a/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/LICENSE b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/LICENSE new file mode 100644 index 0000000000000..8f90f96f4c6c5 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/LICENSE @@ -0,0 +1,15 @@ +The 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 NPM DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE 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/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/clone.js b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/clone.js new file mode 100644 index 0000000000000..e25a4d1426821 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/clone.js @@ -0,0 +1,172 @@ +// The goal here is to minimize both git workload and +// the number of refs we download over the network. +// +// Every method ends up with the checked out working dir +// at the specified ref, and resolves with the git sha. + +// Only certain whitelisted hosts get shallow cloning. +// Many hosts (including GHE) don't always support it. +// A failed shallow fetch takes a LOT longer than a full +// fetch in most cases, so we skip it entirely. +// Set opts.gitShallow = true/false to force this behavior +// one way or the other. +const shallowHosts = new Set([ + 'github.com', + 'gist.github.com', + 'gitlab.com', + 'bitbucket.com', + 'bitbucket.org', +]) +// we have to use url.parse until we add the same shim that hosted-git-info has +// to handle scp:// urls +const { parse } = require('url') // eslint-disable-line node/no-deprecated-api +const path = require('path') + +const getRevs = require('./revs.js') +const spawn = require('./spawn.js') +const { isWindows } = require('./utils.js') + +const pickManifest = require('npm-pick-manifest') +const fs = require('fs/promises') + +module.exports = (repo, ref = 'HEAD', target = null, opts = {}) => + getRevs(repo, opts).then(revs => clone( + repo, + revs, + ref, + resolveRef(revs, ref, opts), + target || defaultTarget(repo, opts.cwd), + opts + )) + +const maybeShallow = (repo, opts) => { + if (opts.gitShallow === false || opts.gitShallow) { + return opts.gitShallow + } + return shallowHosts.has(parse(repo).host) +} + +const defaultTarget = (repo, /* istanbul ignore next */ cwd = process.cwd()) => + path.resolve(cwd, path.basename(repo.replace(/[/\\]?\.git$/, ''))) + +const clone = (repo, revs, ref, revDoc, target, opts) => { + if (!revDoc) { + return unresolved(repo, ref, target, opts) + } + if (revDoc.sha === revs.refs.HEAD.sha) { + return plain(repo, revDoc, target, opts) + } + if (revDoc.type === 'tag' || revDoc.type === 'branch') { + return branch(repo, revDoc, target, opts) + } + return other(repo, revDoc, target, opts) +} + +const resolveRef = (revs, ref, opts) => { + const { spec = {} } = opts + ref = spec.gitCommittish || ref + /* istanbul ignore next - will fail anyway, can't pull */ + if (!revs) { + return null + } + if (spec.gitRange) { + return pickManifest(revs, spec.gitRange, opts) + } + if (!ref) { + return revs.refs.HEAD + } + if (revs.refs[ref]) { + return revs.refs[ref] + } + if (revs.shas[ref]) { + return revs.refs[revs.shas[ref][0]] + } + return null +} + +// pull request or some other kind of advertised ref +const other = (repo, revDoc, target, opts) => { + const shallow = maybeShallow(repo, opts) + + const fetchOrigin = ['fetch', 'origin', revDoc.rawRef] + .concat(shallow ? ['--depth=1'] : []) + + const git = (args) => spawn(args, { ...opts, cwd: target }) + return fs.mkdir(target, { recursive: true }) + .then(() => git(['init'])) + .then(() => isWindows(opts) + ? git(['config', '--local', '--add', 'core.longpaths', 'true']) + : null) + .then(() => git(['remote', 'add', 'origin', repo])) + .then(() => git(fetchOrigin)) + .then(() => git(['checkout', revDoc.sha])) + .then(() => updateSubmodules(target, opts)) + .then(() => revDoc.sha) +} + +// tag or branches. use -b +const branch = (repo, revDoc, target, opts) => { + const args = [ + 'clone', + '-b', + revDoc.ref, + repo, + target, + '--recurse-submodules', + ] + if (maybeShallow(repo, opts)) { + args.push('--depth=1') + } + if (isWindows(opts)) { + args.push('--config', 'core.longpaths=true') + } + return spawn(args, opts).then(() => revDoc.sha) +} + +// just the head. clone it +const plain = (repo, revDoc, target, opts) => { + const args = [ + 'clone', + repo, + target, + '--recurse-submodules', + ] + if (maybeShallow(repo, opts)) { + args.push('--depth=1') + } + if (isWindows(opts)) { + args.push('--config', 'core.longpaths=true') + } + return spawn(args, opts).then(() => revDoc.sha) +} + +const updateSubmodules = async (target, opts) => { + const hasSubmodules = await fs.stat(`${target}/.gitmodules`) + .then(() => true) + .catch(() => false) + if (!hasSubmodules) { + return null + } + return spawn([ + 'submodule', + 'update', + '-q', + '--init', + '--recursive', + ], { ...opts, cwd: target }) +} + +const unresolved = (repo, ref, target, opts) => { + // can't do this one shallowly, because the ref isn't advertised + // but we can avoid checking out the working dir twice, at least + const lp = isWindows(opts) ? ['--config', 'core.longpaths=true'] : [] + const cloneArgs = ['clone', '--mirror', '-q', repo, target + '/.git'] + const git = (args) => spawn(args, { ...opts, cwd: target }) + return fs.mkdir(target, { recursive: true }) + .then(() => git(cloneArgs.concat(lp))) + .then(() => git(['init'])) + .then(() => git(['checkout', ref])) + .then(() => updateSubmodules(target, opts)) + .then(() => git(['rev-parse', '--revs-only', 'HEAD'])) + .then(({ stdout }) => stdout.trim()) +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/errors.js b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/errors.js new file mode 100644 index 0000000000000..3ceaa45811669 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/errors.js @@ -0,0 +1,36 @@ + +const maxRetry = 3 + +class GitError extends Error { + shouldRetry () { + return false + } +} + +class GitConnectionError extends GitError { + constructor () { + super('A git connection error occurred') + } + + shouldRetry (number) { + return number < maxRetry + } +} + +class GitPathspecError extends GitError { + constructor () { + super('The git reference could not be found') + } +} + +class GitUnknownError extends GitError { + constructor () { + super('An unknown git error occurred') + } +} + +module.exports = { + GitConnectionError, + GitPathspecError, + GitUnknownError, +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/find.js b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/find.js new file mode 100644 index 0000000000000..34bd310b88e5d --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/find.js @@ -0,0 +1,15 @@ +const is = require('./is.js') +const { dirname } = require('path') + +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 + } +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/index.js b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/index.js new file mode 100644 index 0000000000000..10a65f782e6da --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/index.js @@ -0,0 +1,9 @@ +module.exports = { + clone: require('./clone.js'), + revs: require('./revs.js'), + spawn: require('./spawn.js'), + is: require('./is.js'), + find: require('./find.js'), + isClean: require('./is-clean.js'), + errors: require('./errors.js'), +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/is-clean.js b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/is-clean.js new file mode 100644 index 0000000000000..182373be94193 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/is-clean.js @@ -0,0 +1,6 @@ +const spawn = require('./spawn.js') + +module.exports = (opts = {}) => + spawn(['status', '--porcelain=v1', '-uno'], opts) + .then(res => !res.stdout.trim().split(/\r?\n+/) + .map(l => l.trim()).filter(l => l).length) diff --git a/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/is.js b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/is.js new file mode 100644 index 0000000000000..f5a0e8754f10d --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/is.js @@ -0,0 +1,4 @@ +// not an airtight indicator, but a good gut-check to even bother trying +const { stat } = require('fs/promises') +module.exports = ({ cwd = process.cwd() } = {}) => + stat(cwd + '/.git').then(() => true, () => false) diff --git a/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/lines-to-revs.js b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/lines-to-revs.js new file mode 100644 index 0000000000000..6bd7e7a4c1531 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/lines-to-revs.js @@ -0,0 +1,147 @@ +// turn an array of lines from `git ls-remote` into a thing +// vaguely resembling a packument, where docs are a resolved ref + +const semver = require('semver') + +module.exports = lines => finish(lines.reduce(linesToRevsReducer, { + versions: {}, + 'dist-tags': {}, + refs: {}, + shas: {}, +})) + +const finish = revs => distTags(shaList(peelTags(revs))) + +// We can check out shallow clones on specific SHAs if we have a ref +const shaList = revs => { + Object.keys(revs.refs).forEach(ref => { + const doc = revs.refs[ref] + if (!revs.shas[doc.sha]) { + revs.shas[doc.sha] = [ref] + } else { + revs.shas[doc.sha].push(ref) + } + }) + return revs +} + +// Replace any tags with their ^{} counterparts, if those exist +const peelTags = revs => { + Object.keys(revs.refs).filter(ref => ref.endsWith('^{}')).forEach(ref => { + const peeled = revs.refs[ref] + const unpeeled = revs.refs[ref.replace(/\^\{\}$/, '')] + if (unpeeled) { + unpeeled.sha = peeled.sha + delete revs.refs[ref] + } + }) + return revs +} + +const distTags = revs => { + // not entirely sure what situations would result in an + // ichabod repo, but best to be careful in Sleepy Hollow anyway + const HEAD = revs.refs.HEAD || /* istanbul ignore next */ {} + const versions = Object.keys(revs.versions) + versions.forEach(v => { + // simulate a dist-tags with latest pointing at the + // 'latest' branch if one exists and is a version, + // or HEAD if not. + const ver = revs.versions[v] + if (revs.refs.latest && ver.sha === revs.refs.latest.sha) { + revs['dist-tags'].latest = v + } else if (ver.sha === HEAD.sha) { + revs['dist-tags'].HEAD = v + if (!revs.refs.latest) { + revs['dist-tags'].latest = v + } + } + }) + return revs +} + +const refType = ref => { + if (ref.startsWith('refs/tags/')) { + return 'tag' + } + if (ref.startsWith('refs/heads/')) { + return 'branch' + } + if (ref.startsWith('refs/pull/')) { + return 'pull' + } + if (ref === 'HEAD') { + return 'head' + } + // Could be anything, ignore for now + /* istanbul ignore next */ + return 'other' +} + +// return the doc, or null if we should ignore it. +const lineToRevDoc = line => { + const split = line.trim().split(/\s+/, 2) + if (split.length < 2) { + return null + } + + const sha = split[0].trim() + const rawRef = split[1].trim() + const type = refType(rawRef) + + if (type === 'tag') { + // refs/tags/foo^{} is the 'peeled tag', ie the commit + // that is tagged by refs/tags/foo they resolve to the same + // content, just different objects in git's data structure. + // But, we care about the thing the tag POINTS to, not the tag + // object itself, so we only look at the peeled tag refs, and + // ignore the pointer. + // For now, though, we have to save both, because some tags + // don't have peels, if they were not annotated. + const ref = rawRef.slice('refs/tags/'.length) + return { sha, ref, rawRef, type } + } + + if (type === 'branch') { + const ref = rawRef.slice('refs/heads/'.length) + return { sha, ref, rawRef, type } + } + + if (type === 'pull') { + // NB: merged pull requests installable with #pull/123/merge + // for the merged pr, or #pull/123 for the PR head + const ref = rawRef.slice('refs/'.length).replace(/\/head$/, '') + return { sha, ref, rawRef, type } + } + + if (type === 'head') { + const ref = 'HEAD' + return { sha, ref, rawRef, type } + } + + // at this point, all we can do is leave the ref un-munged + return { sha, ref: rawRef, rawRef, type } +} + +const linesToRevsReducer = (revs, line) => { + const doc = lineToRevDoc(line) + + if (!doc) { + return revs + } + + revs.refs[doc.ref] = doc + revs.refs[doc.rawRef] = doc + + if (doc.type === 'tag') { + // try to pull a semver value out of tags like `release-v1.2.3` + // which is a pretty common pattern. + const match = !doc.ref.endsWith('^{}') && + doc.ref.match(/v?(\d+\.\d+\.\d+(?:[-+].+)?)$/) + if (match && semver.valid(match[1], true)) { + revs.versions[semver.clean(match[1], true)] = doc + } + } + + return revs +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/make-error.js b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/make-error.js new file mode 100644 index 0000000000000..7540ec7c8b9f7 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/make-error.js @@ -0,0 +1,33 @@ +const { + GitConnectionError, + GitPathspecError, + GitUnknownError, +} = require('./errors.js') + +const connectionErrorRe = new RegExp([ + 'remote error: Internal Server Error', + 'The remote end hung up unexpectedly', + 'Connection timed out', + 'Operation timed out', + 'Failed to connect to .* Timed out', + 'Connection reset by peer', + 'SSL_ERROR_SYSCALL', + 'The requested URL returned error: 503', +].join('|')) + +const missingPathspecRe = /pathspec .* did not match any file\(s\) known to git/ + +function makeError (er) { + const message = er.stderr + let gitEr + if (connectionErrorRe.test(message)) { + gitEr = new GitConnectionError(message) + } else if (missingPathspecRe.test(message)) { + gitEr = new GitPathspecError(message) + } else { + gitEr = new GitUnknownError(message) + } + return Object.assign(gitEr, er) +} + +module.exports = makeError diff --git a/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/opts.js b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/opts.js new file mode 100644 index 0000000000000..1e80e9efe4989 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/opts.js @@ -0,0 +1,57 @@ +const fs = require('node:fs') +const os = require('node:os') +const path = require('node:path') +const ini = require('ini') + +const gitConfigPath = path.join(os.homedir(), '.gitconfig') + +let cachedConfig = null + +// Function to load and cache the git config +const loadGitConfig = () => { + if (cachedConfig === null) { + try { + cachedConfig = {} + if (fs.existsSync(gitConfigPath)) { + const configContent = fs.readFileSync(gitConfigPath, 'utf-8') + cachedConfig = ini.parse(configContent) + } + } catch (error) { + cachedConfig = {} + } + } + return cachedConfig +} + +const checkGitConfigs = () => { + const config = loadGitConfig() + return { + sshCommandSetInConfig: config?.core?.sshCommand !== undefined, + askPassSetInConfig: config?.core?.askpass !== undefined, + } +} + +const sshCommandSetInEnv = process.env.GIT_SSH_COMMAND !== undefined +const askPassSetInEnv = process.env.GIT_ASKPASS !== undefined +const { sshCommandSetInConfig, askPassSetInConfig } = checkGitConfigs() + +// Values we want to set if they're not already defined by the end user +// This defaults to accepting new ssh host key fingerprints +const finalGitEnv = { + ...(askPassSetInEnv || askPassSetInConfig ? {} : { + GIT_ASKPASS: 'echo', + }), + ...(sshCommandSetInEnv || sshCommandSetInConfig ? {} : { + GIT_SSH_COMMAND: 'ssh -oStrictHostKeyChecking=accept-new', + }), +} + +module.exports = (opts = {}) => ({ + stdioString: true, + ...opts, + shell: false, + env: opts.env || { ...finalGitEnv, ...process.env }, +}) + +// Export the loadGitConfig function for testing +module.exports.loadGitConfig = loadGitConfig diff --git a/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/revs.js b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/revs.js new file mode 100644 index 0000000000000..ca14837de1b87 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/revs.js @@ -0,0 +1,28 @@ +const pinflight = require('promise-inflight') +const spawn = require('./spawn.js') +const { LRUCache } = require('lru-cache') + +const revsCache = new LRUCache({ + max: 100, + ttl: 5 * 60 * 1000, +}) + +const linesToRevs = require('./lines-to-revs.js') + +module.exports = async (repo, opts = {}) => { + if (!opts.noGitRevCache) { + const cached = revsCache.get(repo) + if (cached) { + return cached + } + } + + return pinflight(`ls-remote:${repo}`, () => + spawn(['ls-remote', repo], opts) + .then(({ stdout }) => linesToRevs(stdout.trim().split('\n'))) + .then(revs => { + revsCache.set(repo, revs) + return revs + }) + ) +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/spawn.js b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/spawn.js new file mode 100644 index 0000000000000..03c1cbde21547 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/spawn.js @@ -0,0 +1,44 @@ +const spawn = require('@npmcli/promise-spawn') +const promiseRetry = require('promise-retry') +const { log } = require('proc-log') +const makeError = require('./make-error.js') +const makeOpts = require('./opts.js') + +module.exports = (gitArgs, opts = {}) => { + const whichGit = require('./which.js') + const gitPath = whichGit(opts) + + if (gitPath instanceof Error) { + return Promise.reject(gitPath) + } + + // undocumented option, mostly only here for tests + const args = opts.allowReplace || gitArgs[0] === '--no-replace-objects' + ? gitArgs + : ['--no-replace-objects', ...gitArgs] + + let retryOpts = opts.retry + if (retryOpts === null || retryOpts === undefined) { + retryOpts = { + retries: opts.fetchRetries || 2, + factor: opts.fetchRetryFactor || 10, + maxTimeout: opts.fetchRetryMaxtimeout || 60000, + minTimeout: opts.fetchRetryMintimeout || 1000, + } + } + return promiseRetry((retryFn, number) => { + if (number !== 1) { + log.silly('git', `Retrying git command: ${ + args.join(' ')} attempt # ${number}`) + } + + return spawn(gitPath, args, makeOpts(opts)) + .catch(er => { + const gitError = makeError(er) + if (!gitError.shouldRetry(number)) { + throw gitError + } + retryFn(gitError) + }) + }, retryOpts) +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/utils.js b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/utils.js new file mode 100644 index 0000000000000..fcd9578a19597 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/utils.js @@ -0,0 +1,3 @@ +const isWindows = opts => (opts.fakePlatform || process.platform) === 'win32' + +exports.isWindows = isWindows diff --git a/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/which.js b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/which.js new file mode 100644 index 0000000000000..dc2a1ad212166 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/lib/which.js @@ -0,0 +1,18 @@ +const which = require('which') + +let gitPath +try { + gitPath = which.sync('git') +} catch { + // ignore errors +} + +module.exports = (opts = {}) => { + if (opts.git) { + return opts.git + } + if (!gitPath || opts.git === false) { + return Object.assign(new Error('No git binary found in $PATH'), { code: 'ENOGIT' }) + } + return gitPath +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/package.json b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/package.json new file mode 100644 index 0000000000000..2bc6730ba2151 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git/package.json @@ -0,0 +1,59 @@ +{ + "name": "@npmcli/git", + "version": "6.0.1", + "main": "lib/index.js", + "files": [ + "bin/", + "lib/" + ], + "description": "a util for spawning git from npm CLI contexts", + "repository": { + "type": "git", + "url": "git+https://github.com/npm/git.git" + }, + "author": "GitHub Inc.", + "license": "ISC", + "scripts": { + "lint": "npm run eslint", + "snap": "tap", + "test": "tap", + "posttest": "npm run lint", + "postlint": "template-oss-check", + "lintfix": "npm run eslint -- --fix", + "template-oss-apply": "template-oss-apply --force", + "eslint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"" + }, + "tap": { + "timeout": 600, + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] + }, + "devDependencies": { + "@npmcli/eslint-config": "^5.0.0", + "@npmcli/template-oss": "4.23.3", + "npm-package-arg": "^11.0.0", + "slash": "^3.0.0", + "tap": "^16.0.1" + }, + "dependencies": { + "@npmcli/promise-spawn": "^8.0.0", + "ini": "^5.0.0", + "lru-cache": "^10.0.1", + "npm-pick-manifest": "^10.0.0", + "proc-log": "^5.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^5.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + }, + "templateOSS": { + "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", + "version": "4.23.3", + "publish": true + } +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/name-from-folder/LICENSE b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/name-from-folder/LICENSE new file mode 100644 index 0000000000000..d24a9fca761c8 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/name-from-folder/LICENSE @@ -0,0 +1,15 @@ +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 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/@npmcli/map-workspaces/node_modules/@npmcli/name-from-folder/lib/index.js b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/name-from-folder/lib/index.js new file mode 100644 index 0000000000000..afb1dbb76297f --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/name-from-folder/lib/index.js @@ -0,0 +1,7 @@ +const { basename, dirname } = require('path') + +const getName = (parent, base) => + parent.charAt(0) === '@' ? `${parent}/${base}` : base + +module.exports = dir => dir ? getName(basename(dirname(dir)), basename(dir)) + : false diff --git a/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/name-from-folder/package.json b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/name-from-folder/package.json new file mode 100644 index 0000000000000..323edd81d22fb --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/name-from-folder/package.json @@ -0,0 +1,45 @@ +{ + "name": "@npmcli/name-from-folder", + "version": "3.0.0", + "files": [ + "bin/", + "lib/" + ], + "main": "lib/index.js", + "description": "Get the package name from a folder path", + "repository": { + "type": "git", + "url": "git+https://github.com/npm/name-from-folder.git" + }, + "author": "GitHub Inc.", + "license": "ISC", + "scripts": { + "test": "tap", + "snap": "tap", + "lint": "npm run eslint", + "postlint": "template-oss-check", + "template-oss-apply": "template-oss-apply --force", + "lintfix": "npm run eslint -- --fix", + "posttest": "npm run lint", + "eslint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"" + }, + "devDependencies": { + "@npmcli/eslint-config": "^5.0.0", + "@npmcli/template-oss": "4.23.3", + "tap": "^16.3.2" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + }, + "templateOSS": { + "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", + "version": "4.23.3", + "publish": true + }, + "tap": { + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] + } +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json/LICENSE b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json/LICENSE new file mode 100644 index 0000000000000..6a1f3708f6d70 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json/LICENSE @@ -0,0 +1,18 @@ +ISC License + +Copyright GitHub 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/@npmcli/map-workspaces/node_modules/@npmcli/package-json/lib/index.js b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json/lib/index.js new file mode 100644 index 0000000000000..f165ee23b75ab --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json/lib/index.js @@ -0,0 +1,278 @@ +const { readFile, writeFile } = require('node:fs/promises') +const { resolve } = require('node:path') +const parseJSON = require('json-parse-even-better-errors') + +const updateDeps = require('./update-dependencies.js') +const updateScripts = require('./update-scripts.js') +const updateWorkspaces = require('./update-workspaces.js') +const normalize = require('./normalize.js') +const { read, parse } = require('./read-package.js') + +// a list of handy specialized helper functions that take +// care of special cases that are handled by the npm cli +const knownSteps = new Set([ + updateDeps, + updateScripts, + updateWorkspaces, +]) + +// list of all keys that are handled by "knownSteps" helpers +const knownKeys = new Set([ + ...updateDeps.knownKeys, + 'scripts', + 'workspaces', +]) + +class PackageJson { + static normalizeSteps = Object.freeze([ + '_id', + '_attributes', + 'bundledDependencies', + 'bundleDependencies', + 'optionalDedupe', + 'scripts', + 'funding', + 'bin', + ]) + + // npm pkg fix + static fixSteps = Object.freeze([ + 'binRefs', + 'bundleDependencies', + 'bundleDependenciesFalse', + 'fixNameField', + 'fixVersionField', + 'fixRepositoryField', + 'fixDependencies', + 'devDependencies', + 'scriptpath', + ]) + + static prepareSteps = Object.freeze([ + '_id', + '_attributes', + 'bundledDependencies', + 'bundleDependencies', + 'bundleDependenciesDeleteFalse', + 'gypfile', + 'serverjs', + 'scriptpath', + 'authors', + 'readme', + 'mans', + 'binDir', + 'gitHead', + 'fillTypes', + 'normalizeData', + 'binRefs', + ]) + + // create a new empty package.json, so we can save at the given path even + // though we didn't start from a parsed file + static async create (path, opts = {}) { + const p = new PackageJson() + await p.create(path) + if (opts.data) { + return p.update(opts.data) + } + return p + } + + // Loads a package.json at given path and JSON parses + static async load (path, opts = {}) { + const p = new PackageJson() + // Avoid try/catch if we aren't going to create + if (!opts.create) { + return p.load(path) + } + + try { + return await p.load(path) + } catch (err) { + if (!err.message.startsWith('Could not read package.json')) { + throw err + } + return await p.create(path) + } + } + + // npm pkg fix + static async fix (path, opts) { + const p = new PackageJson() + await p.load(path, true) + return p.fix(opts) + } + + // read-package-json compatible behavior + static async prepare (path, opts) { + const p = new PackageJson() + await p.load(path, true) + return p.prepare(opts) + } + + // read-package-json-fast compatible behavior + static async normalize (path, opts) { + const p = new PackageJson() + await p.load(path) + return p.normalize(opts) + } + + #path + #manifest + #readFileContent = '' + #canSave = true + + // Load content from given path + async load (path, parseIndex) { + this.#path = path + let parseErr + try { + this.#readFileContent = await read(this.filename) + } catch (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.fromComment(indexFileContent) + } catch (err) { + throw parseErr + } + // This wasn't a package.json so prevent saving + this.#canSave = false + return this + } + + return this.fromJSON(this.#readFileContent) + } + + // Load data from a JSON string/buffer + fromJSON (data) { + this.#manifest = parse(data) + return this + } + + fromContent (data) { + this.#manifest = data + this.#canSave = false + return this + } + + // Load data from a comment + // /**package { "name": "foo", "version": "1.2.3", ... } **/ + 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, '') + + this.#manifest = parseJSON(data) + return this + } + + get content () { + return this.#manifest + } + + get path () { + return this.#path + } + + get filename () { + if (this.path) { + return resolve(this.path, 'package.json') + } + return undefined + } + + create (path) { + this.#path = path + this.#manifest = {} + return this + } + + // This should be the ONLY way to set content in the manifest + update (content) { + if (!this.content) { + throw new Error('Can not update without content. Please `load` or `create`') + } + + for (const step of knownSteps) { + this.#manifest = step({ content, originalContent: this.content }) + } + + // unknown properties will just be overwitten + for (const [key, value] of Object.entries(content)) { + if (!knownKeys.has(key)) { + this.content[key] = value + } + } + + return this + } + + async save () { + if (!this.#canSave) { + throw new Error('No package.json to save to') + } + const { + [Symbol.for('indent')]: indent, + [Symbol.for('newline')]: newline, + } = this.content + + const format = indent === undefined ? ' ' : indent + const eol = newline === undefined ? '\n' : newline + const fileContent = `${ + JSON.stringify(this.content, null, format) + }\n` + .replace(/\n/g, eol) + + if (fileContent.trim() !== this.#readFileContent.trim()) { + return await writeFile(this.filename, fileContent) + } + } + + async normalize (opts = {}) { + if (!opts.steps) { + opts.steps = this.constructor.normalizeSteps + } + await normalize(this, opts) + return this + } + + async prepare (opts = {}) { + if (!opts.steps) { + opts.steps = this.constructor.prepareSteps + } + await normalize(this, opts) + return this + } + + async fix (opts = {}) { + // This one is not overridable + opts.steps = this.constructor.fixSteps + await normalize(this, opts) + return this + } +} + +module.exports = PackageJson diff --git a/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json/lib/normalize.js b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json/lib/normalize.js new file mode 100644 index 0000000000000..3adec0143f445 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json/lib/normalize.js @@ -0,0 +1,615 @@ +const valid = require('semver/functions/valid') +const clean = require('semver/functions/clean') +const fs = require('node:fs/promises') +const path = require('node:path') +const { log } = require('proc-log') + +/** + * @type {import('hosted-git-info')} + */ +let _hostedGitInfo +function lazyHostedGitInfo () { + if (!_hostedGitInfo) { + _hostedGitInfo = require('hosted-git-info') + } + return _hostedGitInfo +} + +/** + * @type {import('glob').glob} + */ +let _glob +function lazyLoadGlob () { + if (!_glob) { + _glob = require('glob').glob + } + return _glob +} + +// used to be npm-normalize-package-bin +function normalizePackageBin (pkg, changes) { + if (pkg.bin) { + if (typeof pkg.bin === 'string' && pkg.name) { + changes?.push('"bin" was converted to an object') + pkg.bin = { [pkg.name]: pkg.bin } + } else if (Array.isArray(pkg.bin)) { + changes?.push('"bin" was converted to an object') + pkg.bin = pkg.bin.reduce((acc, k) => { + acc[path.basename(k)] = k + return acc + }, {}) + } + if (typeof pkg.bin === 'object') { + for (const binKey in pkg.bin) { + if (typeof pkg.bin[binKey] !== 'string') { + delete pkg.bin[binKey] + changes?.push(`removed invalid "bin[${binKey}]"`) + continue + } + const base = path.basename(secureAndUnixifyPath(binKey)) + if (!base) { + delete pkg.bin[binKey] + changes?.push(`removed invalid "bin[${binKey}]"`) + continue + } + + const binTarget = secureAndUnixifyPath(pkg.bin[binKey]) + + if (!binTarget) { + delete pkg.bin[binKey] + changes?.push(`removed invalid "bin[${binKey}]"`) + continue + } + + if (base !== binKey) { + delete pkg.bin[binKey] + changes?.push(`"bin[${binKey}]" was renamed to "bin[${base}]"`) + } + if (binTarget !== pkg.bin[binKey]) { + changes?.push(`"bin[${base}]" script name was cleaned`) + } + pkg.bin[base] = binTarget + } + + if (Object.keys(pkg.bin).length === 0) { + changes?.push('empty "bin" was removed') + delete pkg.bin + } + + return pkg + } + } + delete pkg.bin +} + +function normalizePackageMan (pkg, changes) { + if (pkg.man) { + const mans = [] + for (const man of (Array.isArray(pkg.man) ? pkg.man : [pkg.man])) { + if (typeof man !== 'string') { + changes?.push(`removed invalid "man [${man}]"`) + } else { + mans.push(secureAndUnixifyPath(man)) + } + } + + if (!mans.length) { + changes?.push('empty "man" was removed') + } else { + pkg.man = mans + return pkg + } + } + delete pkg.man +} + +function isCorrectlyEncodedName (spec) { + return !spec.match(/[/@\s+%:]/) && + spec === encodeURIComponent(spec) +} + +function isValidScopedPackageName (spec) { + if (spec.charAt(0) !== '@') { + return false + } + + const rest = spec.slice(1).split('/') + if (rest.length !== 2) { + return false + } + + return rest[0] && rest[1] && + rest[0] === encodeURIComponent(rest[0]) && + rest[1] === encodeURIComponent(rest[1]) +} + +function unixifyPath (ref) { + return ref.replace(/\\|:/g, '/') +} + +function secureAndUnixifyPath (ref) { + const secured = unixifyPath(path.join('.', path.join('/', unixifyPath(ref)))) + return secured.startsWith('./') ? '' : secured +} + +// We don't want the `changes` array in here by default because this is a hot +// path for parsing packuments during install. So the calling method passes it +// in if it wants to track changes. +const normalize = async (pkg, { strict, steps, root, changes, allowLegacyCase }) => { + if (!pkg.content) { + throw new Error('Can not normalize without content') + } + const data = pkg.content + const scripts = data.scripts || {} + const pkgId = `${data.name ?? ''}@${data.version ?? ''}` + + // name and version are load bearing so we have to clean them up first + if (steps.includes('fixNameField') || steps.includes('normalizeData')) { + if (!data.name && !strict) { + changes?.push('Missing "name" field was set to an empty string') + data.name = '' + } else { + if (typeof data.name !== 'string') { + throw new Error('name field must be a string.') + } + if (!strict) { + const name = data.name.trim() + if (data.name !== name) { + changes?.push(`Whitespace was trimmed from "name"`) + data.name = name + } + } + + if (data.name.startsWith('.') || + !(isValidScopedPackageName(data.name) || isCorrectlyEncodedName(data.name)) || + (strict && (!allowLegacyCase) && data.name !== data.name.toLowerCase()) || + data.name.toLowerCase() === 'node_modules' || + data.name.toLowerCase() === 'favicon.ico') { + throw new Error('Invalid name: ' + JSON.stringify(data.name)) + } + } + } + + if (steps.includes('fixVersionField') || steps.includes('normalizeData')) { + // allow "loose" semver 1.0 versions in non-strict mode + // enforce strict semver 2.0 compliance in strict mode + const loose = !strict + if (!data.version) { + data.version = '' + } else { + if (!valid(data.version, loose)) { + throw new Error(`Invalid version: "${data.version}"`) + } + const version = clean(data.version, loose) + if (version !== data.version) { + changes?.push(`"version" was cleaned and set to "${version}"`) + data.version = version + } + } + } + // remove attributes that start with "_" + if (steps.includes('_attributes')) { + for (const key in data) { + if (key.startsWith('_')) { + changes?.push(`"${key}" was removed`) + delete pkg.content[key] + } + } + } + + // build the "_id" attribute + if (steps.includes('_id')) { + if (data.name && data.version) { + changes?.push(`"_id" was set to ${pkgId}`) + data._id = pkgId + } + } + + // fix bundledDependencies typo + // normalize bundleDependencies + if (steps.includes('bundledDependencies')) { + if (data.bundleDependencies === undefined && data.bundledDependencies !== undefined) { + data.bundleDependencies = data.bundledDependencies + } + changes?.push(`Deleted incorrect "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')) { + changes?.push(`"bundleDependencies" was changed from "false" to "[]"`) + data.bundleDependencies = [] + } else if (bd === true) { + changes?.push(`"bundleDependencies" was auto-populated from "dependencies"`) + data.bundleDependencies = Object.keys(data.dependencies || {}) + } else if (bd && typeof bd === 'object') { + if (!Array.isArray(bd)) { + changes?.push(`"bundleDependencies" was changed from an object to an array`) + data.bundleDependencies = Object.keys(bd) + } + } else if ('bundleDependencies' in data) { + changes?.push(`"bundleDependencies" was removed`) + 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) { + changes?.push(`optionalDependencies."${name}" was removed`) + delete data.dependencies[name] + } + if (!Object.keys(data.dependencies).length) { + changes?.push(`Empty "optionalDependencies" was removed`) + 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 lazyLoadGlob()('*.gyp', { cwd: pkg.path }) + if (files.length) { + scripts.install = 'node-gyp rebuild' + data.scripts = scripts + data.gypfile = true + changes?.push(`"scripts.install" was set to "node-gyp rebuild"`) + changes?.push(`"gypfile" was set to "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 + changes?.push('"scripts.start" was set to "node server.js"') + } catch { + // do nothing + } + } + + // strip "node_modules/.bin" from scripts entries + // remove invalid scripts entries (non-strings) + if ((steps.includes('scripts') || steps.includes('scriptpath')) && data.scripts !== undefined) { + 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] + changes?.push(`Invalid scripts."${name}" was removed`) + } else if (steps.includes('scriptpath') && spre.test(data.scripts[name])) { + data.scripts[name] = data.scripts[name].replace(spre, '') + changes?.push(`scripts entry "${name}" was fixed to remove node_modules/.bin reference`) + } + } + } else { + changes?.push(`Removed invalid "scripts"`) + delete data.scripts + } + } + + if (steps.includes('funding')) { + if (data.funding && typeof data.funding === 'string') { + data.funding = { url: data.funding } + changes?.push(`"funding" was changed to an object with a url attribute`) + } + } + + // 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 + changes?.push('"contributors" was auto-populated with the contents of the "AUTHORS" file') + } 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 lazyLoadGlob()('{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 + changes?.push(`"readme" was set to the contents of ${readmeFile}`) + changes?.push(`"readmeFilename" was set to ${readmeFile}`) + } + if (!data.readme) { + // this.warn('missingReadme') + data.readme = 'ERROR: No README data found!' + } + } + + // expand directories.man + if (steps.includes('mans')) { + if (data.directories?.man && !data.man) { + const manDir = secureAndUnixifyPath(data.directories.man) + const cwd = path.resolve(pkg.path, manDir) + const files = await lazyLoadGlob()('**/*.[0-9]', { cwd }) + data.man = files.map(man => + path.relative(pkg.path, path.join(cwd, man)).split(path.sep).join('/') + ) + } + normalizePackageMan(data, changes) + } + + if (steps.includes('bin') || steps.includes('binDir') || steps.includes('binRefs')) { + normalizePackageBin(data, changes) + } + + // expand "directories.bin" + if (steps.includes('binDir') && data.directories?.bin && !data.bin) { + const binsDir = path.resolve(pkg.path, secureAndUnixifyPath(data.directories.bin)) + const bins = await lazyLoadGlob()('**', { 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, changes) + } + + // populate "gitHead" attribute + if (steps.includes('gitHead') && !data.gitHead) { + const git = require('@npmcli/git') + 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", which was just a call through to + // "normalize-package-data". We only call the "fixer" functions because + // outside of that it was also clobbering _id (which we already conditionally + // do) and also adding the gypfile script (which we also already + // conditionally do) + + // Some steps are isolated so we can do a limited subset of these in `fix` + if (steps.includes('fixRepositoryField') || steps.includes('normalizeData')) { + if (data.repositories) { + /* eslint-disable-next-line max-len */ + changes?.push(`"repository" was set to the first entry in "repositories" (${data.repository})`) + data.repository = data.repositories[0] + } + if (data.repository) { + if (typeof data.repository === 'string') { + changes?.push('"repository" was changed from a string to an object') + data.repository = { + type: 'git', + url: data.repository, + } + } + if (data.repository.url) { + const hosted = lazyHostedGitInfo().fromUrl(data.repository.url) + let r + if (hosted) { + if (hosted.getDefaultRepresentation() === 'shortcut') { + r = hosted.https() + } else { + r = hosted.toString() + } + if (r !== data.repository.url) { + changes?.push(`"repository.url" was normalized to "${r}"`) + data.repository.url = r + } + } + } + } + } + + if (steps.includes('fixDependencies') || steps.includes('normalizeData')) { + // peerDependencies? + // devDependencies is meaningless here, it's ignored on an installed package + for (const type of ['dependencies', 'devDependencies', 'optionalDependencies']) { + if (data[type]) { + let secondWarning = true + if (typeof data[type] === 'string') { + changes?.push(`"${type}" was converted from a string into an object`) + data[type] = data[type].trim().split(/[\n\r\s\t ,]+/) + secondWarning = false + } + if (Array.isArray(data[type])) { + if (secondWarning) { + changes?.push(`"${type}" was converted from an array into an object`) + } + const o = {} + for (const d of data[type]) { + if (typeof d === 'string') { + const dep = d.trim().split(/(:?[@\s><=])/) + const dn = dep.shift() + const dv = dep.join('').replace(/^@/, '').trim() + o[dn] = dv + } + } + data[type] = o + } + } + } + // normalize-package-data used to put optional dependencies BACK into + // dependencies here, we no longer do this + + for (const deps of ['dependencies', 'devDependencies']) { + if (deps in data) { + if (!data[deps] || typeof data[deps] !== 'object') { + changes?.push(`Removed invalid "${deps}"`) + delete data[deps] + } else { + for (const d in data[deps]) { + const r = data[deps][d] + if (typeof r !== 'string') { + changes?.push(`Removed invalid "${deps}.${d}"`) + delete data[deps][d] + } + const hosted = lazyHostedGitInfo().fromUrl(data[deps][d])?.toString() + if (hosted && hosted !== data[deps][d]) { + changes?.push(`Normalized git reference to "${deps}.${d}"`) + data[deps][d] = hosted.toString() + } + } + } + } + } + } + + if (steps.includes('normalizeData')) { + const legacyFixer = require('normalize-package-data/lib/fixer.js') + const legacyMakeWarning = require('normalize-package-data/lib/make_warning.js') + legacyFixer.warn = function () { + changes?.push(legacyMakeWarning.apply(null, arguments)) + } + + const legacySteps = [ + 'fixDescriptionField', + 'fixModulesField', + 'fixFilesField', + 'fixManField', + 'fixBugsField', + 'fixKeywordsField', + 'fixBundleDependenciesField', + 'fixHomepageField', + 'fixReadmeField', + 'fixLicenseField', + 'fixPeople', + 'fixTypos', + ] + for (const legacyStep of legacySteps) { + legacyFixer[legacyStep](data) + } + } + + // 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/map-workspaces/node_modules/@npmcli/package-json/lib/read-package.js b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json/lib/read-package.js new file mode 100644 index 0000000000000..d6c86ce388e6c --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json/lib/read-package.js @@ -0,0 +1,39 @@ +// This is JUST the code needed to open a package.json file and parse it. +// It's isolated out so that code needing to parse a package.json file can do so in the same way as this module does, without needing to require the whole module, or needing to require the underlying parsing library. + +const { readFile } = require('fs/promises') +const parseJSON = require('json-parse-even-better-errors') + +async function read (filename) { + try { + const data = await readFile(filename, 'utf8') + return data + } catch (err) { + err.message = `Could not read package.json: ${err}` + throw err + } +} + +function parse (data) { + try { + const content = parseJSON(data) + return content + } catch (err) { + err.message = `Invalid package.json: ${err}` + throw err + } +} + +// This is what most external libs will use. +// PackageJson will call read and parse separately +async function readPackage (filename) { + const data = await read(filename) + const content = parse(data) + return content +} + +module.exports = { + read, + parse, + readPackage, +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json/lib/update-dependencies.js b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json/lib/update-dependencies.js new file mode 100644 index 0000000000000..7259949ab661d --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json/lib/update-dependencies.js @@ -0,0 +1,75 @@ +const depTypes = new Set([ + 'dependencies', + 'optionalDependencies', + 'devDependencies', + 'peerDependencies', +]) + +// sort alphabetically all types of deps for a given package +const orderDeps = (content) => { + for (const type of depTypes) { + if (content && content[type]) { + content[type] = Object.keys(content[type]) + .sort((a, b) => a.localeCompare(b, 'en')) + .reduce((res, key) => { + res[key] = content[type][key] + return res + }, {}) + } + } + return content +} + +const updateDependencies = ({ content, originalContent }) => { + const pkg = orderDeps({ + ...content, + }) + + // optionalDependencies don't need to be repeated in two places + if (pkg.dependencies) { + if (pkg.optionalDependencies) { + for (const name of Object.keys(pkg.optionalDependencies)) { + delete pkg.dependencies[name] + } + } + } + + const result = { ...originalContent } + + // loop through all types of dependencies and update package json pkg + for (const type of depTypes) { + if (pkg[type]) { + result[type] = pkg[type] + } + + // prune empty type props from resulting object + const emptyDepType = + pkg[type] + && typeof pkg === 'object' + && Object.keys(pkg[type]).length === 0 + if (emptyDepType) { + delete result[type] + } + } + + // if original package.json had dep in peerDeps AND deps, preserve that. + const { dependencies: origProd, peerDependencies: origPeer } = + originalContent || {} + const { peerDependencies: newPeer } = result + if (origProd && origPeer && newPeer) { + // we have original prod/peer deps, and new peer deps + // copy over any that were in both in the original + for (const name of Object.keys(origPeer)) { + if (origProd[name] !== undefined && newPeer[name] !== undefined) { + result.dependencies = result.dependencies || {} + result.dependencies[name] = newPeer[name] + } + } + } + + return result +} + +updateDependencies.knownKeys = depTypes + +module.exports = updateDependencies diff --git a/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json/lib/update-scripts.js b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json/lib/update-scripts.js new file mode 100644 index 0000000000000..30495e54cc3c7 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json/lib/update-scripts.js @@ -0,0 +1,29 @@ +const updateScripts = ({ content, originalContent = {} }) => { + const newScripts = content.scripts + + if (!newScripts) { + return originalContent + } + + // validate scripts content being appended + const hasInvalidScripts = () => + Object.entries(newScripts) + .some(([key, value]) => + typeof key !== 'string' || typeof value !== 'string') + if (hasInvalidScripts()) { + throw Object.assign( + new TypeError( + 'package.json scripts should be a key-value pair of strings.'), + { code: 'ESCRIPTSINVALID' } + ) + } + + return { + ...originalContent, + scripts: { + ...newScripts, + }, + } +} + +module.exports = updateScripts diff --git a/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json/lib/update-workspaces.js b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json/lib/update-workspaces.js new file mode 100644 index 0000000000000..04bf63230636f --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json/lib/update-workspaces.js @@ -0,0 +1,26 @@ +const updateWorkspaces = ({ content, originalContent = {} }) => { + const newWorkspaces = content.workspaces + + if (!newWorkspaces) { + return originalContent + } + + // validate workspaces content being appended + const hasInvalidWorkspaces = () => + newWorkspaces.some(w => !(typeof w === 'string')) + if (!newWorkspaces.length || hasInvalidWorkspaces()) { + throw Object.assign( + new TypeError('workspaces should be an array of strings.'), + { code: 'EWORKSPACESINVALID' } + ) + } + + return { + ...originalContent, + workspaces: [ + ...newWorkspaces, + ], + } +} + +module.exports = updateWorkspaces diff --git a/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json/package.json b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json/package.json new file mode 100644 index 0000000000000..e766e8ccb4bbf --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json/package.json @@ -0,0 +1,61 @@ +{ + "name": "@npmcli/package-json", + "version": "6.0.1", + "description": "Programmatic API to update package.json", + "main": "lib/index.js", + "files": [ + "bin/", + "lib/" + ], + "scripts": { + "snap": "tap", + "test": "tap", + "lint": "npm run eslint", + "lintfix": "npm run eslint -- --fix", + "posttest": "npm run lint", + "postsnap": "npm run lintfix --", + "postlint": "template-oss-check", + "template-oss-apply": "template-oss-apply --force", + "eslint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"" + }, + "keywords": [ + "npm", + "oss" + ], + "author": "GitHub Inc.", + "license": "ISC", + "devDependencies": { + "@npmcli/eslint-config": "^5.0.0", + "@npmcli/template-oss": "4.23.3", + "read-package-json": "^7.0.0", + "read-package-json-fast": "^4.0.0", + "tap": "^16.0.1" + }, + "dependencies": { + "@npmcli/git": "^6.0.0", + "glob": "^10.2.2", + "hosted-git-info": "^8.0.0", + "json-parse-even-better-errors": "^4.0.0", + "normalize-package-data": "^7.0.0", + "proc-log": "^5.0.0", + "semver": "^7.5.3" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/npm/package-json.git" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + }, + "templateOSS": { + "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", + "version": "4.23.3", + "publish": "true" + }, + "tap": { + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] + } +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/promise-spawn/LICENSE b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/promise-spawn/LICENSE new file mode 100644 index 0000000000000..8f90f96f4c6c5 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/promise-spawn/LICENSE @@ -0,0 +1,15 @@ +The 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 NPM DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE 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/@npmcli/map-workspaces/node_modules/@npmcli/promise-spawn/lib/escape.js b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/promise-spawn/lib/escape.js new file mode 100644 index 0000000000000..9aca8bde70a6e --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/promise-spawn/lib/escape.js @@ -0,0 +1,68 @@ +'use strict' + +// eslint-disable-next-line max-len +// this code adapted from: https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/ +const cmd = (input, doubleEscape) => { + if (!input.length) { + return '""' + } + + let result + if (!/[ \t\n\v"]/.test(input)) { + result = input + } else { + result = '"' + for (let i = 0; i <= input.length; ++i) { + let slashCount = 0 + while (input[i] === '\\') { + ++i + ++slashCount + } + + if (i === input.length) { + result += '\\'.repeat(slashCount * 2) + break + } + + if (input[i] === '"') { + result += '\\'.repeat(slashCount * 2 + 1) + result += input[i] + } else { + result += '\\'.repeat(slashCount) + result += input[i] + } + } + result += '"' + } + + // and finally, prefix shell meta chars with a ^ + result = result.replace(/[ !%^&()<>|"]/g, '^$&') + if (doubleEscape) { + result = result.replace(/[ !%^&()<>|"]/g, '^$&') + } + + return result +} + +const sh = (input) => { + if (!input.length) { + return `''` + } + + if (!/[\t\n\r "#$&'()*;<>?\\`|~]/.test(input)) { + return input + } + + // replace single quotes with '\'' and wrap the whole result in a fresh set of quotes + const result = `'${input.replace(/'/g, `'\\''`)}'` + // if the input string already had single quotes around it, clean those up + .replace(/^(?:'')+(?!$)/, '') + .replace(/\\'''/g, `\\'`) + + return result +} + +module.exports = { + cmd, + sh, +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/promise-spawn/lib/index.js b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/promise-spawn/lib/index.js new file mode 100644 index 0000000000000..e147cb8f9c746 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/promise-spawn/lib/index.js @@ -0,0 +1,206 @@ +'use strict' + +const { spawn } = require('child_process') +const os = require('os') +const which = require('which') + +const escape = require('./escape.js') + +// 'extra' object is for decorating the error a bit more +const promiseSpawn = (cmd, args, opts = {}, extra = {}) => { + if (opts.shell) { + return spawnWithShell(cmd, args, opts, extra) + } + + let resolve, reject + const promise = new Promise((_resolve, _reject) => { + resolve = _resolve + reject = _reject + }) + + // Create error here so we have a more useful stack trace when rejecting + const closeError = new Error('command failed') + + const stdout = [] + const stderr = [] + + const getResult = (result) => ({ + cmd, + args, + ...result, + ...stdioResult(stdout, stderr, opts), + ...extra, + }) + const rejectWithOpts = (er, erOpts) => { + const resultError = getResult(erOpts) + reject(Object.assign(er, resultError)) + } + + const proc = spawn(cmd, args, opts) + promise.stdin = proc.stdin + promise.process = proc + + proc.on('error', rejectWithOpts) + + if (proc.stdout) { + proc.stdout.on('data', c => stdout.push(c)) + proc.stdout.on('error', rejectWithOpts) + } + + if (proc.stderr) { + proc.stderr.on('data', c => stderr.push(c)) + proc.stderr.on('error', rejectWithOpts) + } + + proc.on('close', (code, signal) => { + if (code || signal) { + rejectWithOpts(closeError, { code, signal }) + } else { + resolve(getResult({ code, signal })) + } + }) + + return promise +} + +const spawnWithShell = (cmd, args, opts, extra) => { + let command = opts.shell + // if shell is set to true, we use a platform default. we can't let the core + // spawn method decide this for us because we need to know what shell is in use + // ahead of time so that we can escape arguments properly. we don't need coverage here. + if (command === true) { + // istanbul ignore next + command = process.platform === 'win32' ? process.env.ComSpec : 'sh' + } + + const options = { ...opts, shell: false } + const realArgs = [] + let script = cmd + + // first, determine if we're in windows because if we are we need to know if we're + // running an .exe or a .cmd/.bat since the latter requires extra escaping + const isCmd = /(?:^|\\)cmd(?:\.exe)?$/i.test(command) + if (isCmd) { + let doubleEscape = false + + // find the actual command we're running + let initialCmd = '' + let insideQuotes = false + for (let i = 0; i < cmd.length; ++i) { + const char = cmd.charAt(i) + if (char === ' ' && !insideQuotes) { + break + } + + initialCmd += char + if (char === '"' || char === "'") { + insideQuotes = !insideQuotes + } + } + + let pathToInitial + try { + pathToInitial = which.sync(initialCmd, { + path: (options.env && findInObject(options.env, 'PATH')) || process.env.PATH, + pathext: (options.env && findInObject(options.env, 'PATHEXT')) || process.env.PATHEXT, + }).toLowerCase() + } catch (err) { + pathToInitial = initialCmd.toLowerCase() + } + + doubleEscape = pathToInitial.endsWith('.cmd') || pathToInitial.endsWith('.bat') + for (const arg of args) { + script += ` ${escape.cmd(arg, doubleEscape)}` + } + realArgs.push('/d', '/s', '/c', script) + options.windowsVerbatimArguments = true + } else { + for (const arg of args) { + script += ` ${escape.sh(arg)}` + } + realArgs.push('-c', script) + } + + return promiseSpawn(command, realArgs, options, extra) +} + +// open a file with the default application as defined by the user's OS +const open = (_args, opts = {}, extra = {}) => { + const options = { ...opts, shell: true } + const args = [].concat(_args) + + let platform = process.platform + // process.platform === 'linux' may actually indicate WSL, if that's the case + // we want to treat things as win32 anyway so the host can open the argument + if (platform === 'linux' && os.release().toLowerCase().includes('microsoft')) { + platform = 'win32' + } + + let command = options.command + if (!command) { + if (platform === 'win32') { + // spawnWithShell does not do the additional os.release() check, so we + // have to force the shell here to make sure we treat WSL as windows. + options.shell = process.env.ComSpec + // also, the start command accepts a title so to make sure that we don't + // accidentally interpret the first arg as the title, we stick an empty + // string immediately after the start command + command = 'start ""' + } else if (platform === 'darwin') { + command = 'open' + } else { + command = 'xdg-open' + } + } + + return spawnWithShell(command, args, options, extra) +} +promiseSpawn.open = open + +const isPipe = (stdio = 'pipe', fd) => { + if (stdio === 'pipe' || stdio === null) { + return true + } + + if (Array.isArray(stdio)) { + return isPipe(stdio[fd], fd) + } + + return false +} + +const stdioResult = (stdout, stderr, { stdioString = true, stdio }) => { + const result = { + stdout: null, + stderr: null, + } + + // stdio is [stdin, stdout, stderr] + if (isPipe(stdio, 1)) { + result.stdout = Buffer.concat(stdout) + if (stdioString) { + result.stdout = result.stdout.toString().trim() + } + } + + if (isPipe(stdio, 2)) { + result.stderr = Buffer.concat(stderr) + if (stdioString) { + result.stderr = result.stderr.toString().trim() + } + } + + return result +} + +// case insensitive lookup in an object +const findInObject = (obj, key) => { + key = key.toLowerCase() + for (const objKey of Object.keys(obj).sort()) { + if (objKey.toLowerCase() === key) { + return obj[objKey] + } + } +} + +module.exports = promiseSpawn diff --git a/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/promise-spawn/package.json b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/promise-spawn/package.json new file mode 100644 index 0000000000000..9914063f85156 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/@npmcli/promise-spawn/package.json @@ -0,0 +1,51 @@ +{ + "name": "@npmcli/promise-spawn", + "version": "8.0.1", + "files": [ + "bin/", + "lib/" + ], + "main": "./lib/index.js", + "description": "spawn processes the way the npm cli likes to do", + "repository": { + "type": "git", + "url": "git+https://github.com/npm/promise-spawn.git" + }, + "author": "GitHub Inc.", + "license": "ISC", + "scripts": { + "test": "tap", + "snap": "tap", + "lint": "npm run eslint", + "lintfix": "npm run eslint -- --fix", + "posttest": "npm run lint", + "postsnap": "npm run lintfix --", + "postlint": "template-oss-check", + "template-oss-apply": "template-oss-apply --force", + "eslint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"" + }, + "tap": { + "check-coverage": true, + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] + }, + "devDependencies": { + "@npmcli/eslint-config": "^5.0.0", + "@npmcli/template-oss": "4.23.3", + "spawk": "^1.7.1", + "tap": "^16.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + }, + "templateOSS": { + "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", + "version": "4.23.3", + "publish": true + }, + "dependencies": { + "which": "^5.0.0" + } +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/hosted-git-info/LICENSE b/node_modules/@npmcli/map-workspaces/node_modules/hosted-git-info/LICENSE new file mode 100644 index 0000000000000..45055763dc838 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/hosted-git-info/LICENSE @@ -0,0 +1,13 @@ +Copyright (c) 2015, Rebecca Turner + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. diff --git a/node_modules/@npmcli/map-workspaces/node_modules/hosted-git-info/lib/from-url.js b/node_modules/@npmcli/map-workspaces/node_modules/hosted-git-info/lib/from-url.js new file mode 100644 index 0000000000000..efc1247d59d12 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/hosted-git-info/lib/from-url.js @@ -0,0 +1,122 @@ +'use strict' + +const parseUrl = require('./parse-url') + +// look for github shorthand inputs, such as npm/cli +const isGitHubShorthand = (arg) => { + // it cannot contain whitespace before the first # + // it cannot start with a / because that's probably an absolute file path + // but it must include a slash since repos are username/repository + // it cannot start with a . because that's probably a relative file path + // it cannot start with an @ because that's a scoped package if it passes the other tests + // it cannot contain a : before a # because that tells us that there's a protocol + // a second / may not exist before a # + const firstHash = arg.indexOf('#') + const firstSlash = arg.indexOf('/') + const secondSlash = arg.indexOf('/', firstSlash + 1) + const firstColon = arg.indexOf(':') + const firstSpace = /\s/.exec(arg) + const firstAt = arg.indexOf('@') + + const spaceOnlyAfterHash = !firstSpace || (firstHash > -1 && firstSpace.index > firstHash) + const atOnlyAfterHash = firstAt === -1 || (firstHash > -1 && firstAt > firstHash) + const colonOnlyAfterHash = firstColon === -1 || (firstHash > -1 && firstColon > firstHash) + const secondSlashOnlyAfterHash = secondSlash === -1 || (firstHash > -1 && secondSlash > firstHash) + const hasSlash = firstSlash > 0 + // if a # is found, what we really want to know is that the character + // immediately before # is not a / + const doesNotEndWithSlash = firstHash > -1 ? arg[firstHash - 1] !== '/' : !arg.endsWith('/') + const doesNotStartWithDot = !arg.startsWith('.') + + return spaceOnlyAfterHash && hasSlash && doesNotEndWithSlash && + doesNotStartWithDot && atOnlyAfterHash && colonOnlyAfterHash && + secondSlashOnlyAfterHash +} + +module.exports = (giturl, opts, { gitHosts, protocols }) => { + if (!giturl) { + return + } + + const correctedUrl = isGitHubShorthand(giturl) ? `github:${giturl}` : giturl + const parsed = parseUrl(correctedUrl, protocols) + if (!parsed) { + return + } + + const gitHostShortcut = gitHosts.byShortcut[parsed.protocol] + const gitHostDomain = gitHosts.byDomain[parsed.hostname.startsWith('www.') + ? parsed.hostname.slice(4) + : parsed.hostname] + const gitHostName = gitHostShortcut || gitHostDomain + if (!gitHostName) { + return + } + + const gitHostInfo = gitHosts[gitHostShortcut || gitHostDomain] + let auth = null + if (protocols[parsed.protocol]?.auth && (parsed.username || parsed.password)) { + auth = `${parsed.username}${parsed.password ? ':' + parsed.password : ''}` + } + + let committish = null + let user = null + let project = null + let defaultRepresentation = null + + try { + if (gitHostShortcut) { + let pathname = parsed.pathname.startsWith('/') ? parsed.pathname.slice(1) : parsed.pathname + const firstAt = pathname.indexOf('@') + // we ignore auth for shortcuts, so just trim it out + if (firstAt > -1) { + pathname = pathname.slice(firstAt + 1) + } + + const lastSlash = pathname.lastIndexOf('/') + if (lastSlash > -1) { + user = decodeURIComponent(pathname.slice(0, lastSlash)) + // we want nulls only, never empty strings + if (!user) { + user = null + } + project = decodeURIComponent(pathname.slice(lastSlash + 1)) + } else { + project = decodeURIComponent(pathname) + } + + if (project.endsWith('.git')) { + project = project.slice(0, -4) + } + + if (parsed.hash) { + committish = decodeURIComponent(parsed.hash.slice(1)) + } + + defaultRepresentation = 'shortcut' + } else { + if (!gitHostInfo.protocols.includes(parsed.protocol)) { + return + } + + const segments = gitHostInfo.extract(parsed) + if (!segments) { + return + } + + user = segments.user && decodeURIComponent(segments.user) + project = decodeURIComponent(segments.project) + committish = decodeURIComponent(segments.committish) + defaultRepresentation = protocols[parsed.protocol]?.name || parsed.protocol.slice(0, -1) + } + } catch (err) { + /* istanbul ignore else */ + if (err instanceof URIError) { + return + } else { + throw err + } + } + + return [gitHostName, user, auth, project, committish, defaultRepresentation, opts] +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/hosted-git-info/lib/hosts.js b/node_modules/@npmcli/map-workspaces/node_modules/hosted-git-info/lib/hosts.js new file mode 100644 index 0000000000000..9a08efd1b2d7e --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/hosted-git-info/lib/hosts.js @@ -0,0 +1,227 @@ +/* eslint-disable max-len */ + +'use strict' + +const maybeJoin = (...args) => args.every(arg => arg) ? args.join('') : '' +const maybeEncode = (arg) => arg ? encodeURIComponent(arg) : '' +const formatHashFragment = (f) => f.toLowerCase().replace(/^\W+|\/|\W+$/g, '').replace(/\W+/g, '-') + +const defaults = { + sshtemplate: ({ domain, user, project, committish }) => + `git@${domain}:${user}/${project}.git${maybeJoin('#', committish)}`, + sshurltemplate: ({ domain, user, project, committish }) => + `git+ssh://git@${domain}/${user}/${project}.git${maybeJoin('#', committish)}`, + edittemplate: ({ domain, user, project, committish, editpath, path }) => + `https://${domain}/${user}/${project}${maybeJoin('/', editpath, '/', maybeEncode(committish || 'HEAD'), '/', path)}`, + browsetemplate: ({ domain, user, project, committish, treepath }) => + `https://${domain}/${user}/${project}${maybeJoin('/', treepath, '/', maybeEncode(committish))}`, + browsetreetemplate: ({ domain, user, project, committish, treepath, path, fragment, hashformat }) => + `https://${domain}/${user}/${project}/${treepath}/${maybeEncode(committish || 'HEAD')}/${path}${maybeJoin('#', hashformat(fragment || ''))}`, + browseblobtemplate: ({ domain, user, project, committish, blobpath, path, fragment, hashformat }) => + `https://${domain}/${user}/${project}/${blobpath}/${maybeEncode(committish || 'HEAD')}/${path}${maybeJoin('#', hashformat(fragment || ''))}`, + docstemplate: ({ domain, user, project, treepath, committish }) => + `https://${domain}/${user}/${project}${maybeJoin('/', treepath, '/', maybeEncode(committish))}#readme`, + httpstemplate: ({ auth, domain, user, project, committish }) => + `git+https://${maybeJoin(auth, '@')}${domain}/${user}/${project}.git${maybeJoin('#', committish)}`, + filetemplate: ({ domain, user, project, committish, path }) => + `https://${domain}/${user}/${project}/raw/${maybeEncode(committish || 'HEAD')}/${path}`, + shortcuttemplate: ({ type, user, project, committish }) => + `${type}:${user}/${project}${maybeJoin('#', committish)}`, + pathtemplate: ({ user, project, committish }) => + `${user}/${project}${maybeJoin('#', committish)}`, + bugstemplate: ({ domain, user, project }) => + `https://${domain}/${user}/${project}/issues`, + hashformat: formatHashFragment, +} + +const hosts = {} +hosts.github = { + // First two are insecure and generally shouldn't be used any more, but + // they are still supported. + protocols: ['git:', 'http:', 'git+ssh:', 'git+https:', 'ssh:', 'https:'], + domain: 'github.com', + treepath: 'tree', + blobpath: 'blob', + editpath: 'edit', + filetemplate: ({ auth, user, project, committish, path }) => + `https://${maybeJoin(auth, '@')}raw.githubusercontent.com/${user}/${project}/${maybeEncode(committish || 'HEAD')}/${path}`, + gittemplate: ({ auth, domain, user, project, committish }) => + `git://${maybeJoin(auth, '@')}${domain}/${user}/${project}.git${maybeJoin('#', committish)}`, + tarballtemplate: ({ domain, user, project, committish }) => + `https://codeload.${domain}/${user}/${project}/tar.gz/${maybeEncode(committish || 'HEAD')}`, + extract: (url) => { + let [, user, project, type, committish] = url.pathname.split('/', 5) + if (type && type !== 'tree') { + return + } + + if (!type) { + committish = url.hash.slice(1) + } + + if (project && project.endsWith('.git')) { + project = project.slice(0, -4) + } + + if (!user || !project) { + return + } + + return { user, project, committish } + }, +} + +hosts.bitbucket = { + protocols: ['git+ssh:', 'git+https:', 'ssh:', 'https:'], + domain: 'bitbucket.org', + treepath: 'src', + blobpath: 'src', + editpath: '?mode=edit', + edittemplate: ({ domain, user, project, committish, treepath, path, editpath }) => + `https://${domain}/${user}/${project}${maybeJoin('/', treepath, '/', maybeEncode(committish || 'HEAD'), '/', path, editpath)}`, + tarballtemplate: ({ domain, user, project, committish }) => + `https://${domain}/${user}/${project}/get/${maybeEncode(committish || 'HEAD')}.tar.gz`, + extract: (url) => { + let [, user, project, aux] = url.pathname.split('/', 4) + if (['get'].includes(aux)) { + return + } + + if (project && project.endsWith('.git')) { + project = project.slice(0, -4) + } + + if (!user || !project) { + return + } + + return { user, project, committish: url.hash.slice(1) } + }, +} + +hosts.gitlab = { + protocols: ['git+ssh:', 'git+https:', 'ssh:', 'https:'], + domain: 'gitlab.com', + treepath: 'tree', + blobpath: 'tree', + editpath: '-/edit', + httpstemplate: ({ auth, domain, user, project, committish }) => + `git+https://${maybeJoin(auth, '@')}${domain}/${user}/${project}.git${maybeJoin('#', committish)}`, + tarballtemplate: ({ domain, user, project, committish }) => + `https://${domain}/${user}/${project}/repository/archive.tar.gz?ref=${maybeEncode(committish || 'HEAD')}`, + extract: (url) => { + const path = url.pathname.slice(1) + if (path.includes('/-/') || path.includes('/archive.tar.gz')) { + return + } + + const segments = path.split('/') + let project = segments.pop() + if (project.endsWith('.git')) { + project = project.slice(0, -4) + } + + const user = segments.join('/') + if (!user || !project) { + return + } + + return { user, project, committish: url.hash.slice(1) } + }, +} + +hosts.gist = { + protocols: ['git:', 'git+ssh:', 'git+https:', 'ssh:', 'https:'], + domain: 'gist.github.com', + editpath: 'edit', + sshtemplate: ({ domain, project, committish }) => + `git@${domain}:${project}.git${maybeJoin('#', committish)}`, + sshurltemplate: ({ domain, project, committish }) => + `git+ssh://git@${domain}/${project}.git${maybeJoin('#', committish)}`, + edittemplate: ({ domain, user, project, committish, editpath }) => + `https://${domain}/${user}/${project}${maybeJoin('/', maybeEncode(committish))}/${editpath}`, + browsetemplate: ({ domain, project, committish }) => + `https://${domain}/${project}${maybeJoin('/', maybeEncode(committish))}`, + browsetreetemplate: ({ domain, project, committish, path, hashformat }) => + `https://${domain}/${project}${maybeJoin('/', maybeEncode(committish))}${maybeJoin('#', hashformat(path))}`, + browseblobtemplate: ({ domain, project, committish, path, hashformat }) => + `https://${domain}/${project}${maybeJoin('/', maybeEncode(committish))}${maybeJoin('#', hashformat(path))}`, + docstemplate: ({ domain, project, committish }) => + `https://${domain}/${project}${maybeJoin('/', maybeEncode(committish))}`, + httpstemplate: ({ domain, project, committish }) => + `git+https://${domain}/${project}.git${maybeJoin('#', committish)}`, + filetemplate: ({ user, project, committish, path }) => + `https://gist.githubusercontent.com/${user}/${project}/raw${maybeJoin('/', maybeEncode(committish))}/${path}`, + shortcuttemplate: ({ type, project, committish }) => + `${type}:${project}${maybeJoin('#', committish)}`, + pathtemplate: ({ project, committish }) => + `${project}${maybeJoin('#', committish)}`, + bugstemplate: ({ domain, project }) => + `https://${domain}/${project}`, + gittemplate: ({ domain, project, committish }) => + `git://${domain}/${project}.git${maybeJoin('#', committish)}`, + tarballtemplate: ({ project, committish }) => + `https://codeload.github.com/gist/${project}/tar.gz/${maybeEncode(committish || 'HEAD')}`, + extract: (url) => { + let [, user, project, aux] = url.pathname.split('/', 4) + if (aux === 'raw') { + return + } + + if (!project) { + if (!user) { + return + } + + project = user + user = null + } + + if (project.endsWith('.git')) { + project = project.slice(0, -4) + } + + return { user, project, committish: url.hash.slice(1) } + }, + hashformat: function (fragment) { + return fragment && 'file-' + formatHashFragment(fragment) + }, +} + +hosts.sourcehut = { + protocols: ['git+ssh:', 'https:'], + domain: 'git.sr.ht', + treepath: 'tree', + blobpath: 'tree', + filetemplate: ({ domain, user, project, committish, path }) => + `https://${domain}/${user}/${project}/blob/${maybeEncode(committish) || 'HEAD'}/${path}`, + httpstemplate: ({ domain, user, project, committish }) => + `https://${domain}/${user}/${project}.git${maybeJoin('#', committish)}`, + tarballtemplate: ({ domain, user, project, committish }) => + `https://${domain}/${user}/${project}/archive/${maybeEncode(committish) || 'HEAD'}.tar.gz`, + bugstemplate: () => null, + extract: (url) => { + let [, user, project, aux] = url.pathname.split('/', 4) + + // tarball url + if (['archive'].includes(aux)) { + return + } + + if (project && project.endsWith('.git')) { + project = project.slice(0, -4) + } + + if (!user || !project) { + return + } + + return { user, project, committish: url.hash.slice(1) } + }, +} + +for (const [name, host] of Object.entries(hosts)) { + hosts[name] = Object.assign({}, defaults, host) +} + +module.exports = hosts diff --git a/node_modules/@npmcli/map-workspaces/node_modules/hosted-git-info/lib/index.js b/node_modules/@npmcli/map-workspaces/node_modules/hosted-git-info/lib/index.js new file mode 100644 index 0000000000000..0c9d0b08c866b --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/hosted-git-info/lib/index.js @@ -0,0 +1,179 @@ +'use strict' + +const { LRUCache } = require('lru-cache') +const hosts = require('./hosts.js') +const fromUrl = require('./from-url.js') +const parseUrl = require('./parse-url.js') + +const cache = new LRUCache({ max: 1000 }) + +class GitHost { + constructor (type, user, auth, project, committish, defaultRepresentation, opts = {}) { + Object.assign(this, GitHost.#gitHosts[type], { + type, + user, + auth, + project, + committish, + default: defaultRepresentation, + opts, + }) + } + + static #gitHosts = { byShortcut: {}, byDomain: {} } + static #protocols = { + 'git+ssh:': { name: 'sshurl' }, + 'ssh:': { name: 'sshurl' }, + 'git+https:': { name: 'https', auth: true }, + 'git:': { auth: true }, + 'http:': { auth: true }, + 'https:': { auth: true }, + 'git+http:': { auth: true }, + } + + static addHost (name, host) { + GitHost.#gitHosts[name] = host + GitHost.#gitHosts.byDomain[host.domain] = name + GitHost.#gitHosts.byShortcut[`${name}:`] = name + GitHost.#protocols[`${name}:`] = { name } + } + + static fromUrl (giturl, opts) { + if (typeof giturl !== 'string') { + return + } + + const key = giturl + JSON.stringify(opts || {}) + + if (!cache.has(key)) { + const hostArgs = fromUrl(giturl, opts, { + gitHosts: GitHost.#gitHosts, + protocols: GitHost.#protocols, + }) + cache.set(key, hostArgs ? new GitHost(...hostArgs) : undefined) + } + + return cache.get(key) + } + + static parseUrl (url) { + return parseUrl(url) + } + + #fill (template, opts) { + if (typeof template !== 'function') { + return null + } + + const options = { ...this, ...this.opts, ...opts } + + // the path should always be set so we don't end up with 'undefined' in urls + if (!options.path) { + options.path = '' + } + + // template functions will insert the leading slash themselves + if (options.path.startsWith('/')) { + options.path = options.path.slice(1) + } + + if (options.noCommittish) { + options.committish = null + } + + const result = template(options) + return options.noGitPlus && result.startsWith('git+') ? result.slice(4) : result + } + + hash () { + return this.committish ? `#${this.committish}` : '' + } + + ssh (opts) { + return this.#fill(this.sshtemplate, opts) + } + + sshurl (opts) { + return this.#fill(this.sshurltemplate, opts) + } + + browse (path, ...args) { + // not a string, treat path as opts + if (typeof path !== 'string') { + return this.#fill(this.browsetemplate, path) + } + + if (typeof args[0] !== 'string') { + return this.#fill(this.browsetreetemplate, { ...args[0], path }) + } + + return this.#fill(this.browsetreetemplate, { ...args[1], fragment: args[0], path }) + } + + // If the path is known to be a file, then browseFile should be used. For some hosts + // the url is the same as browse, but for others like GitHub a file can use both `/tree/` + // and `/blob/` in the path. When using a default committish of `HEAD` then the `/tree/` + // path will redirect to a specific commit. Using the `/blob/` path avoids this and + // does not redirect to a different commit. + browseFile (path, ...args) { + if (typeof args[0] !== 'string') { + return this.#fill(this.browseblobtemplate, { ...args[0], path }) + } + + return this.#fill(this.browseblobtemplate, { ...args[1], fragment: args[0], path }) + } + + docs (opts) { + return this.#fill(this.docstemplate, opts) + } + + bugs (opts) { + return this.#fill(this.bugstemplate, opts) + } + + https (opts) { + return this.#fill(this.httpstemplate, opts) + } + + git (opts) { + return this.#fill(this.gittemplate, opts) + } + + shortcut (opts) { + return this.#fill(this.shortcuttemplate, opts) + } + + path (opts) { + return this.#fill(this.pathtemplate, opts) + } + + tarball (opts) { + return this.#fill(this.tarballtemplate, { ...opts, noCommittish: false }) + } + + file (path, opts) { + return this.#fill(this.filetemplate, { ...opts, path }) + } + + edit (path, opts) { + return this.#fill(this.edittemplate, { ...opts, path }) + } + + getDefaultRepresentation () { + return this.default + } + + toString (opts) { + if (this.default && typeof this[this.default] === 'function') { + return this[this.default](opts) + } + + return this.sshurl(opts) + } +} + +for (const [name, host] of Object.entries(hosts)) { + GitHost.addHost(name, host) +} + +module.exports = GitHost diff --git a/node_modules/@npmcli/map-workspaces/node_modules/hosted-git-info/lib/parse-url.js b/node_modules/@npmcli/map-workspaces/node_modules/hosted-git-info/lib/parse-url.js new file mode 100644 index 0000000000000..7d5489c008ab4 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/hosted-git-info/lib/parse-url.js @@ -0,0 +1,78 @@ +const url = require('url') + +const lastIndexOfBefore = (str, char, beforeChar) => { + const startPosition = str.indexOf(beforeChar) + return str.lastIndexOf(char, startPosition > -1 ? startPosition : Infinity) +} + +const safeUrl = (u) => { + try { + return new url.URL(u) + } catch { + // this fn should never throw + } +} + +// accepts input like git:github.com:user/repo and inserts the // after the first : +const correctProtocol = (arg, protocols) => { + const firstColon = arg.indexOf(':') + const proto = arg.slice(0, firstColon + 1) + if (Object.prototype.hasOwnProperty.call(protocols, proto)) { + return arg + } + + const firstAt = arg.indexOf('@') + if (firstAt > -1) { + if (firstAt > firstColon) { + return `git+ssh://${arg}` + } else { + return arg + } + } + + const doubleSlash = arg.indexOf('//') + if (doubleSlash === firstColon + 1) { + return arg + } + + return `${arg.slice(0, firstColon + 1)}//${arg.slice(firstColon + 1)}` +} + +// attempt to correct an scp style url so that it will parse with `new URL()` +const correctUrl = (giturl) => { + // ignore @ that come after the first hash since the denotes the start + // of a committish which can contain @ characters + const firstAt = lastIndexOfBefore(giturl, '@', '#') + // ignore colons that come after the hash since that could include colons such as: + // git@github.com:user/package-2#semver:^1.0.0 + const lastColonBeforeHash = lastIndexOfBefore(giturl, ':', '#') + + if (lastColonBeforeHash > firstAt) { + // the last : comes after the first @ (or there is no @) + // like it would in: + // proto://hostname.com:user/repo + // username@hostname.com:user/repo + // :password@hostname.com:user/repo + // username:password@hostname.com:user/repo + // proto://username@hostname.com:user/repo + // proto://:password@hostname.com:user/repo + // proto://username:password@hostname.com:user/repo + // then we replace the last : with a / to create a valid path + giturl = giturl.slice(0, lastColonBeforeHash) + '/' + giturl.slice(lastColonBeforeHash + 1) + } + + if (lastIndexOfBefore(giturl, ':', '#') === -1 && giturl.indexOf('//') === -1) { + // we have no : at all + // as it would be in: + // username@hostname.com/user/repo + // then we prepend a protocol + giturl = `git+ssh://${giturl}` + } + + return giturl +} + +module.exports = (giturl, protocols) => { + const withProtocol = protocols ? correctProtocol(giturl, protocols) : giturl + return safeUrl(withProtocol) || safeUrl(correctUrl(withProtocol)) +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/hosted-git-info/package.json b/node_modules/@npmcli/map-workspaces/node_modules/hosted-git-info/package.json new file mode 100644 index 0000000000000..3bb8bcd1f4982 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/hosted-git-info/package.json @@ -0,0 +1,61 @@ +{ + "name": "hosted-git-info", + "version": "8.0.0", + "description": "Provides metadata and conversions from repository urls for GitHub, Bitbucket and GitLab", + "main": "./lib/index.js", + "repository": { + "type": "git", + "url": "git+https://github.com/npm/hosted-git-info.git" + }, + "keywords": [ + "git", + "github", + "bitbucket", + "gitlab" + ], + "author": "GitHub Inc.", + "license": "ISC", + "bugs": { + "url": "https://github.com/npm/hosted-git-info/issues" + }, + "homepage": "https://github.com/npm/hosted-git-info", + "scripts": { + "posttest": "npm run lint", + "snap": "tap", + "test": "tap", + "test:coverage": "tap --coverage-report=html", + "lint": "npm run eslint", + "postlint": "template-oss-check", + "lintfix": "npm run eslint -- --fix", + "template-oss-apply": "template-oss-apply --force", + "eslint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"" + }, + "dependencies": { + "lru-cache": "^10.0.1" + }, + "devDependencies": { + "@npmcli/eslint-config": "^5.0.0", + "@npmcli/template-oss": "4.23.3", + "tap": "^16.0.1" + }, + "files": [ + "bin/", + "lib/" + ], + "engines": { + "node": "^18.17.0 || >=20.5.0" + }, + "tap": { + "color": 1, + "coverage": true, + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] + }, + "templateOSS": { + "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", + "version": "4.23.3", + "publish": "true" + } +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/ini/LICENSE b/node_modules/@npmcli/map-workspaces/node_modules/ini/LICENSE new file mode 100644 index 0000000000000..19129e315fe59 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/ini/LICENSE @@ -0,0 +1,15 @@ +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/node_modules/@npmcli/map-workspaces/node_modules/ini/lib/ini.js b/node_modules/@npmcli/map-workspaces/node_modules/ini/lib/ini.js new file mode 100644 index 0000000000000..beb390d0b0ee2 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/ini/lib/ini.js @@ -0,0 +1,280 @@ +const { hasOwnProperty } = Object.prototype + +const encode = (obj, opt = {}) => { + if (typeof opt === 'string') { + opt = { section: opt } + } + opt.align = opt.align === true + 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 || (typeof process !== 'undefined' && process.platform) + opt.bracketedArray = opt.bracketedArray !== false + + /* istanbul ignore next */ + const eol = opt.platform === 'win32' ? '\r\n' : '\n' + const separator = opt.whitespace ? ' = ' : '=' + const children = [] + + const keys = opt.sort ? Object.keys(obj).sort() : Object.keys(obj) + + let padToChars = 0 + // If aligning on the separator, then padToChars is determined as follows: + // 1. Get the keys + // 2. Exclude keys pointing to objects unless the value is null or an array + // 3. Add `[]` to array keys + // 4. Ensure non empty set of keys + // 5. Reduce the set to the longest `safe` key + // 6. Get the `safe` length + if (opt.align) { + padToChars = safe( + ( + keys + .filter(k => obj[k] === null || Array.isArray(obj[k]) || typeof obj[k] !== 'object') + .map(k => Array.isArray(obj[k]) ? `${k}[]` : k) + ) + .concat(['']) + .reduce((a, b) => safe(a).length >= safe(b).length ? a : b) + ).length + } + + let out = '' + const arraySuffix = opt.bracketedArray ? '[]' : '' + + for (const k of keys) { + const val = obj[k] + if (val && Array.isArray(val)) { + for (const item of val) { + out += safe(`${k}${arraySuffix}`).padEnd(padToChars, ' ') + separator + safe(item) + eol + } + } else if (val && typeof val === 'object') { + children.push(k) + } else { + out += safe(k).padEnd(padToChars, ' ') + separator + safe(val) + eol + } + } + + if (opt.section && out.length) { + out = '[' + safe(opt.section) + ']' + (opt.newline ? eol + eol : eol) + out + } + + for (const k of children) { + const nk = splitSections(k, '.').join('\\.') + const section = (opt.section ? opt.section + '.' : '') + nk + const child = encode(obj[k], { + ...opt, + section, + }) + if (out.length && child.length) { + out += eol + } + + out += child + } + + return out +} + +function splitSections (str, separator) { + var lastMatchIndex = 0 + var lastSeparatorIndex = 0 + var nextIndex = 0 + var sections = [] + + do { + nextIndex = str.indexOf(separator, lastMatchIndex) + + if (nextIndex !== -1) { + lastMatchIndex = nextIndex + separator.length + + if (nextIndex > 0 && str[nextIndex - 1] === '\\') { + continue + } + + sections.push(str.slice(lastSeparatorIndex, nextIndex)) + lastSeparatorIndex = nextIndex + separator.length + } + } while (nextIndex !== -1) + + sections.push(str.slice(lastSeparatorIndex)) + + return sections +} + +const decode = (str, opt = {}) => { + opt.bracketedArray = opt.bracketedArray !== false + const out = Object.create(null) + let p = out + let section = null + // section |key = value + const re = /^\[([^\]]*)\]\s*$|^([^=]+)(=(.*))?$/i + const lines = str.split(/[\r\n]+/g) + const duplicates = {} + + for (const line of lines) { + if (!line || line.match(/^\s*[;#]/) || line.match(/^\s*$/)) { + continue + } + const match = line.match(re) + if (!match) { + continue + } + if (match[1] !== undefined) { + section = unsafe(match[1]) + if (section === '__proto__') { + // not allowed + // keep parsing the section, but don't attach it. + p = Object.create(null) + continue + } + p = out[section] = out[section] || Object.create(null) + continue + } + const keyRaw = unsafe(match[2]) + let isArray + if (opt.bracketedArray) { + isArray = keyRaw.length > 2 && keyRaw.slice(-2) === '[]' + } else { + duplicates[keyRaw] = (duplicates?.[keyRaw] || 0) + 1 + isArray = duplicates[keyRaw] > 1 + } + const key = isArray && keyRaw.endsWith('[]') + ? keyRaw.slice(0, -2) : keyRaw + + if (key === '__proto__') { + continue + } + const valueRaw = match[3] ? unsafe(match[4]) : true + const value = valueRaw === 'true' || + valueRaw === 'false' || + valueRaw === 'null' ? JSON.parse(valueRaw) + : valueRaw + + // Convert keys with '[]' suffix to an array + if (isArray) { + if (!hasOwnProperty.call(p, key)) { + p[key] = [] + } else if (!Array.isArray(p[key])) { + p[key] = [p[key]] + } + } + + // safeguard against resetting a previously defined + // array by accidentally forgetting the brackets + if (Array.isArray(p[key])) { + p[key].push(value) + } else { + p[key] = value + } + } + + // {a:{y:1},"a.b":{x:2}} --> {a:{y:1,b:{x:2}}} + // use a filter to return the keys that have to be deleted. + const remove = [] + for (const k of Object.keys(out)) { + if (!hasOwnProperty.call(out, k) || + typeof out[k] !== 'object' || + Array.isArray(out[k])) { + continue + } + + // see if the parent section is also an object. + // if so, add it to that, and mark this one for deletion + const parts = splitSections(k, '.') + p = out + const l = parts.pop() + const nl = l.replace(/\\\./g, '.') + for (const part of parts) { + if (part === '__proto__') { + continue + } + if (!hasOwnProperty.call(p, part) || typeof p[part] !== 'object') { + p[part] = Object.create(null) + } + p = p[part] + } + if (p === out && nl === l) { + continue + } + + p[nl] = out[k] + remove.push(k) + } + for (const del of remove) { + delete out[del] + } + + return out +} + +const isQuoted = val => { + return (val.startsWith('"') && val.endsWith('"')) || + (val.startsWith("'") && val.endsWith("'")) +} + +const safe = val => { + if ( + typeof val !== 'string' || + val.match(/[=\r\n]/) || + val.match(/^\[/) || + (val.length > 1 && isQuoted(val)) || + val !== val.trim() + ) { + return JSON.stringify(val) + } + return val.split(';').join('\\;').split('#').join('\\#') +} + +const unsafe = val => { + val = (val || '').trim() + if (isQuoted(val)) { + // remove the single quotes before calling JSON.parse + if (val.charAt(0) === "'") { + val = val.slice(1, -1) + } + try { + val = JSON.parse(val) + } catch { + // ignore errors + } + } else { + // walk the val to find the first not-escaped ; character + let esc = false + let unesc = '' + for (let i = 0, l = val.length; i < l; i++) { + const c = val.charAt(i) + if (esc) { + if ('\\;#'.indexOf(c) !== -1) { + unesc += c + } else { + unesc += '\\' + c + } + + esc = false + } else if (';#'.indexOf(c) !== -1) { + break + } else if (c === '\\') { + esc = true + } else { + unesc += c + } + } + if (esc) { + unesc += '\\' + } + + return unesc.trim() + } + return val +} + +module.exports = { + parse: decode, + decode, + stringify: encode, + encode, + safe, + unsafe, +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/ini/package.json b/node_modules/@npmcli/map-workspaces/node_modules/ini/package.json new file mode 100644 index 0000000000000..6a3995f158cc5 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/ini/package.json @@ -0,0 +1,45 @@ +{ + "author": "GitHub Inc.", + "name": "ini", + "description": "An ini encoder/decoder for node", + "version": "5.0.0", + "repository": { + "type": "git", + "url": "git+https://github.com/npm/ini.git" + }, + "main": "lib/ini.js", + "scripts": { + "eslint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"", + "lint": "npm run eslint", + "lintfix": "npm run eslint -- --fix", + "test": "tap", + "snap": "tap", + "posttest": "npm run lint", + "postlint": "template-oss-check", + "template-oss-apply": "template-oss-apply --force" + }, + "devDependencies": { + "@npmcli/eslint-config": "^5.0.0", + "@npmcli/template-oss": "4.23.3", + "tap": "^16.0.1" + }, + "license": "ISC", + "files": [ + "bin/", + "lib/" + ], + "engines": { + "node": "^18.17.0 || >=20.5.0" + }, + "templateOSS": { + "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", + "version": "4.23.3", + "publish": "true" + }, + "tap": { + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] + } +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/isexe/LICENSE b/node_modules/@npmcli/map-workspaces/node_modules/isexe/LICENSE new file mode 100644 index 0000000000000..c925dbe826b67 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/isexe/LICENSE @@ -0,0 +1,15 @@ +The ISC License + +Copyright (c) 2016-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/@npmcli/map-workspaces/node_modules/isexe/dist/cjs/index.js b/node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/cjs/index.js new file mode 100644 index 0000000000000..cefcb66b5c543 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/cjs/index.js @@ -0,0 +1,46 @@ +"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 __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.sync = exports.isexe = exports.posix = exports.win32 = void 0; +const posix = __importStar(require("./posix.js")); +exports.posix = posix; +const win32 = __importStar(require("./win32.js")); +exports.win32 = win32; +__exportStar(require("./options.js"), exports); +const platform = process.env._ISEXE_TEST_PLATFORM_ || process.platform; +const impl = platform === 'win32' ? win32 : posix; +/** + * Determine whether a path is executable on the current platform. + */ +exports.isexe = impl.isexe; +/** + * Synchronously determine whether a path is executable on the + * current platform. + */ +exports.sync = impl.sync; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/cjs/options.js b/node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/cjs/options.js new file mode 100644 index 0000000000000..0dfad0762cc32 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/cjs/options.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=options.js.map \ No newline at end of file diff --git a/node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/cjs/package.json b/node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/cjs/package.json new file mode 100644 index 0000000000000..5bbefffbabee3 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/cjs/package.json @@ -0,0 +1,3 @@ +{ + "type": "commonjs" +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/cjs/posix.js b/node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/cjs/posix.js new file mode 100644 index 0000000000000..3bc5e79d7007e --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/cjs/posix.js @@ -0,0 +1,67 @@ +"use strict"; +/** + * This is the Posix implementation of isexe, which uses the file + * mode and uid/gid values. + * + * @module + */ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.sync = exports.isexe = void 0; +const fs_1 = require("fs"); +const promises_1 = require("fs/promises"); +/** + * Determine whether a path is executable according to the mode and + * current (or specified) user and group IDs. + */ +const isexe = async (path, options = {}) => { + const { ignoreErrors = false } = options; + try { + return checkStat(await (0, promises_1.stat)(path), options); + } + catch (e) { + const er = e; + if (ignoreErrors || er.code === 'EACCES') + return false; + throw er; + } +}; +exports.isexe = isexe; +/** + * Synchronously determine whether a path is executable according to + * the mode and current (or specified) user and group IDs. + */ +const sync = (path, options = {}) => { + const { ignoreErrors = false } = options; + try { + return checkStat((0, fs_1.statSync)(path), options); + } + catch (e) { + const er = e; + if (ignoreErrors || er.code === 'EACCES') + return false; + throw er; + } +}; +exports.sync = sync; +const checkStat = (stat, options) => stat.isFile() && checkMode(stat, options); +const checkMode = (stat, options) => { + const myUid = options.uid ?? process.getuid?.(); + const myGroups = options.groups ?? process.getgroups?.() ?? []; + const myGid = options.gid ?? process.getgid?.() ?? myGroups[0]; + if (myUid === undefined || myGid === undefined) { + throw new Error('cannot get uid or gid'); + } + const groups = new Set([myGid, ...myGroups]); + const mod = stat.mode; + const uid = stat.uid; + const gid = stat.gid; + const u = parseInt('100', 8); + const g = parseInt('010', 8); + const o = parseInt('001', 8); + const ug = u | g; + return !!(mod & o || + (mod & g && groups.has(gid)) || + (mod & u && uid === myUid) || + (mod & ug && myUid === 0)); +}; +//# sourceMappingURL=posix.js.map \ No newline at end of file diff --git a/node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/cjs/win32.js b/node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/cjs/win32.js new file mode 100644 index 0000000000000..fa7a4d2f7d240 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/cjs/win32.js @@ -0,0 +1,62 @@ +"use strict"; +/** + * This is the Windows implementation of isexe, which uses the file + * extension and PATHEXT setting. + * + * @module + */ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.sync = exports.isexe = void 0; +const fs_1 = require("fs"); +const promises_1 = require("fs/promises"); +/** + * Determine whether a path is executable based on the file extension + * and PATHEXT environment variable (or specified pathExt option) + */ +const isexe = async (path, options = {}) => { + const { ignoreErrors = false } = options; + try { + return checkStat(await (0, promises_1.stat)(path), path, options); + } + catch (e) { + const er = e; + if (ignoreErrors || er.code === 'EACCES') + return false; + throw er; + } +}; +exports.isexe = isexe; +/** + * Synchronously determine whether a path is executable based on the file + * extension and PATHEXT environment variable (or specified pathExt option) + */ +const sync = (path, options = {}) => { + const { ignoreErrors = false } = options; + try { + return checkStat((0, fs_1.statSync)(path), path, options); + } + catch (e) { + const er = e; + if (ignoreErrors || er.code === 'EACCES') + return false; + throw er; + } +}; +exports.sync = sync; +const checkPathExt = (path, options) => { + const { pathExt = process.env.PATHEXT || '' } = options; + const peSplit = pathExt.split(';'); + if (peSplit.indexOf('') !== -1) { + return true; + } + for (let i = 0; i < peSplit.length; i++) { + const p = peSplit[i].toLowerCase(); + const ext = path.substring(path.length - p.length).toLowerCase(); + if (p && ext === p) { + return true; + } + } + return false; +}; +const checkStat = (stat, path, options) => stat.isFile() && checkPathExt(path, options); +//# sourceMappingURL=win32.js.map \ No newline at end of file diff --git a/node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/mjs/index.js b/node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/mjs/index.js new file mode 100644 index 0000000000000..1e309acd7355e --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/mjs/index.js @@ -0,0 +1,16 @@ +import * as posix from './posix.js'; +import * as win32 from './win32.js'; +export * from './options.js'; +export { win32, posix }; +const platform = process.env._ISEXE_TEST_PLATFORM_ || process.platform; +const impl = platform === 'win32' ? win32 : posix; +/** + * Determine whether a path is executable on the current platform. + */ +export const isexe = impl.isexe; +/** + * Synchronously determine whether a path is executable on the + * current platform. + */ +export const sync = impl.sync; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/mjs/options.js b/node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/mjs/options.js new file mode 100644 index 0000000000000..e9ded40bd5b2c --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/mjs/options.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=options.js.map \ No newline at end of file diff --git a/node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/mjs/package.json b/node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/mjs/package.json new file mode 100644 index 0000000000000..3dbc1ca591c05 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/mjs/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/mjs/posix.js b/node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/mjs/posix.js new file mode 100644 index 0000000000000..c453776c0452f --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/mjs/posix.js @@ -0,0 +1,62 @@ +/** + * This is the Posix implementation of isexe, which uses the file + * mode and uid/gid values. + * + * @module + */ +import { statSync } from 'fs'; +import { stat } from 'fs/promises'; +/** + * Determine whether a path is executable according to the mode and + * current (or specified) user and group IDs. + */ +export const isexe = async (path, options = {}) => { + const { ignoreErrors = false } = options; + try { + return checkStat(await stat(path), options); + } + catch (e) { + const er = e; + if (ignoreErrors || er.code === 'EACCES') + return false; + throw er; + } +}; +/** + * Synchronously determine whether a path is executable according to + * the mode and current (or specified) user and group IDs. + */ +export const sync = (path, options = {}) => { + const { ignoreErrors = false } = options; + try { + return checkStat(statSync(path), options); + } + catch (e) { + const er = e; + if (ignoreErrors || er.code === 'EACCES') + return false; + throw er; + } +}; +const checkStat = (stat, options) => stat.isFile() && checkMode(stat, options); +const checkMode = (stat, options) => { + const myUid = options.uid ?? process.getuid?.(); + const myGroups = options.groups ?? process.getgroups?.() ?? []; + const myGid = options.gid ?? process.getgid?.() ?? myGroups[0]; + if (myUid === undefined || myGid === undefined) { + throw new Error('cannot get uid or gid'); + } + const groups = new Set([myGid, ...myGroups]); + const mod = stat.mode; + const uid = stat.uid; + const gid = stat.gid; + const u = parseInt('100', 8); + const g = parseInt('010', 8); + const o = parseInt('001', 8); + const ug = u | g; + return !!(mod & o || + (mod & g && groups.has(gid)) || + (mod & u && uid === myUid) || + (mod & ug && myUid === 0)); +}; +//# sourceMappingURL=posix.js.map \ No newline at end of file diff --git a/node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/mjs/win32.js b/node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/mjs/win32.js new file mode 100644 index 0000000000000..a354ee2a5115c --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/isexe/dist/mjs/win32.js @@ -0,0 +1,57 @@ +/** + * This is the Windows implementation of isexe, which uses the file + * extension and PATHEXT setting. + * + * @module + */ +import { statSync } from 'fs'; +import { stat } from 'fs/promises'; +/** + * Determine whether a path is executable based on the file extension + * and PATHEXT environment variable (or specified pathExt option) + */ +export const isexe = async (path, options = {}) => { + const { ignoreErrors = false } = options; + try { + return checkStat(await stat(path), path, options); + } + catch (e) { + const er = e; + if (ignoreErrors || er.code === 'EACCES') + return false; + throw er; + } +}; +/** + * Synchronously determine whether a path is executable based on the file + * extension and PATHEXT environment variable (or specified pathExt option) + */ +export const sync = (path, options = {}) => { + const { ignoreErrors = false } = options; + try { + return checkStat(statSync(path), path, options); + } + catch (e) { + const er = e; + if (ignoreErrors || er.code === 'EACCES') + return false; + throw er; + } +}; +const checkPathExt = (path, options) => { + const { pathExt = process.env.PATHEXT || '' } = options; + const peSplit = pathExt.split(';'); + if (peSplit.indexOf('') !== -1) { + return true; + } + for (let i = 0; i < peSplit.length; i++) { + const p = peSplit[i].toLowerCase(); + const ext = path.substring(path.length - p.length).toLowerCase(); + if (p && ext === p) { + return true; + } + } + return false; +}; +const checkStat = (stat, path, options) => stat.isFile() && checkPathExt(path, options); +//# sourceMappingURL=win32.js.map \ No newline at end of file diff --git a/node_modules/@npmcli/map-workspaces/node_modules/isexe/package.json b/node_modules/@npmcli/map-workspaces/node_modules/isexe/package.json new file mode 100644 index 0000000000000..a0e2cd04bfdbf --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/isexe/package.json @@ -0,0 +1,96 @@ +{ + "name": "isexe", + "version": "3.1.1", + "description": "Minimal module to check if a file is executable.", + "main": "./dist/cjs/index.js", + "module": "./dist/mjs/index.js", + "types": "./dist/cjs/index.js", + "files": [ + "dist" + ], + "exports": { + ".": { + "import": { + "types": "./dist/mjs/index.d.ts", + "default": "./dist/mjs/index.js" + }, + "require": { + "types": "./dist/cjs/index.d.ts", + "default": "./dist/cjs/index.js" + } + }, + "./posix": { + "import": { + "types": "./dist/mjs/posix.d.ts", + "default": "./dist/mjs/posix.js" + }, + "require": { + "types": "./dist/cjs/posix.d.ts", + "default": "./dist/cjs/posix.js" + } + }, + "./win32": { + "import": { + "types": "./dist/mjs/win32.d.ts", + "default": "./dist/mjs/win32.js" + }, + "require": { + "types": "./dist/cjs/win32.d.ts", + "default": "./dist/cjs/win32.js" + } + }, + "./package.json": "./package.json" + }, + "devDependencies": { + "@types/node": "^20.4.5", + "@types/tap": "^15.0.8", + "c8": "^8.0.1", + "mkdirp": "^0.5.1", + "prettier": "^2.8.8", + "rimraf": "^2.5.0", + "sync-content": "^1.0.2", + "tap": "^16.3.8", + "ts-node": "^10.9.1", + "typedoc": "^0.24.8", + "typescript": "^5.1.6" + }, + "scripts": { + "preversion": "npm test", + "postversion": "npm publish", + "prepublishOnly": "git push origin --follow-tags", + "prepare": "tsc -p tsconfig/cjs.json && tsc -p tsconfig/esm.json && bash ./scripts/fixup.sh", + "pretest": "npm run prepare", + "presnap": "npm run prepare", + "test": "c8 tap", + "snap": "c8 tap", + "format": "prettier --write . --loglevel warn --ignore-path ../../.prettierignore --cache", + "typedoc": "typedoc --tsconfig tsconfig/esm.json ./src/*.ts" + }, + "author": "Isaac Z. Schlueter (http://blog.izs.me/)", + "license": "ISC", + "tap": { + "coverage": false, + "node-arg": [ + "--enable-source-maps", + "--no-warnings", + "--loader", + "ts-node/esm" + ], + "ts": false + }, + "prettier": { + "semi": false, + "printWidth": 75, + "tabWidth": 2, + "useTabs": false, + "singleQuote": true, + "jsxSingleQuote": false, + "bracketSameLine": true, + "arrowParens": "avoid", + "endOfLine": "lf" + }, + "repository": "https://github.com/isaacs/isexe", + "engines": { + "node": ">=16" + } +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/json-parse-even-better-errors/LICENSE.md b/node_modules/@npmcli/map-workspaces/node_modules/json-parse-even-better-errors/LICENSE.md new file mode 100644 index 0000000000000..6991b7cbb89db --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/json-parse-even-better-errors/LICENSE.md @@ -0,0 +1,25 @@ +Copyright 2017 Kat Marchán +Copyright 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. + +--- + +This library is a fork of 'better-json-errors' by Kat Marchán, extended and +distributed under the terms of the MIT license above. diff --git a/node_modules/@npmcli/map-workspaces/node_modules/json-parse-even-better-errors/lib/index.js b/node_modules/@npmcli/map-workspaces/node_modules/json-parse-even-better-errors/lib/index.js new file mode 100644 index 0000000000000..3ffdaac96d2dc --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/json-parse-even-better-errors/lib/index.js @@ -0,0 +1,137 @@ +'use strict' + +const INDENT = Symbol.for('indent') +const NEWLINE = Symbol.for('newline') + +const DEFAULT_NEWLINE = '\n' +const DEFAULT_INDENT = ' ' +const BOM = /^\uFEFF/ + +// only respect indentation if we got a line break, otherwise squash it +// things other than objects and arrays aren't indented, so ignore those +// Important: in both of these regexps, the $1 capture group is the newline +// or undefined, and the $2 capture group is the indent, or undefined. +const FORMAT = /^\s*[{[]((?:\r?\n)+)([\s\t]*)/ +const EMPTY = /^(?:\{\}|\[\])((?:\r?\n)+)?$/ + +// Node 20 puts single quotes around the token and a comma after it +const UNEXPECTED_TOKEN = /^Unexpected token '?(.)'?(,)? /i + +const hexify = (char) => { + const h = char.charCodeAt(0).toString(16).toUpperCase() + return `0x${h.length % 2 ? '0' : ''}${h}` +} + +// Remove byte order marker. This catches EF BB BF (the UTF-8 BOM) +// because the buffer-to-string conversion in `fs.readFileSync()` +// translates it to FEFF, the UTF-16 BOM. +const stripBOM = (txt) => String(txt).replace(BOM, '') + +const makeParsedError = (msg, parsing, position = 0) => ({ + message: `${msg} while parsing ${parsing}`, + position, +}) + +const parseError = (e, txt, context = 20) => { + let msg = e.message + + if (!txt) { + return makeParsedError(msg, 'empty string') + } + + const badTokenMatch = msg.match(UNEXPECTED_TOKEN) + const badIndexMatch = msg.match(/ position\s+(\d+)/i) + + if (badTokenMatch) { + msg = msg.replace( + UNEXPECTED_TOKEN, + `Unexpected token ${JSON.stringify(badTokenMatch[1])} (${hexify(badTokenMatch[1])})$2 ` + ) + } + + let errIdx + if (badIndexMatch) { + errIdx = +badIndexMatch[1] + } else /* istanbul ignore next - doesnt happen in Node 22 */ if ( + msg.match(/^Unexpected end of JSON.*/i) + ) { + errIdx = txt.length - 1 + } + + if (errIdx == null) { + return makeParsedError(msg, `'${txt.slice(0, context * 2)}'`) + } + + const start = errIdx <= context ? 0 : errIdx - context + const end = errIdx + context >= txt.length ? txt.length : errIdx + context + const slice = `${start ? '...' : ''}${txt.slice(start, end)}${end === txt.length ? '' : '...'}` + + return makeParsedError( + msg, + `${txt === slice ? '' : 'near '}${JSON.stringify(slice)}`, + errIdx + ) +} + +class JSONParseError extends SyntaxError { + constructor (er, txt, context, caller) { + const metadata = parseError(er, txt, context) + super(metadata.message) + Object.assign(this, metadata) + this.code = 'EJSONPARSE' + this.systemError = er + Error.captureStackTrace(this, caller || this.constructor) + } + + get name () { + return this.constructor.name + } + + set name (n) {} + + get [Symbol.toStringTag] () { + return this.constructor.name + } +} + +const parseJson = (txt, reviver) => { + const result = JSON.parse(txt, reviver) + if (result && typeof result === 'object') { + // get the indentation so that we can save it back nicely + // if the file starts with {" then we have an indent of '', ie, none + // otherwise, pick the indentation of the next line after the first \n If the + // pattern doesn't match, then it means no indentation. JSON.stringify ignores + // symbols, so this is reasonably safe. if the string is '{}' or '[]', then + // use the default 2-space indent. + const match = txt.match(EMPTY) || txt.match(FORMAT) || [null, '', ''] + result[NEWLINE] = match[1] ?? DEFAULT_NEWLINE + result[INDENT] = match[2] ?? DEFAULT_INDENT + } + return result +} + +const parseJsonError = (raw, reviver, context) => { + const txt = stripBOM(raw) + try { + return parseJson(txt, reviver) + } catch (e) { + if (typeof raw !== 'string' && !Buffer.isBuffer(raw)) { + const msg = Array.isArray(raw) && raw.length === 0 ? 'an empty array' : String(raw) + throw Object.assign( + new TypeError(`Cannot parse ${msg}`), + { code: 'EJSONPARSE', systemError: e } + ) + } + throw new JSONParseError(e, txt, context, parseJsonError) + } +} + +module.exports = parseJsonError +parseJsonError.JSONParseError = JSONParseError +parseJsonError.noExceptions = (raw, reviver) => { + try { + return parseJson(stripBOM(raw), reviver) + } catch { + // no exceptions + } +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/json-parse-even-better-errors/package.json b/node_modules/@npmcli/map-workspaces/node_modules/json-parse-even-better-errors/package.json new file mode 100644 index 0000000000000..193f0d9d459a5 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/json-parse-even-better-errors/package.json @@ -0,0 +1,50 @@ +{ + "name": "json-parse-even-better-errors", + "version": "4.0.0", + "description": "JSON.parse with context information on error", + "main": "lib/index.js", + "files": [ + "bin/", + "lib/" + ], + "scripts": { + "test": "tap", + "snap": "tap", + "lint": "npm run eslint", + "postlint": "template-oss-check", + "template-oss-apply": "template-oss-apply --force", + "lintfix": "npm run eslint -- --fix", + "posttest": "npm run lint", + "eslint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/npm/json-parse-even-better-errors.git" + }, + "keywords": [ + "JSON", + "parser" + ], + "author": "GitHub Inc.", + "license": "MIT", + "devDependencies": { + "@npmcli/eslint-config": "^5.0.0", + "@npmcli/template-oss": "4.23.3", + "tap": "^16.3.0" + }, + "tap": { + "check-coverage": true, + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + }, + "templateOSS": { + "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", + "version": "4.23.3", + "publish": true + } +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/LICENSE b/node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/LICENSE new file mode 100644 index 0000000000000..19d1364a8ac08 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/LICENSE @@ -0,0 +1,15 @@ +This package contains code originally written by Isaac Z. Schlueter. +Used with permission. + +Copyright (c) Meryn Stol ("Author") +All rights reserved. + +The BSD License + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/lib/extract_description.js b/node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/lib/extract_description.js new file mode 100644 index 0000000000000..631966b5f29af --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/lib/extract_description.js @@ -0,0 +1,24 @@ +module.exports = extractDescription + +// Extracts description from contents of a readme file in markdown format +function extractDescription (d) { + if (!d) { + return + } + if (d === 'ERROR: No README data found!') { + return + } + // the first block of text before the first heading + // that isn't the first line heading + d = d.trim().split('\n') + let s = 0 + while (d[s] && d[s].trim().match(/^(#|$)/)) { + s++ + } + const l = d.length + let e = s + 1 + while (e < l && d[e].trim()) { + e++ + } + return d.slice(s, e).join(' ').trim() +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/lib/fixer.js b/node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/lib/fixer.js new file mode 100644 index 0000000000000..1c30cad65e6cb --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/lib/fixer.js @@ -0,0 +1,475 @@ +var isValidSemver = require('semver/functions/valid') +var cleanSemver = require('semver/functions/clean') +var validateLicense = require('validate-npm-package-license') +var hostedGitInfo = require('hosted-git-info') +var moduleBuiltin = require('node:module') +var depTypes = ['dependencies', 'devDependencies', 'optionalDependencies'] +var extractDescription = require('./extract_description') +var url = require('url') +var typos = require('./typos.json') + +var isEmail = str => str.includes('@') && (str.indexOf('@') < str.lastIndexOf('.')) + +module.exports = { + // default warning function + warn: function () {}, + + fixRepositoryField: function (data) { + if (data.repositories) { + this.warn('repositories') + data.repository = data.repositories[0] + } + if (!data.repository) { + return this.warn('missingRepository') + } + if (typeof data.repository === 'string') { + data.repository = { + type: 'git', + url: data.repository, + } + } + var r = data.repository.url || '' + if (r) { + var hosted = hostedGitInfo.fromUrl(r) + if (hosted) { + r = data.repository.url + = hosted.getDefaultRepresentation() === 'shortcut' ? hosted.https() : hosted.toString() + } + } + + if (r.match(/github.com\/[^/]+\/[^/]+\.git\.git$/)) { + this.warn('brokenGitUrl', r) + } + }, + + fixTypos: function (data) { + Object.keys(typos.topLevel).forEach(function (d) { + if (Object.prototype.hasOwnProperty.call(data, d)) { + this.warn('typo', d, typos.topLevel[d]) + } + }, this) + }, + + fixScriptsField: function (data) { + if (!data.scripts) { + return + } + if (typeof data.scripts !== 'object') { + this.warn('nonObjectScripts') + delete data.scripts + return + } + Object.keys(data.scripts).forEach(function (k) { + if (typeof data.scripts[k] !== 'string') { + this.warn('nonStringScript') + delete data.scripts[k] + } else if (typos.script[k] && !data.scripts[typos.script[k]]) { + this.warn('typo', k, typos.script[k], 'scripts') + } + }, this) + }, + + fixFilesField: function (data) { + var files = data.files + if (files && !Array.isArray(files)) { + this.warn('nonArrayFiles') + delete data.files + } else if (data.files) { + data.files = data.files.filter(function (file) { + if (!file || typeof file !== 'string') { + this.warn('invalidFilename', file) + return false + } else { + return true + } + }, this) + } + }, + + fixBinField: function (data) { + if (!data.bin) { + return + } + if (typeof data.bin === 'string') { + var b = {} + var match + if (match = data.name.match(/^@[^/]+[/](.*)$/)) { + b[match[1]] = data.bin + } else { + b[data.name] = data.bin + } + data.bin = b + } + }, + + fixManField: function (data) { + if (!data.man) { + return + } + if (typeof data.man === 'string') { + data.man = [data.man] + } + }, + fixBundleDependenciesField: function (data) { + var bdd = 'bundledDependencies' + var bd = 'bundleDependencies' + if (data[bdd] && !data[bd]) { + data[bd] = data[bdd] + delete data[bdd] + } + if (data[bd] && !Array.isArray(data[bd])) { + this.warn('nonArrayBundleDependencies') + delete data[bd] + } else if (data[bd]) { + data[bd] = data[bd].filter(function (filtered) { + if (!filtered || typeof filtered !== 'string') { + this.warn('nonStringBundleDependency', filtered) + return false + } else { + if (!data.dependencies) { + data.dependencies = {} + } + if (!Object.prototype.hasOwnProperty.call(data.dependencies, filtered)) { + this.warn('nonDependencyBundleDependency', filtered) + data.dependencies[filtered] = '*' + } + return true + } + }, this) + } + }, + + fixDependencies: function (data) { + objectifyDeps(data, this.warn) + addOptionalDepsToDeps(data, this.warn) + this.fixBundleDependenciesField(data) + + ;['dependencies', 'devDependencies'].forEach(function (deps) { + if (!(deps in data)) { + return + } + if (!data[deps] || typeof data[deps] !== 'object') { + this.warn('nonObjectDependencies', deps) + delete data[deps] + return + } + Object.keys(data[deps]).forEach(function (d) { + var r = data[deps][d] + if (typeof r !== 'string') { + this.warn('nonStringDependency', d, JSON.stringify(r)) + delete data[deps][d] + } + var hosted = hostedGitInfo.fromUrl(data[deps][d]) + if (hosted) { + data[deps][d] = hosted.toString() + } + }, this) + }, this) + }, + + fixModulesField: function (data) { + if (data.modules) { + this.warn('deprecatedModules') + delete data.modules + } + }, + + fixKeywordsField: function (data) { + if (typeof data.keywords === 'string') { + data.keywords = data.keywords.split(/,\s+/) + } + if (data.keywords && !Array.isArray(data.keywords)) { + delete data.keywords + this.warn('nonArrayKeywords') + } else if (data.keywords) { + data.keywords = data.keywords.filter(function (kw) { + if (typeof kw !== 'string' || !kw) { + this.warn('nonStringKeyword') + return false + } else { + return true + } + }, this) + } + }, + + fixVersionField: function (data, strict) { + // allow "loose" semver 1.0 versions in non-strict mode + // enforce strict semver 2.0 compliance in strict mode + var loose = !strict + if (!data.version) { + data.version = '' + return true + } + if (!isValidSemver(data.version, loose)) { + throw new Error('Invalid version: "' + data.version + '"') + } + data.version = cleanSemver(data.version, loose) + return true + }, + + fixPeople: function (data) { + modifyPeople(data, unParsePerson) + modifyPeople(data, parsePerson) + }, + + fixNameField: function (data, options) { + if (typeof options === 'boolean') { + options = { strict: options } + } else if (typeof options === 'undefined') { + options = {} + } + var strict = options.strict + if (!data.name && !strict) { + data.name = '' + return + } + if (typeof data.name !== 'string') { + throw new Error('name field must be a string.') + } + if (!strict) { + data.name = data.name.trim() + } + ensureValidName(data.name, strict, options.allowLegacyCase) + if (moduleBuiltin.builtinModules.includes(data.name)) { + this.warn('conflictingName', data.name) + } + }, + + fixDescriptionField: function (data) { + if (data.description && typeof data.description !== 'string') { + this.warn('nonStringDescription') + delete data.description + } + if (data.readme && !data.description) { + data.description = extractDescription(data.readme) + } + if (data.description === undefined) { + delete data.description + } + if (!data.description) { + this.warn('missingDescription') + } + }, + + fixReadmeField: function (data) { + if (!data.readme) { + this.warn('missingReadme') + data.readme = 'ERROR: No README data found!' + } + }, + + fixBugsField: function (data) { + if (!data.bugs && data.repository && data.repository.url) { + var hosted = hostedGitInfo.fromUrl(data.repository.url) + if (hosted && hosted.bugs()) { + data.bugs = { url: hosted.bugs() } + } + } else if (data.bugs) { + if (typeof data.bugs === 'string') { + if (isEmail(data.bugs)) { + data.bugs = { email: data.bugs } + /* eslint-disable-next-line node/no-deprecated-api */ + } else if (url.parse(data.bugs).protocol) { + data.bugs = { url: data.bugs } + } else { + this.warn('nonEmailUrlBugsString') + } + } else { + bugsTypos(data.bugs, this.warn) + var oldBugs = data.bugs + data.bugs = {} + if (oldBugs.url) { + /* eslint-disable-next-line node/no-deprecated-api */ + if (typeof (oldBugs.url) === 'string' && url.parse(oldBugs.url).protocol) { + data.bugs.url = oldBugs.url + } else { + this.warn('nonUrlBugsUrlField') + } + } + if (oldBugs.email) { + if (typeof (oldBugs.email) === 'string' && isEmail(oldBugs.email)) { + data.bugs.email = oldBugs.email + } else { + this.warn('nonEmailBugsEmailField') + } + } + } + if (!data.bugs.email && !data.bugs.url) { + delete data.bugs + this.warn('emptyNormalizedBugs') + } + } + }, + + fixHomepageField: function (data) { + if (!data.homepage && data.repository && data.repository.url) { + var hosted = hostedGitInfo.fromUrl(data.repository.url) + if (hosted && hosted.docs()) { + data.homepage = hosted.docs() + } + } + if (!data.homepage) { + return + } + + if (typeof data.homepage !== 'string') { + this.warn('nonUrlHomepage') + return delete data.homepage + } + /* eslint-disable-next-line node/no-deprecated-api */ + if (!url.parse(data.homepage).protocol) { + data.homepage = 'http://' + data.homepage + } + }, + + fixLicenseField: function (data) { + const license = data.license || data.licence + if (!license) { + return this.warn('missingLicense') + } + if ( + typeof (license) !== 'string' || + license.length < 1 || + license.trim() === '' + ) { + return this.warn('invalidLicense') + } + if (!validateLicense(license).validForNewPackages) { + return this.warn('invalidLicense') + } + }, +} + +function isValidScopedPackageName (spec) { + if (spec.charAt(0) !== '@') { + return false + } + + var rest = spec.slice(1).split('/') + if (rest.length !== 2) { + return false + } + + return rest[0] && rest[1] && + rest[0] === encodeURIComponent(rest[0]) && + rest[1] === encodeURIComponent(rest[1]) +} + +function isCorrectlyEncodedName (spec) { + return !spec.match(/[/@\s+%:]/) && + spec === encodeURIComponent(spec) +} + +function ensureValidName (name, strict, allowLegacyCase) { + if (name.charAt(0) === '.' || + !(isValidScopedPackageName(name) || isCorrectlyEncodedName(name)) || + (strict && (!allowLegacyCase) && name !== name.toLowerCase()) || + name.toLowerCase() === 'node_modules' || + name.toLowerCase() === 'favicon.ico') { + throw new Error('Invalid name: ' + JSON.stringify(name)) + } +} + +function modifyPeople (data, fn) { + if (data.author) { + data.author = fn(data.author) + }['maintainers', 'contributors'].forEach(function (set) { + if (!Array.isArray(data[set])) { + return + } + data[set] = data[set].map(fn) + }) + return data +} + +function unParsePerson (person) { + if (typeof person === 'string') { + return person + } + var name = person.name || '' + var u = person.url || person.web + var wrappedUrl = u ? (' (' + u + ')') : '' + var e = person.email || person.mail + var wrappedEmail = e ? (' <' + e + '>') : '' + return name + wrappedEmail + wrappedUrl +} + +function parsePerson (person) { + if (typeof person !== 'string') { + return person + } + var matchedName = person.match(/^([^(<]+)/) + var matchedUrl = person.match(/\(([^()]+)\)/) + var matchedEmail = person.match(/<([^<>]+)>/) + var obj = {} + if (matchedName && matchedName[0].trim()) { + obj.name = matchedName[0].trim() + } + if (matchedEmail) { + obj.email = matchedEmail[1] + } + if (matchedUrl) { + obj.url = matchedUrl[1] + } + return obj +} + +function addOptionalDepsToDeps (data) { + var o = data.optionalDependencies + if (!o) { + return + } + var d = data.dependencies || {} + Object.keys(o).forEach(function (k) { + d[k] = o[k] + }) + data.dependencies = d +} + +function depObjectify (deps, type, warn) { + if (!deps) { + return {} + } + if (typeof deps === 'string') { + deps = deps.trim().split(/[\n\r\s\t ,]+/) + } + if (!Array.isArray(deps)) { + return deps + } + warn('deprecatedArrayDependencies', type) + var o = {} + deps.filter(function (d) { + return typeof d === 'string' + }).forEach(function (d) { + d = d.trim().split(/(:?[@\s><=])/) + var dn = d.shift() + var dv = d.join('') + dv = dv.trim() + dv = dv.replace(/^@/, '') + o[dn] = dv + }) + return o +} + +function objectifyDeps (data, warn) { + depTypes.forEach(function (type) { + if (!data[type]) { + return + } + data[type] = depObjectify(data[type], type, warn) + }) +} + +function bugsTypos (bugs, warn) { + if (!bugs) { + return + } + Object.keys(bugs).forEach(function (k) { + if (typos.bugs[k]) { + warn('typo', k, typos.bugs[k], 'bugs') + bugs[typos.bugs[k]] = bugs[k] + delete bugs[k] + } + }) +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/lib/make_warning.js b/node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/lib/make_warning.js new file mode 100644 index 0000000000000..3be9c86539952 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/lib/make_warning.js @@ -0,0 +1,22 @@ +var util = require('util') +var messages = require('./warning_messages.json') + +module.exports = function () { + var args = Array.prototype.slice.call(arguments, 0) + var warningName = args.shift() + if (warningName === 'typo') { + return makeTypoWarning.apply(null, args) + } else { + var msgTemplate = messages[warningName] ? messages[warningName] : warningName + ": '%s'" + args.unshift(msgTemplate) + return util.format.apply(null, args) + } +} + +function makeTypoWarning (providedName, probableName, field) { + if (field) { + providedName = field + "['" + providedName + "']" + probableName = field + "['" + probableName + "']" + } + return util.format(messages.typo, providedName, probableName) +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/lib/normalize.js b/node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/lib/normalize.js new file mode 100644 index 0000000000000..e806f110315aa --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/lib/normalize.js @@ -0,0 +1,48 @@ +module.exports = normalize + +var fixer = require('./fixer') +normalize.fixer = fixer + +var makeWarning = require('./make_warning') + +var fieldsToFix = ['name', 'version', 'description', 'repository', 'modules', 'scripts', + 'files', 'bin', 'man', 'bugs', 'keywords', 'readme', 'homepage', 'license'] +var otherThingsToFix = ['dependencies', 'people', 'typos'] + +var thingsToFix = fieldsToFix.map(function (fieldName) { + return ucFirst(fieldName) + 'Field' +}) +// two ways to do this in CoffeeScript on only one line, sub-70 chars: +// thingsToFix = fieldsToFix.map (name) -> ucFirst(name) + "Field" +// thingsToFix = (ucFirst(name) + "Field" for name in fieldsToFix) +thingsToFix = thingsToFix.concat(otherThingsToFix) + +function normalize (data, warn, strict) { + if (warn === true) { + warn = null + strict = true + } + if (!strict) { + strict = false + } + if (!warn || data.private) { + warn = function () { /* noop */ } + } + + if (data.scripts && + data.scripts.install === 'node-gyp rebuild' && + !data.scripts.preinstall) { + data.gypfile = true + } + fixer.warn = function () { + warn(makeWarning.apply(null, arguments)) + } + thingsToFix.forEach(function (thingName) { + fixer['fix' + ucFirst(thingName)](data, strict) + }) + data._id = data.name + '@' + data.version +} + +function ucFirst (string) { + return string.charAt(0).toUpperCase() + string.slice(1) +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/lib/safe_format.js b/node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/lib/safe_format.js new file mode 100644 index 0000000000000..5fc888e5450cd --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/lib/safe_format.js @@ -0,0 +1,11 @@ +var util = require('util') + +module.exports = function () { + var args = Array.prototype.slice.call(arguments, 0) + args.forEach(function (arg) { + if (!arg) { + throw new TypeError('Bad arguments.') + } + }) + return util.format.apply(null, arguments) +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/lib/typos.json b/node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/lib/typos.json new file mode 100644 index 0000000000000..7f9dd283b30ff --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/lib/typos.json @@ -0,0 +1,25 @@ +{ + "topLevel": { + "dependancies": "dependencies" + ,"dependecies": "dependencies" + ,"depdenencies": "dependencies" + ,"devEependencies": "devDependencies" + ,"depends": "dependencies" + ,"dev-dependencies": "devDependencies" + ,"devDependences": "devDependencies" + ,"devDepenencies": "devDependencies" + ,"devdependencies": "devDependencies" + ,"repostitory": "repository" + ,"repo": "repository" + ,"prefereGlobal": "preferGlobal" + ,"hompage": "homepage" + ,"hampage": "homepage" + ,"autohr": "author" + ,"autor": "author" + ,"contributers": "contributors" + ,"publicationConfig": "publishConfig" + ,"script": "scripts" + }, + "bugs": { "web": "url", "name": "url" }, + "script": { "server": "start", "tests": "test" } +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/lib/warning_messages.json b/node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/lib/warning_messages.json new file mode 100644 index 0000000000000..4890f506ed965 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/lib/warning_messages.json @@ -0,0 +1,30 @@ +{ + "repositories": "'repositories' (plural) Not supported. Please pick one as the 'repository' field" + ,"missingRepository": "No repository field." + ,"brokenGitUrl": "Probably broken git url: %s" + ,"nonObjectScripts": "scripts must be an object" + ,"nonStringScript": "script values must be string commands" + ,"nonArrayFiles": "Invalid 'files' member" + ,"invalidFilename": "Invalid filename in 'files' list: %s" + ,"nonArrayBundleDependencies": "Invalid 'bundleDependencies' list. Must be array of package names" + ,"nonStringBundleDependency": "Invalid bundleDependencies member: %s" + ,"nonDependencyBundleDependency": "Non-dependency in bundleDependencies: %s" + ,"nonObjectDependencies": "%s field must be an object" + ,"nonStringDependency": "Invalid dependency: %s %s" + ,"deprecatedArrayDependencies": "specifying %s as array is deprecated" + ,"deprecatedModules": "modules field is deprecated" + ,"nonArrayKeywords": "keywords should be an array of strings" + ,"nonStringKeyword": "keywords should be an array of strings" + ,"conflictingName": "%s is also the name of a node core module." + ,"nonStringDescription": "'description' field should be a string" + ,"missingDescription": "No description" + ,"missingReadme": "No README data" + ,"missingLicense": "No license field." + ,"nonEmailUrlBugsString": "Bug string field must be url, email, or {email,url}" + ,"nonUrlBugsUrlField": "bugs.url field must be a string url. Deleted." + ,"nonEmailBugsEmailField": "bugs.email field must be a string email. Deleted." + ,"emptyNormalizedBugs": "Normalized value of bugs field is an empty object. Deleted." + ,"nonUrlHomepage": "homepage field must be a string url. Deleted." + ,"invalidLicense": "license should be a valid SPDX license expression" + ,"typo": "%s should probably be %s." +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/package.json b/node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/package.json new file mode 100644 index 0000000000000..a849ea3a84839 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data/package.json @@ -0,0 +1,56 @@ +{ + "name": "normalize-package-data", + "version": "7.0.0", + "author": "GitHub Inc.", + "description": "Normalizes data that can be found in package.json files.", + "license": "BSD-2-Clause", + "repository": { + "type": "git", + "url": "git+https://github.com/npm/normalize-package-data.git" + }, + "main": "lib/normalize.js", + "scripts": { + "test": "tap", + "npmclilint": "npmcli-lint", + "lint": "npm run eslint", + "lintfix": "npm run eslint -- --fix", + "posttest": "npm run lint", + "postsnap": "npm run lintfix --", + "postlint": "template-oss-check", + "snap": "tap", + "template-oss-apply": "template-oss-apply --force", + "eslint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"" + }, + "dependencies": { + "hosted-git-info": "^8.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "devDependencies": { + "@npmcli/eslint-config": "^5.0.0", + "@npmcli/template-oss": "4.23.3", + "tap": "^16.0.1" + }, + "files": [ + "bin/", + "lib/" + ], + "engines": { + "node": "^18.17.0 || >=20.5.0" + }, + "templateOSS": { + "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", + "version": "4.23.3", + "publish": "true" + }, + "tap": { + "branches": 86, + "functions": 92, + "lines": 86, + "statements": 86, + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] + } +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/npm-install-checks/LICENSE b/node_modules/@npmcli/map-workspaces/node_modules/npm-install-checks/LICENSE new file mode 100644 index 0000000000000..3bed8320c15b2 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/npm-install-checks/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) Robert Kowalski and Isaac Z. Schlueter ("Authors") +All rights reserved. + +The BSD License + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/node_modules/@npmcli/map-workspaces/node_modules/npm-install-checks/lib/current-env.js b/node_modules/@npmcli/map-workspaces/node_modules/npm-install-checks/lib/current-env.js new file mode 100644 index 0000000000000..9babde1f277ff --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/npm-install-checks/lib/current-env.js @@ -0,0 +1,63 @@ +const process = require('node:process') +const nodeOs = require('node:os') + +function isMusl (file) { + return file.includes('libc.musl-') || file.includes('ld-musl-') +} + +function os () { + return process.platform +} + +function cpu () { + return process.arch +} + +function libc (osName) { + // this is to make it faster on non linux machines + if (osName !== 'linux') { + return undefined + } + let family + const originalExclude = process.report.excludeNetwork + process.report.excludeNetwork = true + const report = process.report.getReport() + process.report.excludeNetwork = originalExclude + if (report.header?.glibcVersionRuntime) { + family = 'glibc' + } else if (Array.isArray(report.sharedObjects) && report.sharedObjects.some(isMusl)) { + family = 'musl' + } + return family +} + +function devEngines (env = {}) { + const osName = env.os || os() + return { + cpu: { + name: env.cpu || cpu(), + }, + libc: { + name: env.libc || libc(osName), + }, + os: { + name: osName, + version: env.osVersion || nodeOs.release(), + }, + packageManager: { + name: 'npm', + version: env.npmVersion, + }, + runtime: { + name: 'node', + version: env.nodeVersion || process.version, + }, + } +} + +module.exports = { + cpu, + libc, + os, + devEngines, +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/npm-install-checks/lib/dev-engines.js b/node_modules/@npmcli/map-workspaces/node_modules/npm-install-checks/lib/dev-engines.js new file mode 100644 index 0000000000000..ac5a182330d3b --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/npm-install-checks/lib/dev-engines.js @@ -0,0 +1,145 @@ +const satisfies = require('semver/functions/satisfies') +const validRange = require('semver/ranges/valid') + +const recognizedOnFail = [ + 'ignore', + 'warn', + 'error', + 'download', +] + +const recognizedProperties = [ + 'name', + 'version', + 'onFail', +] + +const recognizedEngines = [ + 'packageManager', + 'runtime', + 'cpu', + 'libc', + 'os', +] + +/** checks a devEngine dependency */ +function checkDependency (wanted, current, opts) { + const { engine } = opts + + if ((typeof wanted !== 'object' || wanted === null) || Array.isArray(wanted)) { + throw new Error(`Invalid non-object value for "${engine}"`) + } + + const properties = Object.keys(wanted) + + for (const prop of properties) { + if (!recognizedProperties.includes(prop)) { + throw new Error(`Invalid property "${prop}" for "${engine}"`) + } + } + + if (!properties.includes('name')) { + throw new Error(`Missing "name" property for "${engine}"`) + } + + if (typeof wanted.name !== 'string') { + throw new Error(`Invalid non-string value for "name" within "${engine}"`) + } + + if (typeof current.name !== 'string' || current.name === '') { + throw new Error(`Unable to determine "name" for "${engine}"`) + } + + if (properties.includes('onFail')) { + if (typeof wanted.onFail !== 'string') { + throw new Error(`Invalid non-string value for "onFail" within "${engine}"`) + } + if (!recognizedOnFail.includes(wanted.onFail)) { + throw new Error(`Invalid onFail value "${wanted.onFail}" for "${engine}"`) + } + } + + if (wanted.name !== current.name) { + return new Error( + `Invalid name "${wanted.name}" does not match "${current.name}" for "${engine}"` + ) + } + + if (properties.includes('version')) { + if (typeof wanted.version !== 'string') { + throw new Error(`Invalid non-string value for "version" within "${engine}"`) + } + if (typeof current.version !== 'string' || current.version === '') { + throw new Error(`Unable to determine "version" for "${engine}" "${wanted.name}"`) + } + if (validRange(wanted.version)) { + if (!satisfies(current.version, wanted.version, opts.semver)) { + return new Error( + // eslint-disable-next-line max-len + `Invalid semver version "${wanted.version}" does not match "${current.version}" for "${engine}"` + ) + } + } else if (wanted.version !== current.version) { + return new Error( + `Invalid version "${wanted.version}" does not match "${current.version}" for "${engine}"` + ) + } + } +} + +/** checks devEngines package property and returns array of warnings / errors */ +function checkDevEngines (wanted, current = {}, opts = {}) { + if ((typeof wanted !== 'object' || wanted === null) || Array.isArray(wanted)) { + throw new Error(`Invalid non-object value for devEngines`) + } + + const errors = [] + + for (const engine of Object.keys(wanted)) { + if (!recognizedEngines.includes(engine)) { + throw new Error(`Invalid property "${engine}"`) + } + const dependencyAsAuthored = wanted[engine] + const dependencies = [dependencyAsAuthored].flat() + const currentEngine = current[engine] || {} + + // this accounts for empty array eg { runtime: [] } and ignores it + if (dependencies.length === 0) { + continue + } + + const depErrors = [] + for (const dep of dependencies) { + const result = checkDependency(dep, currentEngine, { ...opts, engine }) + if (result) { + depErrors.push(result) + } + } + + const invalid = depErrors.length === dependencies.length + + if (invalid) { + const lastDependency = dependencies[dependencies.length - 1] + let onFail = lastDependency.onFail || 'error' + if (onFail === 'download') { + onFail = 'error' + } + + const err = Object.assign(new Error(`Invalid engine "${engine}"`), { + errors: depErrors, + engine, + isWarn: onFail === 'warn', + isError: onFail === 'error', + current: currentEngine, + required: dependencyAsAuthored, + }) + + errors.push(err) + } + } + return errors +} + +module.exports = { + checkDevEngines, +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/npm-install-checks/lib/index.js b/node_modules/@npmcli/map-workspaces/node_modules/npm-install-checks/lib/index.js new file mode 100644 index 0000000000000..7170292087308 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/npm-install-checks/lib/index.js @@ -0,0 +1,90 @@ +const semver = require('semver') +const currentEnv = require('./current-env') +const { checkDevEngines } = require('./dev-engines') + +const checkEngine = (target, npmVer, nodeVer, force = false) => { + const nodev = force ? null : nodeVer + const eng = target.engines + const opt = { includePrerelease: true } + if (!eng) { + return + } + + const nodeFail = nodev && eng.node && !semver.satisfies(nodev, eng.node, opt) + const npmFail = npmVer && eng.npm && !semver.satisfies(npmVer, eng.npm, opt) + if (nodeFail || npmFail) { + throw Object.assign(new Error('Unsupported engine'), { + pkgid: target._id, + current: { node: nodeVer, npm: npmVer }, + required: eng, + code: 'EBADENGINE', + }) + } +} + +const checkPlatform = (target, force = false, environment = {}) => { + if (force) { + return + } + + const os = environment.os || currentEnv.os() + const cpu = environment.cpu || currentEnv.cpu() + const libc = environment.libc || currentEnv.libc(os) + + const osOk = target.os ? checkList(os, target.os) : true + const cpuOk = target.cpu ? checkList(cpu, target.cpu) : true + let libcOk = target.libc ? checkList(libc, target.libc) : true + if (target.libc && !libc) { + libcOk = false + } + + if (!osOk || !cpuOk || !libcOk) { + throw Object.assign(new Error('Unsupported platform'), { + pkgid: target._id, + current: { + os, + cpu, + libc, + }, + required: { + os: target.os, + cpu: target.cpu, + libc: target.libc, + }, + code: 'EBADPLATFORM', + }) + } +} + +const checkList = (value, list) => { + if (typeof list === 'string') { + list = [list] + } + if (list.length === 1 && list[0] === 'any') { + return true + } + // match none of the negated values, and at least one of the + // non-negated values, if any are present. + let negated = 0 + let match = false + for (const entry of list) { + const negate = entry.charAt(0) === '!' + const test = negate ? entry.slice(1) : entry + if (negate) { + negated++ + if (value === test) { + return false + } + } else { + match = match || value === test + } + } + return match || negated === list.length +} + +module.exports = { + checkEngine, + checkPlatform, + checkDevEngines, + currentEnv, +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/npm-install-checks/package.json b/node_modules/@npmcli/map-workspaces/node_modules/npm-install-checks/package.json new file mode 100644 index 0000000000000..e9e69575a6dc6 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/npm-install-checks/package.json @@ -0,0 +1,52 @@ +{ + "name": "npm-install-checks", + "version": "7.1.0", + "description": "Check the engines and platform fields in package.json", + "main": "lib/index.js", + "dependencies": { + "semver": "^7.1.1" + }, + "devDependencies": { + "@npmcli/eslint-config": "^5.0.0", + "@npmcli/template-oss": "4.23.3", + "tap": "^16.0.1" + }, + "scripts": { + "test": "tap", + "lint": "npm run eslint", + "postlint": "template-oss-check", + "template-oss-apply": "template-oss-apply --force", + "lintfix": "npm run eslint -- --fix", + "snap": "tap", + "posttest": "npm run lint", + "eslint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/npm/npm-install-checks.git" + }, + "keywords": [ + "npm,", + "install" + ], + "license": "BSD-2-Clause", + "files": [ + "bin/", + "lib/" + ], + "engines": { + "node": "^18.17.0 || >=20.5.0" + }, + "author": "GitHub Inc.", + "templateOSS": { + "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", + "version": "4.23.3", + "publish": "true" + }, + "tap": { + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] + } +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/npm-normalize-package-bin/LICENSE b/node_modules/@npmcli/map-workspaces/node_modules/npm-normalize-package-bin/LICENSE new file mode 100644 index 0000000000000..19cec97b18468 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/npm-normalize-package-bin/LICENSE @@ -0,0 +1,15 @@ +The 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 AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/node_modules/@npmcli/map-workspaces/node_modules/npm-normalize-package-bin/lib/index.js b/node_modules/@npmcli/map-workspaces/node_modules/npm-normalize-package-bin/lib/index.js new file mode 100644 index 0000000000000..3cb8478cf6e2f --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/npm-normalize-package-bin/lib/index.js @@ -0,0 +1,64 @@ +// pass in a manifest with a 'bin' field here, and it'll turn it +// into a properly santized bin object +const { join, basename } = require('path') + +const normalize = pkg => + !pkg.bin ? removeBin(pkg) + : typeof pkg.bin === 'string' ? normalizeString(pkg) + : Array.isArray(pkg.bin) ? normalizeArray(pkg) + : typeof pkg.bin === 'object' ? normalizeObject(pkg) + : removeBin(pkg) + +const normalizeString = pkg => { + if (!pkg.name) { + return removeBin(pkg) + } + pkg.bin = { [pkg.name]: pkg.bin } + return normalizeObject(pkg) +} + +const normalizeArray = pkg => { + pkg.bin = pkg.bin.reduce((acc, k) => { + acc[basename(k)] = k + return acc + }, {}) + return normalizeObject(pkg) +} + +const removeBin = pkg => { + delete pkg.bin + return pkg +} + +const normalizeObject = pkg => { + const orig = pkg.bin + const clean = {} + let hasBins = false + Object.keys(orig).forEach(binKey => { + const base = join('/', basename(binKey.replace(/\\|:/g, '/'))).slice(1) + + if (typeof orig[binKey] !== 'string' || !base) { + return + } + + const binTarget = join('/', orig[binKey].replace(/\\/g, '/')) + .replace(/\\/g, '/').slice(1) + + if (!binTarget) { + return + } + + clean[base] = binTarget + hasBins = true + }) + + if (hasBins) { + pkg.bin = clean + } else { + delete pkg.bin + } + + return pkg +} + +module.exports = normalize diff --git a/node_modules/@npmcli/map-workspaces/node_modules/npm-normalize-package-bin/package.json b/node_modules/@npmcli/map-workspaces/node_modules/npm-normalize-package-bin/package.json new file mode 100644 index 0000000000000..a1aeef0e1e751 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/npm-normalize-package-bin/package.json @@ -0,0 +1,45 @@ +{ + "name": "npm-normalize-package-bin", + "version": "4.0.0", + "description": "Turn any flavor of allowable package.json bin into a normalized object", + "main": "lib/index.js", + "repository": { + "type": "git", + "url": "git+https://github.com/npm/npm-normalize-package-bin.git" + }, + "author": "GitHub Inc.", + "license": "ISC", + "scripts": { + "test": "tap", + "snap": "tap", + "lint": "npm run eslint", + "postlint": "template-oss-check", + "template-oss-apply": "template-oss-apply --force", + "lintfix": "npm run eslint -- --fix", + "posttest": "npm run lint", + "eslint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"" + }, + "devDependencies": { + "@npmcli/eslint-config": "^5.0.0", + "@npmcli/template-oss": "4.23.3", + "tap": "^16.3.0" + }, + "files": [ + "bin/", + "lib/" + ], + "engines": { + "node": "^18.17.0 || >=20.5.0" + }, + "templateOSS": { + "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", + "version": "4.23.3", + "publish": "true" + }, + "tap": { + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] + } +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/npm-package-arg/LICENSE b/node_modules/@npmcli/map-workspaces/node_modules/npm-package-arg/LICENSE new file mode 100644 index 0000000000000..19cec97b18468 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/npm-package-arg/LICENSE @@ -0,0 +1,15 @@ +The 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 AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/node_modules/@npmcli/map-workspaces/node_modules/npm-package-arg/lib/npa.js b/node_modules/@npmcli/map-workspaces/node_modules/npm-package-arg/lib/npa.js new file mode 100644 index 0000000000000..8094b3e732cd9 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/npm-package-arg/lib/npa.js @@ -0,0 +1,415 @@ +'use strict' +module.exports = npa +module.exports.resolve = resolve +module.exports.toPurl = toPurl +module.exports.Result = Result + +const { URL } = require('url') +const HostedGit = require('hosted-git-info') +const semver = require('semver') +const path = global.FAKE_WINDOWS ? require('path').win32 : require('path') +const validatePackageName = require('validate-npm-package-name') +const { homedir } = require('os') +const { log } = require('proc-log') + +const isWindows = process.platform === 'win32' || global.FAKE_WINDOWS +const hasSlashes = isWindows ? /\\|[/]/ : /[/]/ +const isURL = /^(?:git[+])?[a-z]+:/i +const isGit = /^[^@]+@[^:.]+\.[^:]+:.+$/i +const isFilename = /[.](?:tgz|tar.gz|tar)$/i + +function npa (arg, where) { + let name + let spec + if (typeof arg === 'object') { + if (arg instanceof Result && (!where || where === arg.where)) { + return arg + } else if (arg.name && arg.rawSpec) { + return npa.resolve(arg.name, arg.rawSpec, where || arg.where) + } else { + return npa(arg.raw, where || arg.where) + } + } + const nameEndsAt = arg[0] === '@' ? arg.slice(1).indexOf('@') + 1 : arg.indexOf('@') + const namePart = nameEndsAt > 0 ? arg.slice(0, nameEndsAt) : arg + if (isURL.test(arg)) { + spec = arg + } else if (isGit.test(arg)) { + spec = `git+ssh://${arg}` + } else if (namePart[0] !== '@' && (hasSlashes.test(namePart) || isFilename.test(namePart))) { + spec = arg + } else if (nameEndsAt > 0) { + name = namePart + spec = arg.slice(nameEndsAt + 1) || '*' + } else { + const valid = validatePackageName(arg) + if (valid.validForOldPackages) { + name = arg + spec = '*' + } else { + spec = arg + } + } + return resolve(name, spec, where, arg) +} + +const isFilespec = isWindows ? /^(?:[.]|~[/]|[/\\]|[a-zA-Z]:)/ : /^(?:[.]|~[/]|[/]|[a-zA-Z]:)/ + +function resolve (name, spec, where, arg) { + const res = new Result({ + raw: arg, + name: name, + rawSpec: spec, + fromArgument: arg != null, + }) + + if (name) { + res.setName(name) + } + + if (spec && (isFilespec.test(spec) || /^file:/i.test(spec))) { + return fromFile(res, where) + } else if (spec && /^npm:/i.test(spec)) { + return fromAlias(res, where) + } + + const hosted = HostedGit.fromUrl(spec, { + noGitPlus: true, + noCommittish: true, + }) + if (hosted) { + return fromHostedGit(res, hosted) + } else if (spec && isURL.test(spec)) { + return fromURL(res) + } else if (spec && (hasSlashes.test(spec) || isFilename.test(spec))) { + return fromFile(res, where) + } else { + return fromRegistry(res) + } +} + +const defaultRegistry = 'https://registry.npmjs.org' + +function toPurl (arg, reg = defaultRegistry) { + const res = npa(arg) + + if (res.type !== 'version') { + throw invalidPurlType(res.type, res.raw) + } + + // URI-encode leading @ of scoped packages + let purl = 'pkg:npm/' + res.name.replace(/^@/, '%40') + '@' + res.rawSpec + if (reg !== defaultRegistry) { + purl += '?repository_url=' + reg + } + + return purl +} + +function invalidPackageName (name, valid, raw) { + // eslint-disable-next-line max-len + const err = new Error(`Invalid package name "${name}" of package "${raw}": ${valid.errors.join('; ')}.`) + err.code = 'EINVALIDPACKAGENAME' + return err +} + +function invalidTagName (name, raw) { + // eslint-disable-next-line max-len + const err = new Error(`Invalid tag name "${name}" of package "${raw}": Tags may not have any characters that encodeURIComponent encodes.`) + err.code = 'EINVALIDTAGNAME' + return err +} + +function invalidPurlType (type, raw) { + // eslint-disable-next-line max-len + const err = new Error(`Invalid type "${type}" of package "${raw}": Purl can only be generated for "version" types.`) + err.code = 'EINVALIDPURLTYPE' + return err +} + +function Result (opts) { + this.type = opts.type + this.registry = opts.registry + this.where = opts.where + if (opts.raw == null) { + this.raw = opts.name ? opts.name + '@' + opts.rawSpec : opts.rawSpec + } else { + this.raw = opts.raw + } + + this.name = undefined + this.escapedName = undefined + this.scope = undefined + this.rawSpec = opts.rawSpec || '' + this.saveSpec = opts.saveSpec + this.fetchSpec = opts.fetchSpec + if (opts.name) { + this.setName(opts.name) + } + this.gitRange = opts.gitRange + this.gitCommittish = opts.gitCommittish + this.gitSubdir = opts.gitSubdir + this.hosted = opts.hosted +} + +Result.prototype.setName = function (name) { + const valid = validatePackageName(name) + if (!valid.validForOldPackages) { + throw invalidPackageName(name, valid, this.raw) + } + + this.name = name + this.scope = name[0] === '@' ? name.slice(0, name.indexOf('/')) : undefined + // scoped packages in couch must have slash url-encoded, e.g. @foo%2Fbar + this.escapedName = name.replace('/', '%2f') + return this +} + +Result.prototype.toString = function () { + const full = [] + if (this.name != null && this.name !== '') { + full.push(this.name) + } + const spec = this.saveSpec || this.fetchSpec || this.rawSpec + if (spec != null && spec !== '') { + full.push(spec) + } + return full.length ? full.join('@') : this.raw +} + +Result.prototype.toJSON = function () { + const result = Object.assign({}, this) + delete result.hosted + return result +} + +// sets res.gitCommittish, res.gitRange, and res.gitSubdir +function setGitAttrs (res, committish) { + if (!committish) { + res.gitCommittish = null + return + } + + // for each :: separated item: + for (const part of committish.split('::')) { + // if the item has no : the n it is a commit-ish + if (!part.includes(':')) { + if (res.gitRange) { + throw new Error('cannot override existing semver range with a committish') + } + if (res.gitCommittish) { + throw new Error('cannot override existing committish with a second committish') + } + res.gitCommittish = part + continue + } + // split on name:value + const [name, value] = part.split(':') + // if name is semver do semver lookup of ref or tag + if (name === 'semver') { + if (res.gitCommittish) { + throw new Error('cannot override existing committish with a semver range') + } + if (res.gitRange) { + throw new Error('cannot override existing semver range with a second semver range') + } + res.gitRange = decodeURIComponent(value) + continue + } + if (name === 'path') { + if (res.gitSubdir) { + throw new Error('cannot override existing path with a second path') + } + res.gitSubdir = `/${value}` + continue + } + log.warn('npm-package-arg', `ignoring unknown key "${name}"`) + } +} + +function fromFile (res, where) { + if (!where) { + where = process.cwd() + } + res.type = isFilename.test(res.rawSpec) ? 'file' : 'directory' + res.where = where + + // always put the '/' on where when resolving urls, or else + // file:foo from /path/to/bar goes to /path/to/foo, when we want + // it to be /path/to/bar/foo + + let specUrl + let resolvedUrl + const prefix = (!/^file:/.test(res.rawSpec) ? 'file:' : '') + const rawWithPrefix = prefix + res.rawSpec + let rawNoPrefix = rawWithPrefix.replace(/^file:/, '') + try { + resolvedUrl = new URL(rawWithPrefix, `file://${path.resolve(where)}/`) + specUrl = new URL(rawWithPrefix) + } catch (originalError) { + const er = new Error('Invalid file: URL, must comply with RFC 8089') + throw Object.assign(er, { + raw: res.rawSpec, + spec: res, + where, + originalError, + }) + } + + // XXX backwards compatibility lack of compliance with RFC 8089 + if (resolvedUrl.host && resolvedUrl.host !== 'localhost') { + const rawSpec = res.rawSpec.replace(/^file:\/\//, 'file:///') + resolvedUrl = new URL(rawSpec, `file://${path.resolve(where)}/`) + specUrl = new URL(rawSpec) + rawNoPrefix = rawSpec.replace(/^file:/, '') + } + // turn file:/../foo into file:../foo + // for 1, 2 or 3 leading slashes since we attempted + // in the previous step to make it a file protocol url with a leading slash + if (/^\/{1,3}\.\.?(\/|$)/.test(rawNoPrefix)) { + const rawSpec = res.rawSpec.replace(/^file:\/{1,3}/, 'file:') + resolvedUrl = new URL(rawSpec, `file://${path.resolve(where)}/`) + specUrl = new URL(rawSpec) + rawNoPrefix = rawSpec.replace(/^file:/, '') + } + // XXX end RFC 8089 violation backwards compatibility section + + // turn /C:/blah into just C:/blah on windows + let specPath = decodeURIComponent(specUrl.pathname) + let resolvedPath = decodeURIComponent(resolvedUrl.pathname) + if (isWindows) { + specPath = specPath.replace(/^\/+([a-z]:\/)/i, '$1') + resolvedPath = resolvedPath.replace(/^\/+([a-z]:\/)/i, '$1') + } + + // replace ~ with homedir, but keep the ~ in the saveSpec + // otherwise, make it relative to where param + if (/^\/~(\/|$)/.test(specPath)) { + res.saveSpec = `file:${specPath.substr(1)}` + resolvedPath = path.resolve(homedir(), specPath.substr(3)) + } else if (!path.isAbsolute(rawNoPrefix)) { + res.saveSpec = `file:${path.relative(where, resolvedPath)}` + } else { + res.saveSpec = `file:${path.resolve(resolvedPath)}` + } + + res.fetchSpec = path.resolve(where, resolvedPath) + return res +} + +function fromHostedGit (res, hosted) { + res.type = 'git' + res.hosted = hosted + res.saveSpec = hosted.toString({ noGitPlus: false, noCommittish: false }) + res.fetchSpec = hosted.getDefaultRepresentation() === 'shortcut' ? null : hosted.toString() + setGitAttrs(res, hosted.committish) + return res +} + +function unsupportedURLType (protocol, spec) { + const err = new Error(`Unsupported URL Type "${protocol}": ${spec}`) + err.code = 'EUNSUPPORTEDPROTOCOL' + return err +} + +function fromURL (res) { + let rawSpec = res.rawSpec + res.saveSpec = rawSpec + if (rawSpec.startsWith('git+ssh:')) { + // git ssh specifiers are overloaded to also use scp-style git + // specifiers, so we have to parse those out and treat them special. + // They are NOT true URIs, so we can't hand them to URL. + + // This regex looks for things that look like: + // git+ssh://git@my.custom.git.com:username/project.git#deadbeef + // ...and various combinations. The username in the beginning is *required*. + const matched = rawSpec.match(/^git\+ssh:\/\/([^:#]+:[^#]+(?:\.git)?)(?:#(.*))?$/i) + if (matched && !matched[1].match(/:[0-9]+\/?.*$/i)) { + res.type = 'git' + setGitAttrs(res, matched[2]) + res.fetchSpec = matched[1] + return res + } + } else if (rawSpec.startsWith('git+file://')) { + // URL can't handle windows paths + rawSpec = rawSpec.replace(/\\/g, '/') + } + const parsedUrl = new URL(rawSpec) + // check the protocol, and then see if it's git or not + switch (parsedUrl.protocol) { + case 'git:': + case 'git+http:': + case 'git+https:': + case 'git+rsync:': + case 'git+ftp:': + case 'git+file:': + case 'git+ssh:': + res.type = 'git' + setGitAttrs(res, parsedUrl.hash.slice(1)) + if (parsedUrl.protocol === 'git+file:' && /^git\+file:\/\/[a-z]:/i.test(rawSpec)) { + // URL can't handle drive letters on windows file paths, the host can't contain a : + res.fetchSpec = `git+file://${parsedUrl.host.toLowerCase()}:${parsedUrl.pathname}` + } else { + parsedUrl.hash = '' + res.fetchSpec = parsedUrl.toString() + } + if (res.fetchSpec.startsWith('git+')) { + res.fetchSpec = res.fetchSpec.slice(4) + } + break + case 'http:': + case 'https:': + res.type = 'remote' + res.fetchSpec = res.saveSpec + break + + default: + throw unsupportedURLType(parsedUrl.protocol, rawSpec) + } + + return res +} + +function fromAlias (res, where) { + const subSpec = npa(res.rawSpec.substr(4), where) + if (subSpec.type === 'alias') { + throw new Error('nested aliases not supported') + } + + if (!subSpec.registry) { + throw new Error('aliases only work for registry deps') + } + + if (!subSpec.name) { + throw new Error('aliases must have a name') + } + + res.subSpec = subSpec + res.registry = true + res.type = 'alias' + res.saveSpec = null + res.fetchSpec = null + return res +} + +function fromRegistry (res) { + res.registry = true + const spec = res.rawSpec.trim() + // no save spec for registry components as we save based on the fetched + // version, not on the argument so this can't compute that. + res.saveSpec = null + res.fetchSpec = spec + const version = semver.valid(spec, true) + const range = semver.validRange(spec, true) + if (version) { + res.type = 'version' + } else if (range) { + res.type = 'range' + } else { + if (encodeURIComponent(spec) !== spec) { + throw invalidTagName(spec, res.raw) + } + res.type = 'tag' + } + return res +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/npm-package-arg/package.json b/node_modules/@npmcli/map-workspaces/node_modules/npm-package-arg/package.json new file mode 100644 index 0000000000000..80baa3d32a52f --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/npm-package-arg/package.json @@ -0,0 +1,61 @@ +{ + "name": "npm-package-arg", + "version": "12.0.0", + "description": "Parse the things that can be arguments to `npm install`", + "main": "./lib/npa.js", + "directories": { + "test": "test" + }, + "files": [ + "bin/", + "lib/" + ], + "dependencies": { + "hosted-git-info": "^8.0.0", + "proc-log": "^5.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^6.0.0" + }, + "devDependencies": { + "@npmcli/eslint-config": "^5.0.0", + "@npmcli/template-oss": "4.23.3", + "tap": "^16.0.1" + }, + "scripts": { + "test": "tap", + "snap": "tap", + "npmclilint": "npmcli-lint", + "lint": "npm run eslint", + "lintfix": "npm run eslint -- --fix", + "posttest": "npm run lint", + "postsnap": "npm run lintfix --", + "postlint": "template-oss-check", + "template-oss-apply": "template-oss-apply --force", + "eslint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/npm/npm-package-arg.git" + }, + "author": "GitHub Inc.", + "license": "ISC", + "bugs": { + "url": "https://github.com/npm/npm-package-arg/issues" + }, + "homepage": "https://github.com/npm/npm-package-arg", + "engines": { + "node": "^18.17.0 || >=20.5.0" + }, + "tap": { + "branches": 97, + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] + }, + "templateOSS": { + "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", + "version": "4.23.3", + "publish": true + } +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/npm-pick-manifest/LICENSE.md b/node_modules/@npmcli/map-workspaces/node_modules/npm-pick-manifest/LICENSE.md new file mode 100644 index 0000000000000..8d28acf866d93 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/npm-pick-manifest/LICENSE.md @@ -0,0 +1,16 @@ +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/@npmcli/map-workspaces/node_modules/npm-pick-manifest/lib/index.js b/node_modules/@npmcli/map-workspaces/node_modules/npm-pick-manifest/lib/index.js new file mode 100644 index 0000000000000..82807971844bf --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/npm-pick-manifest/lib/index.js @@ -0,0 +1,224 @@ +'use strict' + +const npa = require('npm-package-arg') +const semver = require('semver') +const { checkEngine } = require('npm-install-checks') +const normalizeBin = require('npm-normalize-package-bin') + +const engineOk = (manifest, npmVersion, nodeVersion) => { + try { + checkEngine(manifest, npmVersion, nodeVersion) + return true + } catch (_) { + return false + } +} + +const isBefore = (verTimes, ver, time) => + !verTimes || !verTimes[ver] || Date.parse(verTimes[ver]) <= time + +const avoidSemverOpt = { includePrerelease: true, loose: true } +const shouldAvoid = (ver, avoid) => + avoid && semver.satisfies(ver, avoid, avoidSemverOpt) + +const decorateAvoid = (result, avoid) => + result && shouldAvoid(result.version, avoid) + ? { ...result, _shouldAvoid: true } + : result + +const pickManifest = (packument, wanted, opts) => { + const { + defaultTag = 'latest', + before = null, + nodeVersion = process.version, + npmVersion = null, + includeStaged = false, + avoid = null, + avoidStrict = false, + } = opts + + const { name, time: verTimes } = packument + const versions = packument.versions || {} + + if (avoidStrict) { + const looseOpts = { + ...opts, + avoidStrict: false, + } + + const result = pickManifest(packument, wanted, looseOpts) + if (!result || !result._shouldAvoid) { + return result + } + + const caret = pickManifest(packument, `^${result.version}`, looseOpts) + if (!caret || !caret._shouldAvoid) { + return { + ...caret, + _outsideDependencyRange: true, + _isSemVerMajor: false, + } + } + + const star = pickManifest(packument, '*', looseOpts) + if (!star || !star._shouldAvoid) { + return { + ...star, + _outsideDependencyRange: true, + _isSemVerMajor: true, + } + } + + throw Object.assign(new Error(`No avoidable versions for ${name}`), { + code: 'ETARGET', + name, + wanted, + avoid, + before, + versions: Object.keys(versions), + }) + } + + const staged = (includeStaged && packument.stagedVersions && + packument.stagedVersions.versions) || {} + const restricted = (packument.policyRestrictions && + packument.policyRestrictions.versions) || {} + + const time = before && verTimes ? +(new Date(before)) : Infinity + const spec = npa.resolve(name, wanted || defaultTag) + const type = spec.type + const distTags = packument['dist-tags'] || {} + + if (type !== 'tag' && type !== 'version' && type !== 'range') { + throw new Error('Only tag, version, and range are supported') + } + + // if the type is 'tag', and not just the implicit default, then it must + // be that exactly, or nothing else will do. + if (wanted && type === 'tag') { + const ver = distTags[wanted] + // if the version in the dist-tags is before the before date, then + // we use that. Otherwise, we get the highest precedence version + // prior to the dist-tag. + if (isBefore(verTimes, ver, time)) { + return decorateAvoid(versions[ver] || staged[ver] || restricted[ver], avoid) + } else { + return pickManifest(packument, `<=${ver}`, opts) + } + } + + // similarly, if a specific version, then only that version will do + if (wanted && type === 'version') { + const ver = semver.clean(wanted, { loose: true }) + const mani = versions[ver] || staged[ver] || restricted[ver] + return isBefore(verTimes, ver, time) ? decorateAvoid(mani, avoid) : null + } + + // ok, sort based on our heuristics, and pick the best fit + const range = type === 'range' ? wanted : '*' + + // if the range is *, then we prefer the 'latest' if available + // but skip this if it should be avoided, in that case we have + // to try a little harder. + const defaultVer = distTags[defaultTag] + if (defaultVer && + (range === '*' || semver.satisfies(defaultVer, range, { loose: true })) && + !restricted[defaultVer] && + !shouldAvoid(defaultVer, avoid)) { + const mani = versions[defaultVer] + const ok = mani && + isBefore(verTimes, defaultVer, time) && + engineOk(mani, npmVersion, nodeVersion) && + !mani.deprecated && + !staged[defaultVer] + if (ok) { + return mani + } + } + + // ok, actually have to sort the list and take the winner + const allEntries = Object.entries(versions) + .concat(Object.entries(staged)) + .concat(Object.entries(restricted)) + .filter(([ver]) => isBefore(verTimes, ver, time)) + + if (!allEntries.length) { + throw Object.assign(new Error(`No versions available for ${name}`), { + code: 'ENOVERSIONS', + name, + type, + wanted, + before, + versions: Object.keys(versions), + }) + } + + const sortSemverOpt = { loose: true } + const entries = allEntries.filter(([ver]) => + semver.satisfies(ver, range, { loose: true })) + .sort((a, b) => { + const [vera, mania] = a + const [verb, manib] = b + const notavoida = !shouldAvoid(vera, avoid) + const notavoidb = !shouldAvoid(verb, avoid) + const notrestra = !restricted[vera] + const notrestrb = !restricted[verb] + const notstagea = !staged[vera] + const notstageb = !staged[verb] + const notdepra = !mania.deprecated + const notdeprb = !manib.deprecated + const enginea = engineOk(mania, npmVersion, nodeVersion) + const engineb = engineOk(manib, npmVersion, nodeVersion) + // sort by: + // - not an avoided version + // - not restricted + // - not staged + // - not deprecated and engine ok + // - engine ok + // - not deprecated + // - semver + return (notavoidb - notavoida) || + (notrestrb - notrestra) || + (notstageb - notstagea) || + ((notdeprb && engineb) - (notdepra && enginea)) || + (engineb - enginea) || + (notdeprb - notdepra) || + semver.rcompare(vera, verb, sortSemverOpt) + }) + + return decorateAvoid(entries[0] && entries[0][1], avoid) +} + +module.exports = (packument, wanted, opts = {}) => { + const mani = pickManifest(packument, wanted, opts) + const picked = mani && normalizeBin(mani) + const policyRestrictions = packument.policyRestrictions + const restricted = (policyRestrictions && policyRestrictions.versions) || {} + + if (picked && !restricted[picked.version]) { + return picked + } + + const { before = null, defaultTag = 'latest' } = opts + const bstr = before ? new Date(before).toLocaleString() : '' + const { name } = packument + const pckg = `${name}@${wanted}` + + (before ? ` with a date before ${bstr}` : '') + + const isForbidden = picked && !!restricted[picked.version] + const polMsg = isForbidden ? policyRestrictions.message : '' + + const msg = !isForbidden ? `No matching version found for ${pckg}.` + : `Could not download ${pckg} due to policy violations:\n${polMsg}` + + const code = isForbidden ? 'E403' : 'ETARGET' + throw Object.assign(new Error(msg), { + code, + type: npa.resolve(packument.name, wanted).type, + wanted, + versions: Object.keys(packument.versions ?? {}), + name, + distTags: packument['dist-tags'], + defaultTag, + }) +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/npm-pick-manifest/package.json b/node_modules/@npmcli/map-workspaces/node_modules/npm-pick-manifest/package.json new file mode 100644 index 0000000000000..5763088c250b6 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/npm-pick-manifest/package.json @@ -0,0 +1,58 @@ +{ + "name": "npm-pick-manifest", + "version": "10.0.0", + "description": "Resolves a matching manifest from a package metadata document according to standard npm semver resolution rules.", + "main": "./lib", + "files": [ + "bin/", + "lib/" + ], + "scripts": { + "coverage": "tap", + "lint": "npm run eslint", + "test": "tap", + "posttest": "npm run lint", + "postlint": "template-oss-check", + "lintfix": "npm run eslint -- --fix", + "snap": "tap", + "template-oss-apply": "template-oss-apply --force", + "eslint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/npm/npm-pick-manifest.git" + }, + "keywords": [ + "npm", + "semver", + "package manager" + ], + "author": "GitHub Inc.", + "license": "ISC", + "dependencies": { + "npm-install-checks": "^7.1.0", + "npm-normalize-package-bin": "^4.0.0", + "npm-package-arg": "^12.0.0", + "semver": "^7.3.5" + }, + "devDependencies": { + "@npmcli/eslint-config": "^5.0.0", + "@npmcli/template-oss": "4.23.3", + "tap": "^16.0.1" + }, + "tap": { + "check-coverage": true, + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + }, + "templateOSS": { + "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", + "version": "4.23.3", + "publish": true + } +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/proc-log/LICENSE b/node_modules/@npmcli/map-workspaces/node_modules/proc-log/LICENSE new file mode 100644 index 0000000000000..83837797202b7 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/proc-log/LICENSE @@ -0,0 +1,15 @@ +The ISC License + +Copyright (c) GitHub, 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/@npmcli/map-workspaces/node_modules/proc-log/lib/index.js b/node_modules/@npmcli/map-workspaces/node_modules/proc-log/lib/index.js new file mode 100644 index 0000000000000..86d90861078da --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/proc-log/lib/index.js @@ -0,0 +1,153 @@ +const META = Symbol('proc-log.meta') +module.exports = { + META: META, + output: { + LEVELS: [ + 'standard', + 'error', + 'buffer', + 'flush', + ], + KEYS: { + standard: 'standard', + error: 'error', + buffer: 'buffer', + flush: 'flush', + }, + standard: function (...args) { + return process.emit('output', 'standard', ...args) + }, + error: function (...args) { + return process.emit('output', 'error', ...args) + }, + buffer: function (...args) { + return process.emit('output', 'buffer', ...args) + }, + flush: function (...args) { + return process.emit('output', 'flush', ...args) + }, + }, + log: { + LEVELS: [ + 'notice', + 'error', + 'warn', + 'info', + 'verbose', + 'http', + 'silly', + 'timing', + 'pause', + 'resume', + ], + KEYS: { + notice: 'notice', + error: 'error', + warn: 'warn', + info: 'info', + verbose: 'verbose', + http: 'http', + silly: 'silly', + timing: 'timing', + pause: 'pause', + resume: 'resume', + }, + error: function (...args) { + return process.emit('log', 'error', ...args) + }, + notice: function (...args) { + return process.emit('log', 'notice', ...args) + }, + warn: function (...args) { + return process.emit('log', 'warn', ...args) + }, + info: function (...args) { + return process.emit('log', 'info', ...args) + }, + verbose: function (...args) { + return process.emit('log', 'verbose', ...args) + }, + http: function (...args) { + return process.emit('log', 'http', ...args) + }, + silly: function (...args) { + return process.emit('log', 'silly', ...args) + }, + timing: function (...args) { + return process.emit('log', 'timing', ...args) + }, + pause: function () { + return process.emit('log', 'pause') + }, + resume: function () { + return process.emit('log', 'resume') + }, + }, + time: { + LEVELS: [ + 'start', + 'end', + ], + KEYS: { + start: 'start', + end: 'end', + }, + start: function (name, fn) { + process.emit('time', 'start', name) + function end () { + return process.emit('time', 'end', name) + } + if (typeof fn === 'function') { + const res = fn() + if (res && res.finally) { + return res.finally(end) + } + end() + return res + } + return end + }, + end: function (name) { + return process.emit('time', 'end', name) + }, + }, + input: { + LEVELS: [ + 'start', + 'end', + 'read', + ], + KEYS: { + start: 'start', + end: 'end', + read: 'read', + }, + start: function (fn) { + process.emit('input', 'start') + function end () { + return process.emit('input', 'end') + } + if (typeof fn === 'function') { + const res = fn() + if (res && res.finally) { + return res.finally(end) + } + end() + return res + } + return end + }, + end: function () { + return process.emit('input', 'end') + }, + read: function (...args) { + let resolve, reject + const promise = new Promise((_resolve, _reject) => { + resolve = _resolve + reject = _reject + }) + process.emit('input', 'read', resolve, reject, ...args) + return promise + }, + }, +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/proc-log/package.json b/node_modules/@npmcli/map-workspaces/node_modules/proc-log/package.json new file mode 100644 index 0000000000000..957209d3954e5 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/proc-log/package.json @@ -0,0 +1,46 @@ +{ + "name": "proc-log", + "version": "5.0.0", + "files": [ + "bin/", + "lib/" + ], + "main": "lib/index.js", + "description": "just emit 'log' events on the process object", + "repository": { + "type": "git", + "url": "git+https://github.com/npm/proc-log.git" + }, + "author": "GitHub Inc.", + "license": "ISC", + "scripts": { + "test": "tap", + "snap": "tap", + "posttest": "npm run lint", + "postsnap": "eslint index.js test/*.js --fix", + "lint": "npm run eslint", + "postlint": "template-oss-check", + "lintfix": "npm run eslint -- --fix", + "template-oss-apply": "template-oss-apply --force", + "eslint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"" + }, + "devDependencies": { + "@npmcli/eslint-config": "^5.0.0", + "@npmcli/template-oss": "4.23.3", + "tap": "^16.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + }, + "templateOSS": { + "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", + "version": "4.23.3", + "publish": true + }, + "tap": { + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] + } +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/validate-npm-package-name/LICENSE b/node_modules/@npmcli/map-workspaces/node_modules/validate-npm-package-name/LICENSE new file mode 100644 index 0000000000000..fdcd63b302308 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/validate-npm-package-name/LICENSE @@ -0,0 +1,6 @@ +Copyright (c) 2015, 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/@npmcli/map-workspaces/node_modules/validate-npm-package-name/lib/index.js b/node_modules/@npmcli/map-workspaces/node_modules/validate-npm-package-name/lib/index.js new file mode 100644 index 0000000000000..fd800d5a5eae1 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/validate-npm-package-name/lib/index.js @@ -0,0 +1,105 @@ +'use strict' +const { builtinModules: builtins } = require('module') + +var scopedPackagePattern = new RegExp('^(?:@([^/]+?)[/])?([^/]+?)$') +var blacklist = [ + 'node_modules', + 'favicon.ico', +] + +function validate (name) { + var warnings = [] + var errors = [] + + if (name === null) { + errors.push('name cannot be null') + return done(warnings, errors) + } + + if (name === undefined) { + errors.push('name cannot be undefined') + return done(warnings, errors) + } + + if (typeof name !== 'string') { + errors.push('name must be a string') + return done(warnings, errors) + } + + if (!name.length) { + errors.push('name length must be greater than zero') + } + + if (name.match(/^\./)) { + errors.push('name cannot start with a period') + } + + if (name.match(/^_/)) { + errors.push('name cannot start with an underscore') + } + + if (name.trim() !== name) { + errors.push('name cannot contain leading or trailing spaces') + } + + // No funny business + blacklist.forEach(function (blacklistedName) { + if (name.toLowerCase() === blacklistedName) { + errors.push(blacklistedName + ' is a blacklisted name') + } + }) + + // Generate warnings for stuff that used to be allowed + + // core module names like http, events, util, etc + if (builtins.includes(name.toLowerCase())) { + warnings.push(name + ' is a core module name') + } + + if (name.length > 214) { + warnings.push('name can no longer contain more than 214 characters') + } + + // mIxeD CaSe nAMEs + if (name.toLowerCase() !== name) { + warnings.push('name can no longer contain capital letters') + } + + if (/[~'!()*]/.test(name.split('/').slice(-1)[0])) { + warnings.push('name can no longer contain special characters ("~\'!()*")') + } + + if (encodeURIComponent(name) !== name) { + // Maybe it's a scoped package name, like @user/package + var nameMatch = name.match(scopedPackagePattern) + if (nameMatch) { + var user = nameMatch[1] + var pkg = nameMatch[2] + if (encodeURIComponent(user) === user && encodeURIComponent(pkg) === pkg) { + return done(warnings, errors) + } + } + + errors.push('name can only contain URL-friendly characters') + } + + return done(warnings, errors) +} + +var done = function (warnings, errors) { + var result = { + validForNewPackages: errors.length === 0 && warnings.length === 0, + validForOldPackages: errors.length === 0, + warnings: warnings, + errors: errors, + } + if (!result.warnings.length) { + delete result.warnings + } + if (!result.errors.length) { + delete result.errors + } + return result +} + +module.exports = validate diff --git a/node_modules/@npmcli/map-workspaces/node_modules/validate-npm-package-name/package.json b/node_modules/@npmcli/map-workspaces/node_modules/validate-npm-package-name/package.json new file mode 100644 index 0000000000000..42089cbbede70 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/validate-npm-package-name/package.json @@ -0,0 +1,61 @@ +{ + "name": "validate-npm-package-name", + "version": "6.0.0", + "description": "Give me a string and I'll tell you if it's a valid npm package name", + "main": "lib/", + "directories": { + "test": "test" + }, + "devDependencies": { + "@npmcli/eslint-config": "^5.0.0", + "@npmcli/template-oss": "4.23.3", + "tap": "^16.0.1" + }, + "scripts": { + "cov:test": "TAP_FLAGS='--cov' npm run test:code", + "test:code": "tap ${TAP_FLAGS:-'--'} test/*.js", + "test:style": "standard", + "test": "tap", + "lint": "npm run eslint", + "postlint": "template-oss-check", + "template-oss-apply": "template-oss-apply --force", + "lintfix": "npm run eslint -- --fix", + "snap": "tap", + "posttest": "npm run lint", + "eslint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/npm/validate-npm-package-name.git" + }, + "keywords": [ + "npm", + "package", + "names", + "validation" + ], + "author": "GitHub Inc.", + "license": "ISC", + "bugs": { + "url": "https://github.com/npm/validate-npm-package-name/issues" + }, + "homepage": "https://github.com/npm/validate-npm-package-name", + "files": [ + "bin/", + "lib/" + ], + "engines": { + "node": "^18.17.0 || >=20.5.0" + }, + "templateOSS": { + "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", + "version": "4.23.3", + "publish": true + }, + "tap": { + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] + } +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/which/LICENSE b/node_modules/@npmcli/map-workspaces/node_modules/which/LICENSE new file mode 100644 index 0000000000000..19129e315fe59 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/which/LICENSE @@ -0,0 +1,15 @@ +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/node_modules/@npmcli/map-workspaces/node_modules/which/bin/which.js b/node_modules/@npmcli/map-workspaces/node_modules/which/bin/which.js new file mode 100755 index 0000000000000..6df16f21acf93 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/which/bin/which.js @@ -0,0 +1,52 @@ +#!/usr/bin/env node + +const which = require('../lib') +const argv = process.argv.slice(2) + +const usage = (err) => { + if (err) { + console.error(`which: ${err}`) + } + console.error('usage: which [-as] program ...') + process.exit(1) +} + +if (!argv.length) { + return usage() +} + +let dashdash = false +const [commands, flags] = argv.reduce((acc, arg) => { + if (dashdash || arg === '--') { + dashdash = true + return acc + } + + if (!/^-/.test(arg)) { + acc[0].push(arg) + return acc + } + + for (const flag of arg.slice(1).split('')) { + if (flag === 's') { + acc[1].silent = true + } else if (flag === 'a') { + acc[1].all = true + } else { + usage(`illegal option -- ${flag}`) + } + } + + return acc +}, [[], {}]) + +for (const command of commands) { + try { + const res = which.sync(command, { all: flags.all }) + if (!flags.silent) { + console.log([].concat(res).join('\n')) + } + } catch (err) { + process.exitCode = 1 + } +} diff --git a/node_modules/@npmcli/map-workspaces/node_modules/which/lib/index.js b/node_modules/@npmcli/map-workspaces/node_modules/which/lib/index.js new file mode 100644 index 0000000000000..2fd358baf888f --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/which/lib/index.js @@ -0,0 +1,111 @@ +const { isexe, sync: isexeSync } = require('isexe') +const { join, delimiter, sep, posix } = require('path') + +const isWindows = process.platform === 'win32' + +// used to check for slashed in commands passed in. always checks for the posix +// seperator on all platforms, and checks for the current separator when not on +// a posix platform. don't use the isWindows check for this since that is mocked +// in tests but we still need the code to actually work when called. that is also +// why it is ignored from coverage. +/* istanbul ignore next */ +const rSlash = new RegExp(`[${posix.sep}${sep === posix.sep ? '' : sep}]`.replace(/(\\)/g, '\\$1')) +const rRel = new RegExp(`^\\.${rSlash.source}`) + +const getNotFoundError = (cmd) => + Object.assign(new Error(`not found: ${cmd}`), { code: 'ENOENT' }) + +const getPathInfo = (cmd, { + path: optPath = process.env.PATH, + pathExt: optPathExt = process.env.PATHEXT, + delimiter: optDelimiter = delimiter, +}) => { + // If it has a slash, then we don't bother searching the pathenv. + // just check the file itself, and that's it. + const pathEnv = cmd.match(rSlash) ? [''] : [ + // windows always checks the cwd first + ...(isWindows ? [process.cwd()] : []), + ...(optPath || /* istanbul ignore next: very unusual */ '').split(optDelimiter), + ] + + if (isWindows) { + const pathExtExe = optPathExt || + ['.EXE', '.CMD', '.BAT', '.COM'].join(optDelimiter) + const pathExt = pathExtExe.split(optDelimiter).flatMap((item) => [item, item.toLowerCase()]) + if (cmd.includes('.') && pathExt[0] !== '') { + pathExt.unshift('') + } + return { pathEnv, pathExt, pathExtExe } + } + + return { pathEnv, pathExt: [''] } +} + +const getPathPart = (raw, cmd) => { + const pathPart = /^".*"$/.test(raw) ? raw.slice(1, -1) : raw + const prefix = !pathPart && rRel.test(cmd) ? cmd.slice(0, 2) : '' + return prefix + join(pathPart, cmd) +} + +const which = async (cmd, opt = {}) => { + const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt) + const found = [] + + for (const envPart of pathEnv) { + const p = getPathPart(envPart, cmd) + + for (const ext of pathExt) { + const withExt = p + ext + const is = await isexe(withExt, { pathExt: pathExtExe, ignoreErrors: true }) + if (is) { + if (!opt.all) { + return withExt + } + found.push(withExt) + } + } + } + + if (opt.all && found.length) { + return found + } + + if (opt.nothrow) { + return null + } + + throw getNotFoundError(cmd) +} + +const whichSync = (cmd, opt = {}) => { + const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt) + const found = [] + + for (const pathEnvPart of pathEnv) { + const p = getPathPart(pathEnvPart, cmd) + + for (const ext of pathExt) { + const withExt = p + ext + const is = isexeSync(withExt, { pathExt: pathExtExe, ignoreErrors: true }) + if (is) { + if (!opt.all) { + return withExt + } + found.push(withExt) + } + } + } + + if (opt.all && found.length) { + return found + } + + if (opt.nothrow) { + return null + } + + throw getNotFoundError(cmd) +} + +module.exports = which +which.sync = whichSync diff --git a/node_modules/@npmcli/map-workspaces/node_modules/which/package.json b/node_modules/@npmcli/map-workspaces/node_modules/which/package.json new file mode 100644 index 0000000000000..94184233c61c4 --- /dev/null +++ b/node_modules/@npmcli/map-workspaces/node_modules/which/package.json @@ -0,0 +1,52 @@ +{ + "author": "GitHub Inc.", + "name": "which", + "description": "Like which(1) unix command. Find the first instance of an executable in the PATH.", + "version": "5.0.0", + "repository": { + "type": "git", + "url": "git+https://github.com/npm/node-which.git" + }, + "main": "lib/index.js", + "bin": { + "node-which": "./bin/which.js" + }, + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "devDependencies": { + "@npmcli/eslint-config": "^5.0.0", + "@npmcli/template-oss": "4.23.3", + "tap": "^16.3.0" + }, + "scripts": { + "test": "tap", + "lint": "npm run eslint", + "postlint": "template-oss-check", + "template-oss-apply": "template-oss-apply --force", + "lintfix": "npm run eslint -- --fix", + "snap": "tap", + "posttest": "npm run lint", + "eslint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"" + }, + "files": [ + "bin/", + "lib/" + ], + "tap": { + "check-coverage": true, + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + }, + "templateOSS": { + "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", + "version": "4.23.3", + "publish": "true" + } +} diff --git a/node_modules/@npmcli/map-workspaces/package.json b/node_modules/@npmcli/map-workspaces/package.json index e6292b06bd2b4..f2667f25e9d5d 100644 --- a/node_modules/@npmcli/map-workspaces/package.json +++ b/node_modules/@npmcli/map-workspaces/package.json @@ -1,18 +1,18 @@ { "name": "@npmcli/map-workspaces", - "version": "3.0.6", + "version": "4.0.1", "main": "lib/index.js", "files": [ "bin/", "lib/" ], "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^18.17.0 || >=20.5.0" }, "description": "Retrieves a name:pathname Map for a given workspaces config", "repository": { "type": "git", - "url": "https://github.com/npm/map-workspaces.git" + "url": "git+https://github.com/npm/map-workspaces.git" }, "keywords": [ "npm", @@ -25,14 +25,15 @@ "author": "GitHub Inc.", "license": "ISC", "scripts": { - "lint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"", + "lint": "npm run eslint", "pretest": "npm run lint", "test": "tap", "snap": "tap", "postlint": "template-oss-check", - "lintfix": "npm run lint -- --fix", + "lintfix": "npm run eslint -- --fix", "posttest": "npm run lint", - "template-oss-apply": "template-oss-apply --force" + "template-oss-apply": "template-oss-apply --force", + "eslint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"" }, "tap": { "check-coverage": true, @@ -42,19 +43,19 @@ ] }, "devDependencies": { - "@npmcli/eslint-config": "^4.0.0", - "@npmcli/template-oss": "4.21.3", + "@npmcli/eslint-config": "^5.0.0", + "@npmcli/template-oss": "4.23.3", "tap": "^16.0.1" }, "dependencies": { - "@npmcli/name-from-folder": "^2.0.0", + "@npmcli/name-from-folder": "^3.0.0", + "@npmcli/package-json": "^6.0.0", "glob": "^10.2.2", - "minimatch": "^9.0.0", - "read-package-json-fast": "^3.0.0" + "minimatch": "^9.0.0" }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.21.3", + "version": "4.23.3", "publish": "true" } } diff --git a/package-lock.json b/package-lock.json index d316152fe593c..c0871f8865fba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -90,7 +90,7 @@ "@npmcli/arborist": "^7.5.4", "@npmcli/config": "^8.3.4", "@npmcli/fs": "^4.0.0", - "@npmcli/map-workspaces": "^3.0.6", + "@npmcli/map-workspaces": "^4.0.1", "@npmcli/package-json": "^5.2.0", "@npmcli/promise-spawn": "^7.0.2", "@npmcli/redact": "^2.0.1", @@ -1610,19 +1610,231 @@ } }, "node_modules/@npmcli/map-workspaces": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@npmcli/map-workspaces/-/map-workspaces-3.0.6.tgz", - "integrity": "sha512-tkYs0OYnzQm6iIRdfy+LcLBjcKuQCeE5YLb8KnrIlutJfheNaPvPpgoFEyEFgbjzl5PLZ3IA/BWAwRU0eHuQDA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/map-workspaces/-/map-workspaces-4.0.1.tgz", + "integrity": "sha512-g5H8ljH7Z+4T1ASsfcL09gZl4YGw6M4GbjzPt6HgE+pCRSKC4nlNc4nY75zshi88eEHcdoh3Q8XgWFkGKoVOPw==", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/name-from-folder": "^2.0.0", + "@npmcli/name-from-folder": "^3.0.0", + "@npmcli/package-json": "^6.0.0", "glob": "^10.2.2", - "minimatch": "^9.0.0", - "read-package-json-fast": "^3.0.0" + "minimatch": "^9.0.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/@npmcli/git": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-6.0.1.tgz", + "integrity": "sha512-BBWMMxeQzalmKadyimwb2/VVQyJB01PH0HhVSNLHNBDZN/M/h/02P6f8fxedIiFhpMj11SO9Ep5tKTBE7zL2nw==", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/promise-spawn": "^8.0.0", + "ini": "^5.0.0", + "lru-cache": "^10.0.1", + "npm-pick-manifest": "^10.0.0", + "proc-log": "^5.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^5.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/@npmcli/name-from-folder": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/name-from-folder/-/name-from-folder-3.0.0.tgz", + "integrity": "sha512-61cDL8LUc9y80fXn+lir+iVt8IS0xHqEKwPu/5jCjxQTVoSCmkXvw4vbMrzAMtmghz3/AkiBjhHkDKUH+kf7kA==", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/@npmcli/package-json": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-6.0.1.tgz", + "integrity": "sha512-YW6PZ99sc1Q4DINEY2td5z9Z3rwbbsx7CyCnOc7UXUUdePXh5gPi1UeaoQVmKQMVbIU7aOwX2l1OG5ZfjgGi5g==", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^6.0.0", + "glob": "^10.2.2", + "hosted-git-info": "^8.0.0", + "json-parse-even-better-errors": "^4.0.0", + "normalize-package-data": "^7.0.0", + "proc-log": "^5.0.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/@npmcli/promise-spawn": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-8.0.1.tgz", + "integrity": "sha512-ZscqKtJqy7oj6MgXEJcHQ1om4utU0Q84QtC28UVuiO6ALSO9sDPanXdu6Wd1oYhItW8fx2u96zRFUE8BuPlAjA==", + "inBundle": true, + "license": "ISC", + "dependencies": { + "which": "^5.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/hosted-git-info": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.0.0.tgz", + "integrity": "sha512-4nw3vOVR+vHUOT8+U4giwe2tcGv+R3pwwRidUe67DoMBTjhrfr6rZYJVVwdkBE+Um050SG+X9tf0Jo4fOpn01w==", + "inBundle": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/ini": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-5.0.0.tgz", + "integrity": "sha512-+N0ngpO3e7cRUWOJAS7qw0IZIVc6XPrW4MlFBdD066F2L4k1L6ker3hLqSq7iXxU5tgS4WGkIUElWn5vogAEnw==", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/json-parse-even-better-errors": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-4.0.0.tgz", + "integrity": "sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA==", + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/normalize-package-data": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-7.0.0.tgz", + "integrity": "sha512-k6U0gKRIuNCTkwHGZqblCfLfBRh+w1vI6tBo+IeJwq2M8FUiOqhX7GH+GArQGScA7azd1WfyRCvxoXDO3hQDIA==", + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^8.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/npm-install-checks": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-7.1.0.tgz", + "integrity": "sha512-bkTildVlofeMX7wiOaWk3PlW7YcBXAuEc7TWpOxwUgalG5ZvgT/ms+6OX9zt7iGLv4+VhKbRZhpOfgQJzk1YAw==", + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/npm-normalize-package-bin": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-4.0.0.tgz", + "integrity": "sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w==", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/npm-package-arg": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-12.0.0.tgz", + "integrity": "sha512-ZTE0hbwSdTNL+Stx2zxSqdu2KZfNDcrtrLdIk7XGnQFYBWYDho/ORvXtn5XEePcL3tFpGjHCV3X3xrtDh7eZ+A==", + "inBundle": true, + "license": "ISC", + "dependencies": { + "hosted-git-info": "^8.0.0", + "proc-log": "^5.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^6.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/npm-pick-manifest": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-10.0.0.tgz", + "integrity": "sha512-r4fFa4FqYY8xaM7fHecQ9Z2nE9hgNfJR+EmoKv0+chvzWkBcORX3r0FpTByP+CbOVJDladMXnPQGVN8PBLGuTQ==", + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-install-checks": "^7.1.0", + "npm-normalize-package-bin": "^4.0.0", + "npm-package-arg": "^12.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/proc-log": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-5.0.0.tgz", + "integrity": "sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ==", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/validate-npm-package-name": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-6.0.0.tgz", + "integrity": "sha512-d7KLgL1LD3U3fgnvWEY1cQXoO/q6EQ1BSz48Sa149V/5zVTAbgmZIpyI8TRi6U9/JNyeYLlTKsEMPtLC27RFUg==", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/which": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", + "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", + "inBundle": true, + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/@npmcli/metavuln-calculator": { @@ -1653,7 +1865,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/@npmcli/name-from-folder/-/name-from-folder-2.0.0.tgz", "integrity": "sha512-pwK+BfEBZJbKdNYpHHRTNBwBoqrN/iIMO0AiGvYsp3Hoaq0WbgGSWQR6SCldZovoDpY3yje5lkFUe6gsDgJ2vg==", - "inBundle": true, "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -1794,6 +2005,22 @@ "node": "^18.17.0 || >=20.5.0" } }, + "node_modules/@npmcli/template-oss/node_modules/@npmcli/map-workspaces": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@npmcli/map-workspaces/-/map-workspaces-3.0.6.tgz", + "integrity": "sha512-tkYs0OYnzQm6iIRdfy+LcLBjcKuQCeE5YLb8KnrIlutJfheNaPvPpgoFEyEFgbjzl5PLZ3IA/BWAwRU0eHuQDA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/name-from-folder": "^2.0.0", + "glob": "^10.2.2", + "minimatch": "^9.0.0", + "read-package-json-fast": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/@octokit/auth-token": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.4.tgz", @@ -10698,7 +10925,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", - "inBundle": true, "license": "ISC", "dependencies": { "json-parse-even-better-errors": "^3.0.0", @@ -15773,7 +15999,7 @@ "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/fs": "^4.0.0", "@npmcli/installed-package-contents": "^2.1.0", - "@npmcli/map-workspaces": "^3.0.2", + "@npmcli/map-workspaces": "^4.0.1", "@npmcli/metavuln-calculator": "^7.1.1", "@npmcli/name-from-folder": "^2.0.0", "@npmcli/node-gyp": "^3.0.0", @@ -15828,7 +16054,7 @@ "version": "8.3.4", "license": "ISC", "dependencies": { - "@npmcli/map-workspaces": "^3.0.2", + "@npmcli/map-workspaces": "^4.0.1", "@npmcli/package-json": "^5.1.1", "ci-info": "^4.0.0", "ini": "^4.1.2", diff --git a/package.json b/package.json index bb92796e057c8..a68eb8d6370ec 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "@npmcli/arborist": "^7.5.4", "@npmcli/config": "^8.3.4", "@npmcli/fs": "^4.0.0", - "@npmcli/map-workspaces": "^3.0.6", + "@npmcli/map-workspaces": "^4.0.1", "@npmcli/package-json": "^5.2.0", "@npmcli/promise-spawn": "^7.0.2", "@npmcli/redact": "^2.0.1", diff --git a/workspaces/arborist/package.json b/workspaces/arborist/package.json index 80e7402c66d59..4fc7a87259af8 100644 --- a/workspaces/arborist/package.json +++ b/workspaces/arborist/package.json @@ -6,7 +6,7 @@ "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/fs": "^4.0.0", "@npmcli/installed-package-contents": "^2.1.0", - "@npmcli/map-workspaces": "^3.0.2", + "@npmcli/map-workspaces": "^4.0.1", "@npmcli/metavuln-calculator": "^7.1.1", "@npmcli/name-from-folder": "^2.0.0", "@npmcli/node-gyp": "^3.0.0", diff --git a/workspaces/config/package.json b/workspaces/config/package.json index c55b9906662a5..c9617da862628 100644 --- a/workspaces/config/package.json +++ b/workspaces/config/package.json @@ -37,7 +37,7 @@ "tap": "^16.3.8" }, "dependencies": { - "@npmcli/map-workspaces": "^3.0.2", + "@npmcli/map-workspaces": "^4.0.1", "@npmcli/package-json": "^5.1.1", "ci-info": "^4.0.0", "ini": "^4.1.2",