vlt
Version:
The vlt CLI
1,356 lines (1,348 loc) • 42.1 kB
JavaScript
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 `/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 = `/${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 `/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}:${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