UNPKG

vlt

Version:
1,356 lines (1,348 loc) 42.1 kB
var global = globalThis; import {Buffer} from "node:buffer"; import {setTimeout,clearTimeout,setImmediate,clearImmediate,setInterval,clearInterval} from "node:timers"; import {createRequire as _vlt_createRequire} from "node:module"; var require = _vlt_createRequire(import.meta.filename); import { parseRange } from "./chunk-JBBINXAZ.js"; import { error, typeError } from "./chunk-KVH5ECIG.js"; // ../../src/spec/src/index.ts import { homedir } from "node:os"; import { isAbsolute, join, resolve, win32 as winPath } from "node:path"; import { inspect } from "node:util"; // ../../src/spec/src/browser.ts var kCustomInspect = Symbol.for("nodejs.util.inspect.custom"); var defaultRegistry = "https://registry.npmjs.org/"; var defaultRegistries = { npm: defaultRegistry, gh: "https://npm.pkg.github.com/" }; var defaultJsrRegistries = { jsr: "https://npm.jsr.io/" }; var defaultGitHosts = { github: "git+ssh://git@github.com:$1/$2.git", bitbucket: "git+ssh://git@bitbucket.org:$1/$2.git", gitlab: "git+ssh://git@gitlab.com:$1/$2.git", gist: "git+ssh://git@gist.github.com/$1.git" }; var defaultGitHostArchives = { github: "https://api.github.com/repos/$1/$2/tarball/$committish", bitbucket: "https://bitbucket.org/$1/$2/get/$committish.tar.gz", gist: "https://codeload.github.com/gist/$1/tar.gz/$committish", gitlab: "https://gitlab.com/$1/$2/repository/archive.tar.gz?ref=$committish" }; var gitHostWebsites = { github: "https://github.com/", bitbucket: "https://bitbucket.org/", gist: "https://gist.github.com/", gitlab: "https://gitlab.com/" }; var defaultScopeRegistries = { "@jsr": "https://npm.jsr.io/" }; var getOptions = (options) => ({ catalog: {}, catalogs: {}, ...options, "jsr-registries": { ...options?.["jsr-registries"] ?? {}, ...defaultJsrRegistries }, registry: options?.registry ?? defaultRegistry, "scope-registries": options?.["scope-registries"] ?? {}, "git-hosts": options?.["git-hosts"] ? { ...defaultGitHosts, ...options["git-hosts"] } : defaultGitHosts, registries: options?.registries ?? {}, "git-host-archives": options?.["git-host-archives"] ? { ...defaultGitHostArchives, ...options["git-host-archives"] } : defaultGitHostArchives }); var startsWithSpecIdentifier = (spec, options) => spec.startsWith("/") || spec.startsWith("./") || spec.startsWith("../") || spec.startsWith("file:") || spec.startsWith("http:") || spec.startsWith("https:") || spec.startsWith("workspace:") || spec.startsWith("catalog:") || spec.startsWith("git@") || spec.startsWith("git://") || spec.startsWith("git+ssh://") || spec.startsWith("git+http://") || spec.startsWith("git+https://") || spec.startsWith("git+file://") || spec.startsWith("git@github.com") || spec.startsWith("registry:") || spec.startsWith("npm:") || spec.startsWith("gh:") || // anything that starts with a known git host key, or a // custom registered registry protocol e.g: `github:`, `custom:` [ ...Object.keys(options["git-hosts"]), ...Object.keys(options.registries), ...Object.keys(options["jsr-registries"]) ].some((key) => spec.startsWith(`${key}:`)); var findFirstAt = (spec, hasScope) => spec.indexOf("@", hasScope ? 1 : 0); var findGitIdentifier = (spec) => spec.indexOf("#") > 2; var findFileIdentifier = (spec) => spec.includes("/"); var isSpec = (spec) => typeof spec === "object" && spec !== null && "spec" in spec && "bareSpec" in spec && "name" in spec && "type" in spec && "options" in spec && typeof spec.spec === "string" && typeof spec.bareSpec === "string" && typeof spec.name === "string"; var Spec = class _Spec { static parse(spec, bareOrOptions, options) { return typeof spec === "object" ? spec : new this(spec, bareOrOptions, options); } static parseArgs(specOrBareSpec, opts) { const options = getOptions(opts ?? {}); if (startsWithSpecIdentifier(specOrBareSpec, options)) { const parsed = this.parse("(unknown)", specOrBareSpec, options); if (parsed.subspec) { const { namedJsrRegistry: jsrHost } = parsed; if (!jsrHost) { parsed.name = parsed.subspec.name; } parsed.spec = `${parsed.name}@${parsed.bareSpec}`; } return parsed; } else { const hasScope = specOrBareSpec.startsWith("@"); const at = findFirstAt(specOrBareSpec, hasScope); if (at > -1) { return this.parse( specOrBareSpec.substring(0, at), specOrBareSpec.substring(at + 1), options ); } else if (findGitIdentifier(specOrBareSpec) || !hasScope && findFileIdentifier(specOrBareSpec)) { return this.parse("(unknown)", specOrBareSpec, options); } else { return this.parse(`${specOrBareSpec}@`, options); } } } static nodejsDependencies; type; spec; options; name; scope; scopeRegistry; bareSpec; gitRemote; gitSelector; gitSelectorParsed; gitCommittish; namedGitHost; namedGitHostPath; workspaceSpec; workspace; namedRegistry; namedJsrRegistry; registry; registrySpec; conventionalRegistryTarball; semver; range; distTag; remoteURL; file; catalog; subspec; overridden = false; #final; #toString; /** * Return the final entry in the chain of subspecs * When deciding which thing to actually fetch, spec.final is the thing * to look at. */ get final() { if (this.#final) return this.#final; const final = this.subspec ? this.subspec.final : this; if (final.type === "catalog") { throw error('invalid Spec.final value, type is "catalog"'); } return this.#final = final; } /** * Normally, the string value of a Spec is just the string passed in to * be parsed. However, in the case of a chain of subspecs, like * `foo@npm:bar@npm:baz@npm:quux@latest`, this simplifies out the middle * parts of the chain, returning just `foo@npm:quux@latest` */ toString() { if (this.#toString !== void 0) return this.#toString; let sub = this; while (sub.subspec?.subspec) sub = sub.subspec; if (sub.subspec && sub.subspec.type !== "registry") sub = sub.subspec; return this.#toString = this.name + "@" + sub.bareSpec; } constructor(spec, bareOrOptions, options = {}) { if (bareOrOptions && typeof bareOrOptions === "object") { options = bareOrOptions; bareOrOptions = void 0; } this.options = getOptions(options); if (typeof bareOrOptions === "string") { this.name = spec; this.#parseScope(spec); this.bareSpec = bareOrOptions; this.spec = `${this.name}@${bareOrOptions}`; } else { this.spec = spec; if (!spec.startsWith("git@") && startsWithSpecIdentifier(spec, this.options) && spec.includes(":") && [ ...Object.keys(this.options.registries), ...Object.keys(defaultRegistries) ].some((key) => spec.startsWith(`${key}:`))) { this.name = spec; this.bareSpec = spec; } else { const hasScope = spec.startsWith("@"); let at = findFirstAt(spec, hasScope); if (at === -1) { at = spec.length; spec += "@"; } this.name = spec.substring(0, at); if (hasScope) this.#parseScope(this.name); this.bareSpec = spec.substring(at + 1); } } if (this.bareSpec.startsWith("catalog:")) { this.catalog = this.bareSpec.substring("catalog:".length); const catalog = this.catalog ? this.options.catalogs[this.catalog] : this.options.catalog; if (!catalog) { throw this.#error("Named catalog not found", { name: this.catalog, validOptions: Object.keys(this.options.catalogs) }); } const sub = catalog[this.name]; if (!sub) { throw this.#error("Name not found in catalog", { name: this.name, validOptions: Object.keys(catalog) }); } this.subspec = _Spec.parse(this.name, sub); this.type = "catalog"; return; } if (this.bareSpec.startsWith("https://")) { for (const [name, origin] of Object.entries(gitHostWebsites)) { if (this.bareSpec.startsWith(origin)) { const parsed = new URL(this.bareSpec); const [user, project] = parsed.pathname.replace(/\.git$/, "").replace(/\/+/g, " ").trim().split(" "); if (user && project) { this.bareSpec = `${name}:${user}/${project}${parsed.hash}`; this.spec = `${this.name}@${this.bareSpec}`; break; } } } } if (this.bareSpec.startsWith("workspace:")) { this.type = "workspace"; const ws = this.bareSpec.substring("workspace:".length).trim(); const w = ws.lastIndexOf("@"); if (w === -1) { this.workspace = this.name; } else { const wsName = ws.substring(0, w); if (!wsName || wsName === "*" || wsName === "~" || wsName === "^" || (wsName.startsWith("@") ? wsName.split("/").length !== 2 || wsName.substring(1).includes("@") : wsName.includes("@"))) { throw this.#error( "workspace: name must be a path or valid package name", { found: wsName } ); } this.workspace = wsName; } const wss = w === -1 ? ws : ws.substring(w + 1) || "*"; const range2 = wss === "*" ? void 0 : parseRange(wss); if (wss !== "*" && wss !== "~" && wss !== "^" && !range2) { throw this.#error( "workspace: spec must be one of *, ~, or ^, or a valid semver range", { found: wss, wanted: `'*'|'~'|'^'|SemverRange` } ); } this.workspaceSpec = wss; if (range2) { this.semver = wss; this.range = range2; } return; } if (this.bareSpec.startsWith("git://") || this.bareSpec.startsWith("git+ssh://") || this.bareSpec.startsWith("git+http://") || this.bareSpec.startsWith("git+https://") || this.bareSpec.startsWith("git+file://") || // legacy affordance this.bareSpec.startsWith("git@github.com")) { if (this.bareSpec.startsWith("git@")) { this.bareSpec = `git+ssh://${this.bareSpec}`; this.spec = `${this.name}@${this.bareSpec}`; } this.type = "git"; for (const [name, host] of Object.entries( this.options["git-hosts"] )) { const s = host.indexOf("$"); if (s > 0 && this.bareSpec.startsWith(host.substring(0, s))) { const p = this.bareSpec.substring(s).replace(/\.git(#.*)?$/, "$1"); this.bareSpec = `${name}:${p}`; this.spec = `${this.name}@${this.bareSpec}`; this.#parseHostedGit(name, host); this.type = "git"; return; } } this.#parseGitSelector(this.bareSpec); return; } const regs = Object.entries(this.options.registries); if (!this.options.registries.npm) { regs.push(["npm", this.options.registry]); } if (!this.options.registries.gh) { regs.push(["gh", defaultRegistries.gh]); } if (this.bareSpec.startsWith("registry:")) { const reg = this.bareSpec.substring("registry:".length); const h = reg.indexOf("#"); if (h === -1) { throw this.#error("registry: must include name/version"); } this.type = "registry"; let url = reg.substring(0, h); if (!url.endsWith("/")) url += "/"; const regSpec = reg.substring(h + 1); for (let [name, u] of regs) { if (!u.endsWith("/")) { u += "/"; this.options.registries[name] = u; } if (u === url) this.namedRegistry = name; } this.#parseRegistrySpec(regSpec, url); this.#guessRegistryTarball(); return; } for (const [host, url] of regs) { const h = `${host}:`; if (this.bareSpec.startsWith(h)) { this.type = "registry"; this.namedRegistry = host; this.#parseRegistrySpec( this.bareSpec.substring(h.length), url ).namedRegistry ??= host; if (this.subspec && this.name === this.bareSpec) { this.name = this.subspec.name; this.spec = `${this.name}@${this.bareSpec}`; } this.#guessRegistryTarball(); return; } } const ghosts = Object.entries(this.options["git-hosts"]); for (const [name, template] of ghosts) { if (this.#parseHostedGit(name, template)) { this.type = "git"; return; } } const jsrs = Object.entries(this.options["jsr-registries"]); for (const [host, url] of jsrs) { const h = `${host}:`; if (this.bareSpec.startsWith(h)) { this.type = "registry"; this.namedJsrRegistry = host; this.#parseJsrRegistrySpec( this.bareSpec.substring(h.length), url ).namedJsrRegistry ??= host; return; } } if (this.bareSpec.startsWith("https://") || this.bareSpec.startsWith("http://")) { this.remoteURL = this.bareSpec; this.type = "remote"; return; } if (this.bareSpec.startsWith("file:")) { this.type = "file"; const [path, uri] = getNormalizeFile( this.constructor.nodejsDependencies )(this.bareSpec, this); this.file = path; this.bareSpec = uri.replace(/\/+$/, ""); this.spec = `${this.name}@${this.bareSpec}`; return; } if (!this.bareSpec.startsWith("./") && !this.bareSpec.startsWith("../") && this.options["git-hosts"].github) { const hash = this.bareSpec.indexOf("#"); const up = hash === -1 ? this.bareSpec : this.bareSpec.substring(0, hash); if (up.split("/").length === 2) { this.bareSpec = `github:${this.bareSpec}`; this.spec = `${this.name}@${this.bareSpec}`; this.#parseHostedGit( "github", this.options["git-hosts"].github ); this.type = "git"; return; } } if (this.bareSpec.includes("/") || this.bareSpec === "." || this.bareSpec === "..") { this.type = "file"; const [file, uri] = getNormalizeFile( this.constructor.nodejsDependencies )(`file:${this.bareSpec}`, this); this.bareSpec = uri; this.spec = `${this.name}@${this.bareSpec}`; this.file = file; return; } this.type = "registry"; const range = parseRange(this.bareSpec); if (range) { this.semver = this.bareSpec.trim(); this.range = range; } else { this.distTag = this.bareSpec; } this.registrySpec = this.bareSpec; const { "scope-registries": scopeRegs, registry } = this.options; const scopeReg = this.scope && scopeRegs[this.scope]; this.registry = scopeReg ?? registry; for (const r of Object.values(this.options["jsr-registries"])) { if (this.registry === r) return; } this.#guessRegistryTarball(); } #parseScope(name) { if (!name.startsWith("@")) return; const s = name.indexOf("/"); if (s > 1 && s < name.length - 1) { const scope = name.substring(0, s); this.registry = this.scopeRegistry = this.options["scope-registries"][scope]; this.scope = scope; } } #parseHostedGit(name, template) { if (this.bareSpec.startsWith(`${name}:`)) { const h = this.bareSpec.indexOf("#"); const bare = h === -1 ? this.bareSpec : this.bareSpec.substring(0, h); const hash = h === -1 ? "" : this.bareSpec.substring(h); const hostPath = bare.substring(name.length + 1); if (!hostPath) { throw this.#error("invalid named git host specifier"); } const split = hostPath.split("/"); let t = template; for (let i = 0; i < split.length; i++) { t = t.split(`$${i + 1}`).join(split[i]); } t += hash; this.namedGitHost = name; this.namedGitHostPath = hostPath; this.#parseGitSelector(t); if (this.gitCommittish && !this.gitSelectorParsed?.path) { const archiveHost = this.options["git-host-archives"][name]; if (name === "github" && this.gitCommittish.startsWith("pull/") && this.gitCommittish.match(/\//g)?.length === 1) { this.gitCommittish += "/head"; } if (archiveHost) { this.type = "remote"; let t2 = archiveHost; t2 = t2.split("$committish").join(this.gitCommittish); for (let i = 0; i < split.length; i++) { t2 = t2.split(`$${i + 1}`).join(split[i]); } this.remoteURL = t2; } } return true; } return false; } /* c8 ignore start */ [kCustomInspect]() { return `@vltpkg/spec.Spec ${String(this)}`; } /* c8 ignore stop */ #guessRegistryTarball() { const { name, registry, range } = this.final; if (!registry || !range?.isSingle) return; const stripScope = /^@[^/]+\//; this.conventionalRegistryTarball = String( new URL( `/${name}/-/${name.replace(stripScope, "")}-${range}.tgz`, registry ) ); } #parseRegistrySpec(s, url) { this.registry = url; this.subspec = this.constructor.parse(s, { ...this.options, registry: url }); return this.subspec; } #parseJsrRegistrySpec(s, url) { this.registry = url; if (!s.startsWith("@")) s = `${this.name}@${s}`; const name = `@jsr/${s.replace(/^@/, "").replace(/\//, "__")}`; this.subspec = this.constructor.parse(name, { ...this.options, "scope-registries": { ...this.options["scope-registries"], "@jsr": url } }); if (this.name === "(unknown)") { const nextAt = s.indexOf("@", 1); if (nextAt === -1) { this.name = s; } else { this.name = s.substring(0, s.indexOf("@", 1)); } } const reg = `${this.namedJsrRegistry}:`; const n = `${reg}${this.name}`; if (this.bareSpec.startsWith(n + "@")) { this.bareSpec = reg + this.bareSpec.substring(n.length + 1); } else if (this.bareSpec === n) { this.bareSpec = reg; } this.spec = this.name + "@" + this.bareSpec; return this.subspec; } #error(message, extra = {}) { return error(message, { spec: this.spec, ...extra }, this.#error); } #parseGitSelector(s) { const h = s.indexOf("#"); if (h === -1) { this.gitRemote = s; return; } this.gitRemote = s.substring(0, h); this.gitSelector = s.substring(h + 1); const [selectorParsed, committish, range] = this.constructor.parseGitSelector(this.gitSelector, this); this.range = range; this.gitCommittish = committish; this.gitSelectorParsed = selectorParsed; } /** * Sets a registry value that should be used for this spec in case * it is currently just following the default registry. */ set inheritedRegistry(reg) { if (reg != null && this.type === "registry" && this.registry === this.options.registry) { this.registry = reg; } } /** * Should only ever be called with the bit that comes AFTER the # * in the git remote url. */ static parseGitSelector(selector, spec) { if (!selector) return [{}]; const split = selector.split("::"); const first = split[0]; let committish = void 0; let range = void 0; const parsed = {}; if (typeof first !== "string") { throw typeError("impossible", { found: first, wanted: String }); } if (!first.includes(":")) { committish = first; split.shift(); } for (const kv of split) { const c = kv.indexOf(":"); if (c === -1) continue; const k = kv.substring(0, c); const v = kv.substring(c + 1); if (k === "semver") { if (committish) { throw error( "Cannot specify a semver range and committish value", { spec } ); } range = parseRange(v); if (!range) { throw error(`Invalid git tag semver range: ${v}`, { spec }); } } if (k === "semver" || k === "path") { if (k === "path") { if ( /* c8 ignore next */ this.nodejsDependencies?.isAbsolute( v ) || /(^|\/|\\)\.\.($|\\|\/)/.test(v) ) { throw error("Invalid path in git selector", { spec }); } parsed.path = (this.nodejsDependencies ? this.nodejsDependencies.join("/", v).substring(1) : v).replace(/\\/g, "/"); } else { parsed[k] = v; } } } return [parsed, committish, range]; } }; var getNormalizeFile = (opts) => (bareSpec, spec) => { const slashes = bareSpec.substring( "file:".length, "file://".length ); const pref = `file:${slashes === "//" ? slashes : ""}`; const rest = bareSpec.substring(pref.length); const [a = "", b = "/", c = "/", d = "/"] = rest.split("", 4); if (!a) { return [".", "file:."]; } if (a === "/" && b === "~" && c !== "/" || a === "~" && b !== "/") { throw error( `invalid file: specifier. '~username' not supported`, { spec } ); } if (a === "~") { return ( /* c8 ignore start */ opts ? [ opts.resolve(opts.homedir(), rest.substring(2)), `file:${rest}` ] : [rest, `file:${rest}`] ); } if (a === "/" && b === "~") { return opts ? [ opts.resolve(opts.homedir(), rest.substring(3)), `file:${rest.substring(1)}` ] : ( /* c8 ignore stop */ [rest.substring(1), `file:${rest.substring(1)}`] ); } if (a === "/" && b === "." && (c === "/" || c === "." && d === "/")) { return [rest.substring(1), `file:${rest.substring(1)}`]; } if (a === "." && (b === "/" || b === "." && c === "/")) { return [rest, `file:${rest}`]; } if (slashes === "//") { try { const parsed = new URL(bareSpec); if (parsed.host) { if (parsed.host !== "localhost") { throw error( `invalid file:// specifier. host must be empty or 'localhost'`, { spec, found: parsed.host, validOptions: ["", "localhost"] } ); } } return [ parsed.pathname.replace(/^\/([a-zA-Z]:\/)/, "$1"), `file://${parsed.pathname}` ]; } catch (er) { throw error("invalid file:// specifier", { spec, cause: er }); } } if (opts?.winPath.isAbsolute(rest)) { return [rest, `file://${rest}`]; } return [`./${rest}`, `file:./${rest}`]; }; // ../../src/spec/src/index.ts var Spec2 = class extends Spec { [kCustomInspect](_depth, options) { const str = inspect( Object.fromEntries( Object.entries(this).filter(([k, v]) => { return k !== "options" && v !== void 0; }) ), options ); return `@vltpkg/spec.Spec ${str}`; } }; Spec2.nodejsDependencies = { homedir, isAbsolute, join, resolve, winPath }; // ../../src/dep-id/src/browser.ts var delimiter = "\xB7"; var depIDRegExp = new RegExp( `^((git)?${delimiter}[^${delimiter}]*${delimiter}[^${delimiter}]*(${delimiter}[^${delimiter}]*)?$|^(file|remote|workspace)${delimiter}[^${delimiter}]*)(${delimiter}[^${delimiter}]*)?$` ); var isDepID = (str) => typeof str === "string" && depIDRegExp.test(str); var asDepID = (str) => { if (!isDepID(str)) { throw error("Expected dep id", { found: str }); } return str; }; var joinDepIDTuple = (list) => { const [type, first, second, extra] = list; const f = encode(first); switch (type) { case "registry": return `${delimiter}${f}${delimiter}${encode(second)}${extra ? `${delimiter}${encode(extra)}` : ""}`; case "git": return `${type}${delimiter}${f}${delimiter}${encode(second)}${extra ? `${delimiter}${encode(extra)}` : ""}`; default: return `${type}${delimiter}${f}${second ? `${delimiter}${encode(second)}` : ""}`; } }; var encode = (s) => s ? encodeURIComponent(s).replaceAll("%40", "@").replaceAll("%2f", "\xA7").replaceAll("%2F", "\xA7") : s; var decode = (s) => s ? decodeURIComponent( s.replaceAll("@", "%40").replaceAll("\xA7", "%2F") ) : s; var seenSplitDepIDs = /* @__PURE__ */ new Map(); var splitDepID = (id) => { const seen = seenSplitDepIDs.get(id); if (seen) return seen; let res; const [type, first = "", second, extra] = id.replaceAll("\xA7", "/").split(delimiter, 4); const f = decodeURIComponent(first); switch (type) { case "git": case "": { if (second === void 0) { throw error(`invalid ${type} id`, { found: id }); } res = [ type || "registry", f, decodeURIComponent(second), decode(extra) ]; break; } case "file": case "remote": case "workspace": { res = [type, f, decode(second)]; break; } default: { throw error("invalid DepID type", { found: type, validOptions: ["git", "file", "workspace", "remote", ""] }); } } seenSplitDepIDs.set(id, res); return res; }; var baseDepID = (id) => { const [type, first, second] = splitDepID(id); switch (type) { case "git": case "registry": return joinDepIDTuple([type, first, second]); default: return joinDepIDTuple([type, first]); } }; var seenHydrated = /* @__PURE__ */ new Map(); var hydrate = (id, name, options = {}) => { const cacheKey = (name ?? "") + id; const seen = seenHydrated.get(cacheKey); if (seen) return seen; const res = hydrateTuple(splitDepID(id), name, options); seenHydrated.set(cacheKey, res); return res; }; var seenHydratedTuples = /* @__PURE__ */ new Map(); var hydrateTuple = (tuple, name, options = {}) => { const [type, first, second] = tuple; const cacheKey = (name ?? "") + type + first + (second ?? ""); const seen = seenHydratedTuples.get(cacheKey); if (seen) return seen; let res; switch (type) { case "remote": { if (!first) throw error("no remoteURL found on remote id", { found: tuple }); res = Spec.parse(name ?? "(unknown)", first, options); break; } case "file": { if (!first) { throw error("no file path found on remote id", { found: tuple }); } res = Spec.parse(name ?? "(unknown)", `file:${first}`, options); break; } case "registry": { if (typeof first !== "string") { throw error("no registry url or name in registry ID", { found: tuple }); } if (!second) { throw error("no name/specifier in registry ID", { found: tuple }); } if (!first) { const s2 = Spec.parseArgs(second, options); if (name && s2.name !== name) { res = Spec.parse(name, `npm:${second}`, options); } else { res = s2; } break; } if (!/^https?:\/\//.test(first)) { const reg = options.registries?.[first]; if (first !== "npm" && !reg) { throw error("named registry not found in options", { name: first, found: tuple }); } res = Spec.parse( name ?? "(unknown)", `${first}:${second}`, options ); break; } const s = Spec.parse( name ?? "(unknown)", `registry:${first}#${second}`, options ); res = name && s.final.name !== name ? Spec.parse(s.final.name, s.bareSpec, options) : s; break; } case "git": { if (!first) { throw error("no git remote in git ID", { found: tuple }); } res = Spec.parse( name ?? "(unknown)", first + "#" + second, options ); break; } case "workspace": { if (!first) { throw error("no name/path on workspace id", { found: tuple }); } res = name && name !== first ? Spec.parse(name, `workspace:${first}@*`, options) : Spec.parse(first, `workspace:*`, options); break; } } seenHydratedTuples.set(cacheKey, res); return res; }; var omitDefReg = (s) => !s || s === "https://registry.npmjs.org" || s === "https://registry.npmjs.org/" ? "" : s; var seenTuples = /* @__PURE__ */ new Map(); var getTuple = (spec, mani, extra) => { const cacheKey = String(spec) + (mani.name ?? "") + (mani.version ?? "") + (extra ?? ""); const seen = seenTuples.get(cacheKey); if (seen) return seen; let res; const f = spec.final; switch (f.type) { case "registry": { const reg = omitDefReg(f.registry); if (!f.namedRegistry && reg) { for (const [alias, host] of Object.entries( spec.options.registries )) { if (reg === host) { f.namedRegistry = alias; break; } } } const version = mani.version ? mani.version.startsWith("v") ? mani.version.slice(1) : mani.version : f.bareSpec; res = [ f.type, f.namedRegistry ?? reg, `${isPackageNameConfused(spec, mani.name) ? spec.name : mani.name ?? f.name}@${version}`, extra ]; break; } case "git": { const { namedGitHost, namedGitHostPath, gitRemote, gitSelector = "" } = f; if (!gitRemote) throw error("no host on git specifier", { spec }); if (namedGitHost) { if (!namedGitHostPath) { throw error("named git host without path portion", { spec }); } res = [ f.type, `${namedGitHost}:${namedGitHostPath}`, gitSelector, extra ]; break; } else { res = [f.type, gitRemote, gitSelector, extra]; } break; } case "remote": { const { remoteURL } = f; if (!remoteURL) throw error("no URL on remote specifier", { spec }); res = [f.type, remoteURL, extra]; break; } case "file": case "workspace": throw error("Path-based dep ids are not supported", { spec }); } seenTuples.set(cacheKey, res); return res; }; var isPackageNameConfused = (spec, name) => !!spec?.name && // a nameless spec can't be checked !spec.subspec && // it's not an aliased package or using a custom protocol spec.type === "registry" && // the defined spec is of type registry spec.name !== name; var getId = (spec, mani, extra) => joinDepIDTuple(getTuple(spec, mani, extra)); var resetCaches = () => { seenHydrated.clear(); seenHydratedTuples.clear(); seenSplitDepIDs.clear(); seenTuples.clear(); }; // ../../src/dep-id/src/index.ts var seenHydrated2 = /* @__PURE__ */ new Map(); var hydrate2 = (id, name, options = {}) => { const cacheKey = (name ?? "") + id; const seen = seenHydrated2.get(cacheKey); if (seen) return seen; const res = hydrateTuple2(splitDepID(id), name, options); seenHydrated2.set(cacheKey, res); return res; }; var seenHydratedTuples2 = /* @__PURE__ */ new Map(); var hydrateTuple2 = (tuple, name, options = {}) => { const [type, first, second] = tuple; const cacheKey = (name ?? "") + type + first + (second ?? ""); const seen = seenHydratedTuples2.get(cacheKey); if (seen) return seen; let res; switch (type) { case "remote": { if (!first) throw error("no remoteURL found on remote id", { found: tuple }); res = Spec2.parse(name ?? "(unknown)", first); break; } case "file": { if (!first) { throw error("no file path found on remote id", { found: tuple }); } res = Spec2.parse(name ?? "(unknown)", `file:${first}`, options); break; } case "registry": { if (typeof first !== "string") { throw error("no registry url or name in registry ID", { found: tuple }); } if (!second) { throw error("no name/specifier in registry ID", { found: tuple }); } if (!first) { const s2 = Spec2.parse(second); if (name && s2.name !== name) { res = Spec2.parse(`${name}@npm:${second}`); } else { res = s2; } break; } if (!/^https?:\/\//.test(first)) { const reg = options.registries?.[first]; if (first !== "npm" && !reg) { throw error("named registry not found in options", { name: first, found: tuple }); } res = Spec2.parse( name ?? "(unknown)", `${first}:${second}`, options ); break; } const s = Spec2.parse( name ?? "(unknown)", `registry:${first}#${second}`, options ); res = name && s.final.name !== name ? Spec2.parse(s.final.name + "@" + s.bareSpec) : s; break; } case "git": { if (!first) { throw error("no git remote in git ID", { found: tuple }); } res = Spec2.parse( name ?? "(unknown)", first + "#" + second, options ); break; } case "workspace": { if (!first) { throw error("no name/path on workspace id", { found: tuple }); } res = name && name !== first ? Spec2.parse(name, `workspace:${first}@*`, options) : Spec2.parse(first, `workspace:*`, options); break; } } seenHydratedTuples2.set(cacheKey, res); return res; }; var resetCaches2 = () => { seenHydrated2.clear(); seenHydratedTuples2.clear(); resetCaches(); }; // ../../node_modules/.pnpm/graph-run@1.1.0/node_modules/graph-run/dist/esm/index.js import { setMaxListeners } from "node:events"; var isGraphRunError = (er) => !!er && typeof er === "object" && "cause" in er && !!er.cause && typeof er.cause === "object" && "code" in er.cause && (er.cause.code === "GRAPHRUN_NO_NODES" && "found" in er.cause && "wanted" in er.cause && typeof er.cause.wanted === "string" || er.cause.code === "GRAPHRUN_TRAVERSAL" && "path" in er.cause && Array.isArray(er.cause.path) && "node" in er.cause && "cause" in er.cause || er.cause.code === "GRAPHRUN_CYCLE_WITHOUT_PATH"); var RunnerBase = class { results = /* @__PURE__ */ new Map(); settled = /* @__PURE__ */ new Map(); dependents = /* @__PURE__ */ new Map(); directDependents = /* @__PURE__ */ new Map(); options; abortController; failFast; errors = []; from; constructor(options, from) { const ac = new AbortController(); this.from = from ?? this.constructor; this.abortController = ac; setMaxListeners(Infinity, ac.signal); this.options = options; if (!options.graph.length) { const er = new Error("no nodes provided to graph traversal", { cause: { code: "GRAPHRUN_NO_NODES", found: options.graph, wanted: "[first: Node, ...rest: Node[]]" } }); Error.captureStackTrace(er, from); throw er; } this.failFast = options.failFast !== false; const { signal } = options; if (signal !== void 0) { signal.addEventListener("abort", (reason) => ac.abort(reason), { once: true, signal: ac.signal }); } } route(n, d) { const dependents = this.dependents.get(d); if (!dependents?.has(n)) return void 0; const directDependents = this.directDependents.get(d); if (!directDependents) return void 0; if (directDependents.has(n)) { return [n, d]; } const queue = [ ...directDependents ].map((dd) => [dd, d]); let step = void 0; while (void 0 !== (step = queue.shift())) { if (!dependents.has(step[0])) continue; if (step[0] === n) { return step; } const ddd = this.directDependents.get(step[0]); if (ddd) { for (const d2 of ddd) { queue.push([d2, ...step]); } } } } cycleCheck(n, path, d) { const dependents = this.dependents.get(n) ?? /* @__PURE__ */ new Set(); this.dependents.set(n, dependents); const isCycle = dependents.has(d); if (isCycle) { const cycle = this.route(d, n); if (!cycle) { throw new Error("cycle detected, but cycle route not found", { cause: { code: "GRAPHRUN_CYCLE_WITHOUT_PATH" } }); } cycle.unshift(n); this.onCycle(d, cycle, path); return true; } const depDD = this.directDependents.get(d) ?? /* @__PURE__ */ new Set(); this.directDependents.set(d, depDD); depDD.add(n); const depDependents = this.dependents.get(d) ?? /* @__PURE__ */ new Set(); this.dependents.set(d, depDependents); for (const n2 of dependents) { depDependents.add(n2); } depDependents.add(n); return false; } handleError(er, n, path) { this.errors.push(er); this.settled.set(n, { status: "rejected", reason: er }); if (this.failFast) { this.abortController.abort(er); const e = new Error("failed graph traversal", { cause: { code: "GRAPHRUN_TRAVERSAL", node: n, path, cause: er } }); Error.captureStackTrace(e, this.from); throw e; } } handleValue(value, n) { this.results.set(n, value); this.settled.set(n, { status: "fulfilled", value }); } }; var Runner = class extends RunnerBase { running = /* @__PURE__ */ new Map(); async getDeps(n) { if (this.abortController.signal.aborted) return []; const deps = await this.options.getDeps(n); for (const d of deps) { const dependents = this.dependents.get(d) ?? /* @__PURE__ */ new Set(); this.dependents.set(d, dependents); dependents.add(n); const depDD = this.directDependents.get(d) ?? /* @__PURE__ */ new Set(); this.directDependents.set(d, depDD); depDD.add(n); } return deps; } async visit(n, path, depResults) { const { signal } = this.abortController; return this.options.visit(n, signal, path, depResults); } async onCycle(n, cycle, path) { if (this.abortController.signal.aborted) return; await this.options.onCycle?.(n, cycle, path); } async #walk(n, path) { const r = this.running.get(n); if (r) return r; if (this.settled.get(n)) return; const p = this.#step(n, path).then(() => { this.running.delete(n); }, (er) => { this.running.delete(n); throw er; }); this.running.set(n, p); return p; } async #step(n, path) { const dependents = this.dependents.get(n) ?? /* @__PURE__ */ new Set(); this.dependents.set(n, dependents); const deps = await this.getDeps(n); const awaiting = []; const depPath = [...path, n]; for (const d of deps) { if (this.abortController.signal.aborted) return; if (d === n) continue; if (this.cycleCheck(n, depPath, d)) continue; if (this.settled.get(d)) continue; awaiting.push(this.running.get(d) ?? this.#walk(d, depPath)); } if (this.abortController.signal.aborted) return; await Promise.all(awaiting); if (this.abortController.signal.aborted) return; const depRes = new Map(deps.map((d) => [d, this.results.get(d)])); try { this.handleValue(await this.visit(n, path, depRes), n); } catch (er) { this.handleError(er, n, path); } } async run() { const promises = []; for (const n of this.options.graph) { promises.push(this.#walk(n, [])); } await Promise.all(promises); } }; var RunnerSync = class extends RunnerBase { getDeps(n) { if (this.abortController.signal.aborted) return []; return this.options.getDeps(n); } visit(n, path, depResults) { const { signal } = this.abortController; return this.options.visit(n, signal, path, depResults); } onCycle(n, cycle, path) { if (this.abortController.signal.aborted) return; this.options.onCycle?.(n, cycle, path); } #walk(n, path) { if (this.settled.get(n)) return; this.#step(n, path); } #step(n, path) { const dependents = this.dependents.get(n) ?? /* @__PURE__ */ new Set(); this.dependents.set(n, dependents); const deps = this.getDeps(n); const depPath = [...path, n]; for (const d of deps) { if (this.abortController.signal.aborted) return; if (d === n) continue; if (this.cycleCheck(n, depPath, d)) continue; if (!this.settled.get(d)) this.#walk(d, depPath); } if (this.abortController.signal.aborted) return; const depRes = new Map(deps.map((d) => [d, this.results.get(d)])); try { this.handleValue(this.visit(n, path, depRes), n); } catch (er) { this.handleError(er, n, path); } } run() { for (const n of this.options.graph) { this.#walk(n, []); } return this.results; } }; var graphRun = async (options) => { const runner = new Runner(options, graphRun); await runner.run(); if (runner.errors.length) { const e = new AggregateError(runner.errors, "failed graph traversal"); Error.captureStackTrace(e, graphRun); throw e; } return runner.results; }; var graphRunSync = (options) => { const runner = new RunnerSync(options, graphRunSync); runner.run(); if (runner.errors.length) { const e = new AggregateError(runner.errors, "failed graph traversal"); Error.captureStackTrace(e, graphRunSync); throw e; } return runner.results; }; export { defaultRegistry, defaultRegistries, defaultJsrRegistries, defaultGitHosts, defaultGitHostArchives, defaultScopeRegistries, isSpec, Spec, Spec2, asDepID, joinDepIDTuple, splitDepID, baseDepID, hydrate, isPackageNameConfused, getId, hydrate2, hydrateTuple2 as hydrateTuple, resetCaches2 as resetCaches, isGraphRunError, graphRun, graphRunSync }; //# sourceMappingURL=chunk-U5J4TCIV.js.map