// src/actions/deplint/loader.ts
import PATH from "node:path";
import { pathToFileURL } from "node:url";

// src/actions/deplint/ruleConfig.ts
var VALID_RULE_LEVELS = /* @__PURE__ */ new Set(["off", "warn", "error"]);
var VALID_RANGE_BOUNDS = /* @__PURE__ */ new Set(["infer", "major", "minor"]);
var VALID_RANGE_FORMS = /* @__PURE__ */ new Set(["broad", "shorthand"]);
var VALID_WORKSPACE_PROTOCOLS = /* @__PURE__ */ new Set(["workspace:~", "workspace:^", "workspace:*"]);
var BUILT_IN_RULE_OPTION_KEYS = {
  "deplint.peerDependencies.range-style": /* @__PURE__ */ new Set(["bound", "form", "ignore"]),
  "deplint.workspace.protocol": /* @__PURE__ */ new Set(["ignore", "protocol"])
};
function isRecord(value) {
  return typeof value === "object" && value !== null && !Array.isArray(value);
}
function isRuleLevel(value) {
  return typeof value === "string" && VALID_RULE_LEVELS.has(value);
}
function severityFromLevel(level) {
  return level === "warn" ? "warning" : "error";
}
function formatRuleConfigLocation(ruleId) {
  return `commands.deplint.rules["${ruleId}"]`;
}
function parseRuleConfig(ruleId, value) {
  if (typeof value === "string") {
    if (!isRuleLevel(value)) {
      throw new TypeError(`${formatRuleConfigLocation(ruleId)} must be one of "off", "warn", or "error"`);
    }
    return { level: value, options: {} };
  }
  if (Array.isArray(value)) {
    if (value.length !== 2) {
      throw new TypeError(`${formatRuleConfigLocation(ruleId)} tuple must be [level, options]`);
    }
    const level = value[0];
    if (!isRuleLevel(level)) {
      throw new TypeError(`${formatRuleConfigLocation(ruleId)} level must be one of "off", "warn", or "error"`);
    }
    const options = value[1];
    if (!isRecord(options)) {
      throw new TypeError(`${formatRuleConfigLocation(ruleId)} options must be an object`);
    }
    return { level, options: { ...options } };
  }
  throw new TypeError(`${formatRuleConfigLocation(ruleId)} must be a level or [level, options] tuple`);
}
function validateIgnore(ruleId, options) {
  if (options.ignore === void 0) return;
  if (!Array.isArray(options.ignore) || options.ignore.some((pattern) => typeof pattern !== "string")) {
    throw new TypeError(`${formatRuleConfigLocation(ruleId)}.ignore must be an array of strings`);
  }
}
function validateBuiltInOptions(ruleId, options, builtInRuleIds) {
  validateIgnore(ruleId, options);
  if (!builtInRuleIds.has(ruleId)) return;
  const allowedKeys = BUILT_IN_RULE_OPTION_KEYS[ruleId] ?? /* @__PURE__ */ new Set(["ignore"]);
  for (const key of Object.keys(options)) {
    if (!allowedKeys.has(key)) {
      throw new TypeError(`${formatRuleConfigLocation(ruleId)} has unknown option "${key}"`);
    }
  }
  if (ruleId === "deplint.peerDependencies.range-style" && options.bound !== void 0 && (typeof options.bound !== "string" || !VALID_RANGE_BOUNDS.has(options.bound))) {
    throw new TypeError(`${formatRuleConfigLocation(ruleId)}.bound must be "infer", "major", or "minor"`);
  }
  if (ruleId === "deplint.peerDependencies.range-style" && options.form !== void 0 && (typeof options.form !== "string" || !VALID_RANGE_FORMS.has(options.form))) {
    throw new TypeError(`${formatRuleConfigLocation(ruleId)}.form must be "broad" or "shorthand"`);
  }
  if (ruleId === "deplint.workspace.protocol" && options.protocol !== void 0 && (typeof options.protocol !== "string" || !VALID_WORKSPACE_PROTOCOLS.has(options.protocol))) {
    throw new TypeError(`${formatRuleConfigLocation(ruleId)}.protocol must be "workspace:~", "workspace:^", or "workspace:*"`);
  }
}
function normalizeDeplintRules(rules2, config, builtInRuleIds) {
  const ruleConfigs = config?.rules ?? {};
  const ruleIds = new Set(rules2.map((rule) => rule.id));
  const unknownRuleIds = Object.keys(ruleConfigs).filter((ruleId) => !ruleIds.has(ruleId));
  if (unknownRuleIds.length > 0) {
    throw new TypeError(`Unknown deplint rule ${unknownRuleIds.map((ruleId) => `"${ruleId}"`).join(", ")} in commands.deplint.rules`);
  }
  return rules2.map((rule) => {
    const ruleConfig = ruleConfigs[rule.id];
    if (ruleConfig === void 0) {
      return {
        ...rule,
        enabled: true,
        meta: { ...rule.meta, severity: "warning" },
        options: {}
      };
    }
    const { level, options } = parseRuleConfig(rule.id, ruleConfig);
    validateBuiltInOptions(rule.id, options, builtInRuleIds);
    return {
      ...rule,
      enabled: level !== "off",
      meta: level === "off" ? { ...rule.meta } : { ...rule.meta, severity: severityFromLevel(level) },
      options
    };
  });
}

// src/actions/deplint/getBasePackageName.ts
function getBasePackageName(importName) {
  const importNameScrubbed = importName.replaceAll('"', "").trim();
  if (importNameScrubbed.startsWith("@")) {
    const parts = importNameScrubbed.split("/");
    return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : importNameScrubbed;
  }
  return importNameScrubbed.split("/", 1)[0];
}

// src/actions/deplint/checkPackage/getMismatchedPeerDevVersions.ts
import chalk2 from "chalk";
import semver2 from "semver";

// src/actions/deplint/packageJsonEditor.ts
import fs2 from "node:fs";
import chalk from "chalk";
import semver from "semver";
import sortPackageJson from "sort-package-json";

// src/actions/deplint/getRequiredPeerDependencies.ts
import fs from "node:fs";
import path from "node:path";
function findDepPackageJson(location, dep) {
  let dir = location;
  while (true) {
    const candidate = path.join(dir, "node_modules", dep, "package.json");
    if (fs.existsSync(candidate)) return candidate;
    const parent = path.dirname(dir);
    if (parent === dir) return void 0;
    dir = parent;
  }
}
function getRequiredPeerDependencies(location, allDeps) {
  const required = /* @__PURE__ */ new Set();
  for (const dep of allDeps) {
    const depPkgPath = findDepPackageJson(location, dep);
    if (!(depPkgPath != null && depPkgPath.length > 0)) continue;
    try {
      const raw = fs.readFileSync(depPkgPath, "utf8");
      const pkg = JSON.parse(raw);
      const peerDeps = pkg.peerDependencies;
      const meta = pkg.peerDependenciesMeta;
      if (peerDeps) {
        const requiredPeers = Object.keys(peerDeps).filter((peer) => !(meta?.[peer]?.optional ?? false));
        for (const peer of requiredPeers) {
          required.add(peer);
        }
      }
    } catch {
    }
  }
  return required;
}

// src/actions/deplint/packageJsonEditor.ts
function formatPeerRange(version, boundType = "major") {
  const parsed = semver.parse(version);
  if (!parsed) return `~${version}`;
  if (boundType === "minor") return `>=${parsed.version} <${parsed.major}.${parsed.minor + 1}`;
  return `>=${parsed.version} <${parsed.major + 1}`;
}
function inferPeerBoundType(devRange) {
  return devRange?.startsWith("~") ?? false ? "minor" : "major";
}
function inferPeerShorthandPrefix(devRange) {
  if (!(devRange != null && devRange.length > 0)) return "~";
  if (devRange.startsWith("^")) return "^";
  if (devRange.startsWith("~")) return "~";
  const lower = semver.minVersion(devRange);
  if (!lower) return "~";
  const base = `${lower.major}.${lower.minor}`;
  try {
    if (!semver.subset(devRange, `~${base}`) && semver.subset(devRange, `^${base}`)) return "^";
  } catch {
  }
  return "~";
}
function readInstalledVersion(location, dep) {
  const depPkgPath = findDepPackageJson(location, dep);
  if (!(depPkgPath != null && depPkgPath.length > 0)) return void 0;
  try {
    const depPkg = JSON.parse(fs2.readFileSync(depPkgPath, "utf8"));
    return depPkg.version;
  } catch {
    return void 0;
  }
}
function resolvePeerLowerBound(location, dep, devRange) {
  if (devRange != null && devRange.length > 0 && devRange !== "*" && !devRange.startsWith("workspace:") && !devRange.startsWith("catalog:") && !devRange.startsWith("npm:")) {
    try {
      const min = semver.minVersion(devRange);
      if (min) return min.version;
    } catch {
    }
  }
  return readInstalledVersion(location, dep);
}
function resolveDepVersion(location, dep) {
  const version = readInstalledVersion(location, dep);
  return version != null && version.length > 0 ? `~${version}` : "*";
}
function resolveExpectedPeerVersion(location, dep, devRange, boundType) {
  const lower = resolvePeerLowerBound(location, dep, devRange);
  return lower != null && lower.length > 0 ? formatPeerRange(lower, boundType ?? inferPeerBoundType(devRange)) : "*";
}
function resolveExpectedPeerShorthandVersion(location, dep, devRange) {
  const lower = resolvePeerLowerBound(location, dep, devRange);
  if (!(lower != null && lower.length > 0)) return "*";
  const parsed = semver.parse(lower);
  if (!parsed) return devRange != null && devRange.length > 0 && devRange !== "*" ? devRange : `~${lower}`;
  return `${inferPeerShorthandPrefix(devRange)}${parsed.major}.${parsed.minor}`;
}
function resolvePeerVersionForFix(location, dep, devRange, form, boundType) {
  return form === "broad" ? resolveExpectedPeerVersion(location, dep, devRange, boundType) : resolveExpectedPeerShorthandVersion(location, dep, devRange);
}
function resolveExpectedDevVersion(location, dep) {
  const version = readInstalledVersion(location, dep);
  if (!(version != null && version.length > 0)) return "*";
  const match = /^(\d+)\.(\d+)/.exec(version);
  return match ? `~${match[1]}.${match[2]}` : `~${version}`;
}

// src/actions/deplint/checkPackage/getMismatchedPeerDevVersions.ts
function findMismatchedPeerDevVersions({
  peerDependencies,
  peerDependencyVersions,
  devDependencyVersions
}, exclude) {
  const mismatches = [];
  for (const dep of peerDependencies) {
    if (exclude?.has(dep) ?? false) continue;
    const peerVersion = peerDependencyVersions[dep];
    const devVersion = devDependencyVersions[dep];
    const hasWorkspaceProtocol = devVersion?.startsWith("workspace:") || peerVersion?.startsWith("workspace:");
    if (devVersion && peerVersion !== devVersion && !hasWorkspaceProtocol && !semver2.subset(devVersion, peerVersion)) {
      mismatches.push({
        dep,
        devVersion,
        peerVersion
      });
    }
  }
  return mismatches;
}

// src/actions/deplint/checkPackage/getUnlistedDependencies.ts
import { builtinModules } from "node:module";
import chalk3 from "chalk";

// src/actions/deplint/isTerminalPackage.ts
import fs3 from "node:fs";
var EXPORT_META_KEYS = /* @__PURE__ */ new Set([".", "./package.json", "./README.md"]);
function hasBinSetup(bin) {
  if (typeof bin === "string") return bin.length > 0;
  if (typeof bin !== "object" || bin === null || Array.isArray(bin)) return false;
  return Object.keys(bin).length > 0;
}
function isCliOnlyExports(exports) {
  if (exports === void 0) return true;
  if (typeof exports === "string") return true;
  if (typeof exports !== "object" || exports === null || Array.isArray(exports)) return false;
  return Object.keys(exports).every((k) => EXPORT_META_KEYS.has(k));
}
function hasLibrarySurface(pkg) {
  return pkg.main !== void 0 || pkg.module !== void 0 || !isCliOnlyExports(pkg.exports);
}
function withTerminalOverride(classification, isTerminalOverride) {
  if (isTerminalOverride === void 0) return classification;
  if (isTerminalOverride) {
    return {
      isTerminalPackage: true,
      kind: classification.kind === "terminal[private]" ? "terminal[private]" : "terminal[cli]"
    };
  }
  return {
    isTerminalPackage: false,
    kind: classification.kind === "library/cli" || classification.kind === "terminal[cli]" ? "library/cli" : "library"
  };
}
function classifyDeplintPackage(location, isTerminalOverride) {
  try {
    const pkg = JSON.parse(
      fs3.readFileSync(`${location}/package.json`, "utf8")
    );
    if (pkg.private === true) {
      return withTerminalOverride({
        isTerminalPackage: true,
        kind: "terminal[private]"
      }, isTerminalOverride);
    }
    if (pkg.xy?.commands?.deplint?.terminal === true) {
      return withTerminalOverride({
        isTerminalPackage: true,
        kind: "terminal[cli]"
      }, isTerminalOverride);
    }
    const hasBin = hasBinSetup(pkg.bin);
    if (hasBin && hasLibrarySurface(pkg)) {
      return withTerminalOverride({
        isTerminalPackage: false,
        kind: "library/cli"
      }, isTerminalOverride);
    }
    if (hasBin) {
      return withTerminalOverride({
        isTerminalPackage: true,
        kind: "terminal[cli]"
      }, isTerminalOverride);
    }
    return withTerminalOverride({
      isTerminalPackage: false,
      kind: "library"
    }, isTerminalOverride);
  } catch {
    return withTerminalOverride({
      isTerminalPackage: false,
      kind: "library"
    }, isTerminalOverride);
  }
}
function isTerminalPackage(location) {
  return classifyDeplintPackage(location).isTerminalPackage;
}

// src/actions/deplint/tsScriptsAliases.ts
var VARIANT_MAP = {
  "@xylabs/toolchain": "@xylabs/toolchain",
  "@xylabs/ts-scripts-react-yarn3": "@xylabs/ts-scripts-react-pnpm",
  "@xylabs/ts-scripts-react-pnpm": "@xylabs/ts-scripts-react-yarn3"
};
function isSatisfiedByTsScriptsVariant(imp, allDeps) {
  const variant = VARIANT_MAP[imp];
  return variant !== void 0 && allDeps.includes(variant);
}
function isUsedViaTsScriptsVariant(dep, imports) {
  const variant = VARIANT_MAP[dep];
  return variant !== void 0 && imports.includes(variant);
}

// src/actions/deplint/checkPackage/getUnlistedDependencies.ts
function isRuntimeImportListed(imp, name, dependencies, peerDependencies) {
  return dependencies.includes(imp) || imp === name || peerDependencies.includes(imp) || builtinModules.includes(imp);
}
function isDistTypeImportListed(imp, name, dependencies, devDependencies, peerDependencies) {
  return dependencies.includes(imp) || imp === name || dependencies.includes(`@types/${imp}`) || devDependencies.includes(`@types/${imp}`) || peerDependencies.includes(imp) || peerDependencies.includes(`@types/${imp}`) || builtinModules.includes(imp);
}
function shouldBePeerDependency(imp, _location, _currentPeers, _distImports, workspaceNames) {
  if (workspaceNames?.has(imp) ?? false) return false;
  if (imp.startsWith("@types/")) return false;
  return true;
}
function findUnlistedDependencies(name, dependencies, devDependencies, peerDependencies, externalDistImports, externalDistTypeImports) {
  const allDeps = [...dependencies, ...devDependencies, ...peerDependencies];
  const results = [];
  for (const imp of externalDistImports) {
    if (!isRuntimeImportListed(imp, name, dependencies, peerDependencies) && !isSatisfiedByTsScriptsVariant(imp, allDeps)) {
      results.push({ imp, section: "dependencies" });
    }
  }
  for (const imp of externalDistTypeImports) {
    if (!isDistTypeImportListed(imp, name, dependencies, devDependencies, peerDependencies) && !isSatisfiedByTsScriptsVariant(imp, allDeps)) {
      results.push({ imp, section: "dependencies" });
    }
  }
  return results;
}

// src/actions/deplint/checkPackage/getUnlistedDevDependencies.ts
import { builtinModules as builtinModules2 } from "node:module";
import chalk4 from "chalk";
function findUnlistedDevDeps(name, dependencies, devDependencies, peerDependencies, externalAllImports, distImports, externalDistTypeImports) {
  const results = [];
  for (const imp of externalAllImports) {
    if (!distImports.includes(imp) && !externalDistTypeImports.includes(imp) && imp !== name && !dependencies.includes(imp) && !dependencies.includes(`@types/${imp}`) && !peerDependencies.includes(imp) && !peerDependencies.includes(`@types/${imp}`) && !devDependencies.includes(imp) && !devDependencies.includes(`@types/${imp}`) && !builtinModules2.includes(imp) && !isSatisfiedByTsScriptsVariant(imp, [...dependencies, ...devDependencies, ...peerDependencies])) {
      results.push(imp);
    }
  }
  return results;
}

// src/actions/deplint/checkPackage/getUnnecessaryPeerDependencies.ts
import chalk5 from "chalk";

// src/actions/deplint/checkPackage/getUnsatisfiedPeerDependencies.ts
import fs4 from "node:fs";
import semver3 from "semver";
function readDepPackageJson(location, dep) {
  const depPkgPath = findDepPackageJson(location, dep);
  if (!(depPkgPath != null && depPkgPath.length > 0)) return void 0;
  try {
    return JSON.parse(fs4.readFileSync(depPkgPath, "utf8"));
  } catch {
    return void 0;
  }
}
function readPeerDeps(location, dep) {
  const pkg = readDepPackageJson(location, dep);
  if (!pkg) return [];
  const peers = pkg.peerDependencies;
  return Object.keys(peers ?? {});
}
function readPeerVersionRange(location, dep, peer) {
  const pkg = readDepPackageJson(location, dep);
  if (!pkg) return void 0;
  const peers = pkg.peerDependencies;
  return peers?.[peer];
}
function readInstalledVersion2(location, dep) {
  const pkg = readDepPackageJson(location, dep);
  if (!pkg) return void 0;
  return pkg.version;
}
function isPeerOptionalInAll(location, peer, sources) {
  for (const source of sources) {
    const pkg = readDepPackageJson(location, source.requiredBy);
    if (!pkg) continue;
    const meta = pkg.peerDependenciesMeta?.[peer];
    if (!(meta?.optional ?? false)) return false;
  }
  return true;
}
var MAX_TRANSITIVE_DEPTH = 2;
function collectPeerSources(location, dependencies, devDependencies, peerDependencies = []) {
  const peerSources = /* @__PURE__ */ new Map();
  const visited = /* @__PURE__ */ new Set();
  function addPeerSource(peer, source) {
    const sources = peerSources.get(peer) ?? [];
    sources.push(source);
    peerSources.set(peer, sources);
  }
  function collectFromDeps(deps, isRuntime, chain) {
    for (const dep of deps) {
      const visitKey = `${dep}:${chain.join(">")}`;
      if (visited.has(visitKey)) continue;
      visited.add(visitKey);
      for (const peer of readPeerDeps(location, dep)) {
        addPeerSource(peer, {
          chain: chain.length > 0 ? [...chain, dep] : void 0,
          isRuntimeDep: isRuntime,
          requiredBy: dep
        });
      }
      if (chain.length < MAX_TRANSITIVE_DEPTH) {
        const depPkg = readDepPackageJson(location, dep);
        if (depPkg) {
          const transitiveDeps = Object.keys(depPkg.dependencies ?? {});
          collectFromDeps(transitiveDeps, isRuntime, [...chain, dep]);
        }
      }
    }
  }
  const runtimeRoots = [.../* @__PURE__ */ new Set([...dependencies, ...peerDependencies])];
  collectFromDeps(runtimeRoots, true, []);
  const devOnly = devDependencies.filter((d) => !runtimeRoots.includes(d));
  collectFromDeps(devOnly, false, []);
  return peerSources;
}
function getRequiredTransitivePeers(location, {
  dependencies,
  devDependencies,
  peerDependencies
}) {
  const peerSources = collectPeerSources(location, dependencies, devDependencies, peerDependencies);
  return new Set(peerSources.keys());
}
function resolveVersionRange(location, sources, peer) {
  for (const source of sources) {
    const range = readPeerVersionRange(location, source.requiredBy, peer);
    if (range != null && range.length > 0) return range;
  }
  return "*";
}
function checkVersionSatisfaction(location, peer, requestedRange) {
  const installedVersion = readInstalledVersion2(location, peer);
  if (!(installedVersion != null && installedVersion.length > 0)) return { satisfied: true };
  if (requestedRange === "*") return { installedVersion, satisfied: true };
  if (requestedRange.startsWith("workspace:")) return { installedVersion, satisfied: true };
  try {
    const isSatisfied = semver3.satisfies(installedVersion, requestedRange, { includePrerelease: true });
    return { installedVersion, satisfied: isSatisfied };
  } catch {
    return { installedVersion, satisfied: true };
  }
}
function findDeclaredPeerVersionMismatches(name, location, peerDependencies, peerDependencyVersions, exclude) {
  const results = [];
  for (const peer of peerDependencies) {
    if ((exclude?.has(peer) ?? false) || peer === name) continue;
    const declaredRange = peerDependencyVersions[peer];
    if (!declaredRange || declaredRange === "*") continue;
    const { installedVersion, satisfied: isSatisfied } = checkVersionSatisfaction(location, peer, declaredRange);
    if (!isSatisfied) {
      results.push({
        hasRuntimeSource: true,
        installedVersion,
        peer,
        reason: "version-mismatch",
        sources: [{ isRuntimeDep: true, requiredBy: name }],
        versionRange: declaredRange
      });
    }
  }
  return results;
}
function classifyPeer(peer, sources, ctx) {
  const {
    location,
    depsSet,
    devDepsSet,
    peerDepsSet,
    isTerminal,
    forceDevs,
    forcePeerOptional
  } = ctx;
  if (forceDevs.has(peer)) return void 0;
  const isPeerForced = forcePeerOptional?.has(peer) ?? false;
  const runtimeSources = sources.filter((s) => s.isRuntimeDep);
  const hasRuntimeSource = runtimeSources.length > 0 && (isPeerForced || !isPeerOptionalInAll(location, peer, runtimeSources));
  if (!depsSet.has(peer) && !devDepsSet.has(peer)) {
    return {
      hasRuntimeSource,
      peer,
      reason: "missing",
      sources,
      versionRange: resolveVersionRange(location, sources, peer)
    };
  }
  const directRuntimeSources = sources.filter((s) => s.isRuntimeDep && !s.chain);
  const shouldForwardRuntime = directRuntimeSources.length > 0 && (isPeerForced || !isPeerOptionalInAll(location, peer, directRuntimeSources));
  if (shouldForwardRuntime && !isTerminal && !depsSet.has(peer) && !peerDepsSet.has(peer)) {
    return {
      hasRuntimeSource,
      peer,
      reason: "under-exposed",
      sources,
      versionRange: resolveVersionRange(location, sources, peer)
    };
  }
  const versionRange = resolveVersionRange(location, sources, peer);
  const { installedVersion, satisfied: isSatisfied } = checkVersionSatisfaction(location, peer, versionRange);
  if (isSatisfied) return void 0;
  return {
    hasRuntimeSource,
    installedVersion,
    mismatchedSources: findMismatchedSources(location, sources, peer, installedVersion),
    peer,
    reason: "version-mismatch",
    sources,
    versionRange
  };
}
function findUnsatisfiedPeers({ name, location }, {
  dependencies,
  devDependencies,
  peerDependencies,
  peerDependencyVersions
}, exclude, isTerminal, forcePeerOptional, forceDevs) {
  const peerSources = collectPeerSources(location, dependencies, devDependencies, peerDependencies);
  const ctx = {
    depsSet: new Set(dependencies),
    devDepsSet: new Set(devDependencies),
    forceDevs: forceDevs ?? /* @__PURE__ */ new Set(),
    forcePeerOptional,
    isTerminal: isTerminal ?? isTerminalPackage(location),
    location,
    peerDepsSet: new Set(peerDependencies)
  };
  const unsatisfied = [];
  for (const [peer, sources] of peerSources) {
    if ((exclude?.has(peer) ?? false) || peer === name) continue;
    if (!(forcePeerOptional?.has(peer) ?? false) && isPeerOptionalInAll(location, peer, sources)) continue;
    const finding = classifyPeer(peer, sources, ctx);
    if (finding) unsatisfied.push(finding);
  }
  const declaredMismatches = findDeclaredPeerVersionMismatches(name, location, peerDependencies, peerDependencyVersions, exclude).filter((m) => !(forceDevs?.has(m.peer) ?? false));
  return [
    ...unsatisfied,
    ...declaredMismatches
  ];
}
function findMismatchedSources(location, sources, peer, installedVersion) {
  if (!(installedVersion != null && installedVersion.length > 0)) return [];
  return sources.filter((source) => {
    const range = readPeerVersionRange(location, source.requiredBy, peer);
    if (!(range != null && range.length > 0) || range === "*" || range.startsWith("workspace:")) return false;
    try {
      return !semver3.satisfies(installedVersion, range, { includePrerelease: true });
    } catch {
      return false;
    }
  });
}
function resolvePeerTargetSections(hasRuntimeSource, isTerminal) {
  if (!hasRuntimeSource) return ["devDependencies"];
  if (isTerminal) return ["dependencies"];
  return ["peerDependencies", "devDependencies"];
}

// src/actions/deplint/checkPackage/getUnnecessaryPeerDependencies.ts
function isPeerImportedInDist(dep, externalDistImports, externalDistTypeImports) {
  const baseName = dep.replace(/^@types\//, "");
  return externalDistImports.includes(dep) || externalDistImports.includes(baseName) || externalDistTypeImports.includes(dep) || externalDistTypeImports.includes(baseName);
}
function findUnrequestedPeerDeps(location, packageParams, { externalDistImports, externalDistTypeImports }, isTerminal, exclude) {
  const requiredPeers = isTerminal ? null : getRequiredTransitivePeers(location, packageParams);
  const unrequested = [];
  for (const dep of packageParams.peerDependencies) {
    if (exclude?.has(dep) ?? false) continue;
    if (packageParams.dependencies.includes(dep)) continue;
    if (!isPeerImportedInDist(dep, externalDistImports, externalDistTypeImports)) continue;
    if (!(requiredPeers?.has(dep) ?? false)) {
      unrequested.push(dep);
    }
  }
  return unrequested;
}
function findRedundantPeerDeps({ peerDependencies, dependencies }, exclude) {
  const depsSet = new Set(dependencies);
  const redundant = [];
  for (const dep of peerDependencies) {
    if (exclude?.has(dep) ?? false) continue;
    if (depsSet.has(dep)) {
      redundant.push(dep);
    }
  }
  return redundant;
}

// src/actions/deplint/checkPackage/getUnusedDependencies.ts
import chalk6 from "chalk";
function isDepImported(dep, distImports, distTypeImports) {
  const baseName = dep.replace(/^@types\//, "");
  return distImports.includes(dep) || distImports.includes(baseName) || distTypeImports.includes(dep) || distTypeImports.includes(baseName);
}
function findUnusedDependencies(location, dependencies, devDependencies, externalDistImports, externalDistTypeImports, externalAllImports, exclude) {
  const runtimeRequiredPeers = getRequiredPeerDependencies(location, dependencies);
  const devRequiredPeers = getRequiredPeerDependencies(location, devDependencies);
  const results = [];
  for (const dep of dependencies) {
    if (exclude?.has(dep) ?? false) continue;
    if (runtimeRequiredPeers.has(dep)) continue;
    const isImported = isDepImported(dep, externalDistImports, externalDistTypeImports);
    if (isImported || isUsedViaTsScriptsVariant(dep, [...externalDistImports, ...externalDistTypeImports])) continue;
    if (devRequiredPeers.has(dep)) {
      results.push({
        dep,
        kind: "move-to-dev",
        reason: "only needed as peer of devDependencies"
      });
    } else if (externalAllImports.includes(dep)) {
      results.push({ dep, kind: "move-to-dev" });
    } else {
      results.push({ dep, kind: "remove" });
    }
  }
  return results;
}

// src/actions/deplint/checkPackage/getUnusedDevDependencies.ts
import chalk7 from "chalk";

// src/actions/deplint/getCliReferencedPackagesFromFiles.ts
import fs6 from "node:fs";
import path3 from "node:path";
import ts from "typescript";

// src/actions/deplint/getScriptReferencedPackages.ts
import fs5 from "node:fs";
import path2 from "node:path";
function getBinNames(location, dep) {
  const depPkgPath = findDepPackageJson(location, dep);
  if (!(depPkgPath != null && depPkgPath.length > 0)) return [];
  try {
    const raw = fs5.readFileSync(depPkgPath, "utf8");
    const pkg = JSON.parse(raw);
    const bin = pkg.bin;
    if (bin == null) return [];
    if (typeof bin === "string") return [pkg.name?.split("/").pop() ?? dep];
    if (typeof bin !== "object" || Array.isArray(bin)) return [];
    return Object.keys(bin);
  } catch {
    return [];
  }
}
function tokenizeScript(script) {
  return script.split(/[&|;$()"`\s]+/).map((t) => t.trim()).filter(Boolean);
}
function getScriptReferencedPackages(location, allDeps) {
  const pkgPath = path2.join(location, "package.json");
  let scripts;
  try {
    const raw = fs5.readFileSync(pkgPath, "utf8");
    const pkg = JSON.parse(raw);
    scripts = pkg.scripts ?? {};
  } catch {
    return /* @__PURE__ */ new Set();
  }
  const scriptText = Object.values(scripts).join(" ");
  const tokens = new Set(tokenizeScript(scriptText));
  const binToPackage = /* @__PURE__ */ new Map();
  for (const dep of allDeps) {
    const bins = getBinNames(location, dep);
    for (const bin of bins) {
      binToPackage.set(bin, dep);
    }
  }
  const referenced = /* @__PURE__ */ new Set();
  for (const token of tokens) {
    const baseName = getBasePackageName(token);
    if (allDeps.includes(baseName)) {
      referenced.add(baseName);
    }
    const pkg = binToPackage.get(token);
    if (pkg != null && pkg.length > 0) {
      referenced.add(pkg);
    }
  }
  return referenced;
}

// src/actions/deplint/getCliReferencedPackagesFromFiles.ts
var shellCommandFunctions = /* @__PURE__ */ new Set(["execSync", "exec"]);
var directExecFunctions = /* @__PURE__ */ new Set(["spawn", "spawnSync", "execFile", "execFileSync"]);
var allExecFunctions = /* @__PURE__ */ new Set([...shellCommandFunctions, ...directExecFunctions]);
function getCommandTokensFromFile(filePath) {
  const tokens = /* @__PURE__ */ new Set();
  let sourceCode;
  try {
    sourceCode = fs6.readFileSync(filePath, "utf8");
  } catch {
    return tokens;
  }
  const isMjsFile = filePath.endsWith(".mjs");
  const sourceFile = ts.createSourceFile(
    path3.basename(filePath),
    sourceCode,
    ts.ScriptTarget.Latest,
    true,
    isMjsFile ? ts.ScriptKind.JS : void 0
  );
  function visit(node) {
    if (ts.isCallExpression(node) && node.arguments.length > 0) {
      const fnName = getFunctionName(node.expression);
      if (fnName != null && fnName.length > 0 && allExecFunctions.has(fnName)) {
        const firstArg = node.arguments[0];
        if (ts.isStringLiteral(firstArg) || ts.isNoSubstitutionTemplateLiteral(firstArg)) {
          const value = firstArg.text;
          if (shellCommandFunctions.has(fnName)) {
            for (const token of tokenizeScript(value)) {
              tokens.add(token);
            }
          } else {
            tokens.add(value);
          }
        } else if (ts.isTemplateExpression(firstArg)) {
          const head = firstArg.head.text;
          if (head) {
            for (const token of tokenizeScript(head)) {
              tokens.add(token);
            }
          }
        }
      }
    }
    ts.forEachChild(node, visit);
  }
  visit(sourceFile);
  return tokens;
}
function getFunctionName(expr) {
  if (ts.isIdentifier(expr)) {
    return expr.text;
  }
  if (ts.isPropertyAccessExpression(expr) && ts.isIdentifier(expr.name)) {
    return expr.name.text;
  }
  return void 0;
}
function getCliReferencedPackagesFromFiles(allFiles, location, allDeps) {
  const allTokens = /* @__PURE__ */ new Set();
  for (const file of allFiles) {
    for (const token of getCommandTokensFromFile(file)) {
      allTokens.add(token);
    }
  }
  if (allTokens.size === 0) return /* @__PURE__ */ new Set();
  const binToPackage = /* @__PURE__ */ new Map();
  for (const dep of allDeps) {
    for (const bin of getBinNames(location, dep)) {
      binToPackage.set(bin, dep);
    }
  }
  const referenced = /* @__PURE__ */ new Set();
  for (const token of allTokens) {
    const baseName = getBasePackageName(token);
    if (allDeps.includes(baseName)) {
      referenced.add(baseName);
    }
    const pkg = binToPackage.get(token);
    if (pkg != null && pkg.length > 0) {
      referenced.add(pkg);
    }
  }
  return referenced;
}

// src/actions/deplint/implicitDevDependencies.ts
import fs7 from "node:fs";
var hasFileWithExtension = (files, extensions) => files.some((f) => extensions.some((ext) => f.endsWith(ext)));
var tsExtensions = [".ts", ".tsx", ".mts", ".cts"];
var hasTypescriptFiles = ({ allFiles }) => hasFileWithExtension(allFiles, tsExtensions);
var decoratorPattern = /^\s*@[a-zA-Z]\w*/m;
var hasDecorators = ({ allFiles }) => allFiles.filter((f) => tsExtensions.some((ext) => f.endsWith(ext))).some((file) => {
  try {
    const content = fs7.readFileSync(file, "utf8");
    return decoratorPattern.test(content);
  } catch {
    return false;
  }
});
var hasDependencyRequiringTslib = ({ location, allDependencies }) => allDependencies.some((dep) => {
  const pkgPath = findDepPackageJson(location, dep);
  if (!(pkgPath != null && pkgPath.length > 0)) return false;
  try {
    const pkg = JSON.parse(fs7.readFileSync(pkgPath, "utf8"));
    const peers = pkg.peerDependencies;
    return peers !== void 0 && "tslib" in peers;
  } catch {
    return false;
  }
});
var importPlugins = /* @__PURE__ */ new Set(["eslint-plugin-import-x", "eslint-plugin-import"]);
function hasImportPlugin({ location, allDependencies }) {
  if (allDependencies.some((d) => importPlugins.has(d))) return true;
  for (const dep of allDependencies) {
    const pkgPath = findDepPackageJson(location, dep);
    if (!(pkgPath != null && pkgPath.length > 0)) continue;
    try {
      const pkg = JSON.parse(fs7.readFileSync(pkgPath, "utf8"));
      const transitiveDeps = [
        ...Object.keys(pkg.dependencies ?? {}),
        ...Object.keys(pkg.peerDependencies ?? {})
      ];
      if (transitiveDeps.some((d) => importPlugins.has(d))) return true;
    } catch {
    }
  }
  return false;
}
var hasVitest = ({ allDependencies }) => allDependencies.includes("vitest");
var rules = [
  {
    package: "typescript",
    isNeeded: hasTypescriptFiles
  },
  {
    package: "eslint-import-resolver-typescript",
    isNeeded: (context) => hasTypescriptFiles(context) && context.allDependencies.includes("eslint") && hasImportPlugin(context)
  },
  {
    package: "tslib",
    isNeeded: (context) => hasDecorators(context) || hasDependencyRequiringTslib(context)
  },
  {
    package: "@vitest/coverage-v8",
    isNeeded: hasVitest
  },
  {
    package: "@xylabs/toolchain",
    isNeeded: hasTypescriptFiles
  }
];
function getImplicitDevDependencies(context) {
  const implicit = /* @__PURE__ */ new Set();
  for (const rule of rules) {
    if (rule.isNeeded(context)) {
      implicit.add(rule.package);
    }
  }
  return implicit;
}

// src/actions/deplint/checkPackage/getUnusedDevDependencies.ts
var allExternalImports = ({
  externalAllImports,
  externalDistImports,
  externalDistTypeImports
}) => {
  return /* @__PURE__ */ new Set([
    ...externalAllImports,
    ...externalDistImports,
    ...externalDistTypeImports
  ]);
};
function isDevDepUsed(dep, allImports, implicitDeps, requiredPeers, scriptRefs, cliRefs) {
  if (implicitDeps.has(dep)) return true;
  if (requiredPeers.has(dep)) return true;
  if (scriptRefs.has(dep)) return true;
  if (cliRefs.has(dep)) return true;
  if (dep.startsWith("@types/")) {
    const baseName = dep.replace(/^@types\//, "");
    return allImports.has(baseName) || allImports.has(dep) || implicitDeps.has(baseName);
  }
  if (allImports.has(dep)) return true;
  return isUsedViaTsScriptsVariant(dep, [...allImports]);
}
function findUnusedDevDeps(location, dependencies, devDependencies, peerDependencies, sourceParams, fileContext, exclude) {
  const allImports = allExternalImports(sourceParams);
  const allDeps = [...dependencies, ...devDependencies, ...peerDependencies];
  const implicitDeps = getImplicitDevDependencies({
    ...fileContext,
    allDependencies: allDeps,
    location
  });
  const requiredPeers = getRequiredPeerDependencies(location, allDeps);
  const scriptRefs = getScriptReferencedPackages(location, allDeps);
  const cliRefs = getCliReferencedPackagesFromFiles(fileContext.allFiles, location, allDeps);
  const unused = [];
  for (const dep of devDependencies) {
    if (exclude?.has(dep) ?? false) continue;
    if (dependencies.includes(dep) || peerDependencies.includes(dep)) continue;
    if (!isDevDepUsed(dep, allImports, implicitDeps, requiredPeers, scriptRefs, cliRefs)) {
      unused.push(dep);
    }
  }
  return unused;
}

// src/actions/deplint/checkPackage/getUnusedPeerDependencies.ts
import chalk8 from "chalk";
function isPeerUsed(dep, externalDistImports, externalDistTypeImports) {
  const baseName = dep.replace(/^@types\//, "");
  return externalDistImports.includes(dep) || externalDistImports.includes(baseName) || externalDistTypeImports.includes(dep) || externalDistTypeImports.includes(baseName);
}
function findUnusedPeerDeps(peerDependencies, externalDistImports, externalDistTypeImports, exclude) {
  const unused = [];
  for (const dep of peerDependencies) {
    if (exclude?.has(dep) ?? false) continue;
    if (!isPeerUsed(dep, externalDistImports, externalDistTypeImports)) {
      unused.push(dep);
    }
  }
  return unused;
}

// src/actions/deplint/checkPackage/getWorkspaceVersionProblems.ts
import chalk9 from "chalk";
import semver4 from "semver";
function checkSection(deps, versions, section, workspaceNames, problems, expectedVersion) {
  for (const dep of deps) {
    if (!workspaceNames.has(dep)) continue;
    const version = versions[dep];
    const isInvalidVersion = expectedVersion === void 0 ? version !== void 0 && !version.startsWith("workspace:") : version !== expectedVersion;
    if (version !== void 0 && isInvalidVersion) {
      problems.push({
        dep,
        expectedVersion,
        section,
        version
      });
    }
  }
}
function findWorkspaceVersionProblems(packageParams, workspaceNames, expectedVersion) {
  const problems = [];
  checkSection(packageParams.dependencies, packageParams.dependencyVersions, "dependencies", workspaceNames, problems, expectedVersion);
  checkSection(packageParams.devDependencies, packageParams.devDependencyVersions, "devDependencies", workspaceNames, problems, expectedVersion);
  checkSection(packageParams.peerDependencies, packageParams.peerDependencyVersions, "peerDependencies", workspaceNames, problems, expectedVersion);
  return problems;
}

// src/actions/deplint/peerRangeOptions.ts
function resolvePeerRangeBoundOption(options) {
  return options.bound === "major" || options.bound === "minor" ? options.bound : void 0;
}
function resolvePeerRangeFormOption(options) {
  if (options.form === "broad" || options.form === "shorthand") return options.form;
  return options.bound === void 0 ? "shorthand" : "broad";
}
function isBroadPeerRange(range) {
  return /(?:^|\s)>=\s*\d/.test(range) && /(?:^|\s)<\s*\d/.test(range);
}

// src/actions/deplint/rulesDiagnostic.ts
function resolvedAddFix(context, dependency, section, detail, isOptional) {
  const devRange = context.packageParams.devDependencyVersions[dependency];
  const version = section === "peerDependencies" ? resolvePeerVersionForFix(
    context.workspace.location,
    dependency,
    devRange,
    context.peerRangeForm,
    context.peerRangeBound
  ) : resolveDepVersion(context.workspace.location, dependency);
  return {
    action: "add",
    dependency,
    detail,
    ...section === "peerDependencies" && isOptional !== void 0 && { isOptional },
    section,
    version
  };
}

// src/actions/deplint/rulesMisplaced.ts
var misplacedDependenciesRule = {
  category: "dependencies",
  id: "deplint.dependencies.misplaced",
  meta: {
    description: "Dependencies declared in the wrong package.json section",
    fixable: ["manifest"],
    severity: "error"
  },
  evaluate(context) {
    for (const dep of context.packageParams.dependencies) {
      if (context.forceDevs.has(dep)) {
        context.report({
          data: { dep, mode: "to-dev" },
          dependency: dep,
          message: `dependency ${dep} should be a devDependency \u2014 configured as refType "dev"`
        });
        continue;
      }
      if (context.isTerminalPackage) continue;
      if (context.forceDeps.has(dep)) continue;
      if (context.packageParams.dependencyVersions[dep]?.startsWith("workspace:")) continue;
      if (context.forcePeers.has(dep) || shouldBePeerDependency(dep, context.workspace.location, context.packageParams.peerDependencies, context.sourceParams.externalDistImports, context.workspaceNames)) {
        const reason = context.forcePeers.has(dep) ? 'configured as refType "peer"' : "external runtime dep \u2014 consumers should control the version";
        context.report({
          data: {
            dep,
            mode: "to-peer",
            needsDevCompanion: !context.packageParams.devDependencies.includes(dep)
          },
          dependency: dep,
          message: `dependency ${dep} should be a peerDependency \u2014 ${reason}`
        });
      }
    }
  },
  resolveFixes(diagnostic, context) {
    const data = diagnostic.data;
    if (!data) return [];
    if (data.mode === "to-dev") {
      return [{
        action: "move",
        dependency: data.dep,
        detail: "moved from dependencies to devDependencies",
        fromSection: "dependencies",
        toSection: "devDependencies"
      }];
    }
    const optional = context.forcePeerOptional.get(data.dep);
    const fixes = [{
      action: "move",
      dependency: data.dep,
      detail: "moved from dependencies to peerDependencies",
      fromSection: "dependencies",
      ...optional !== void 0 && { optional },
      toSection: "peerDependencies"
    }];
    if (data.needsDevCompanion ?? false) {
      fixes.push(resolvedAddFix(context, data.dep, "devDependencies", "added to devDependencies"));
    }
    return fixes;
  }
};
var misplacedPeerDependenciesRule = {
  category: "peerDependencies",
  id: "deplint.peerDependencies.misplaced",
  meta: {
    description: "Peer dependencies declared in the wrong package.json section",
    fixable: ["manifest"],
    severity: "error"
  },
  evaluate(context) {
    for (const dep of context.packageParams.peerDependencies) {
      const version = context.packageParams.peerDependencyVersions[dep] ?? (context.workspaceNames?.has(dep) ?? false ? "workspace:~" : "*");
      if (context.forceDeps.has(dep)) {
        const isAlreadyIn = context.packageParams.dependencies.includes(dep);
        context.report({
          data: {
            alreadyInTarget: isAlreadyIn,
            dep,
            mode: "to-dep",
            version
          },
          dependency: dep,
          message: `peerDependency ${dep} should be a dependency \u2014 configured as refType "dep"`
        });
        continue;
      }
      if (context.forceDevs.has(dep)) {
        const isAlreadyIn = context.packageParams.devDependencies.includes(dep);
        context.report({
          data: {
            alreadyInTarget: isAlreadyIn,
            dep,
            mode: "to-dev",
            version
          },
          dependency: dep,
          message: `peerDependency ${dep} should be a devDependency \u2014 configured as refType "dev"`
        });
        continue;
      }
      if ((context.workspaceNames?.has(dep) ?? false) && !context.forcePeers.has(dep)) {
        const isAlreadyIn = context.packageParams.dependencies.includes(dep);
        context.report({
          data: {
            alreadyInTarget: isAlreadyIn,
            dep,
            mode: "to-dep",
            version
          },
          dependency: dep,
          message: `peerDependency ${dep} should be a dependency \u2014 sibling workspace packages ship in lockstep; set refType "peer" in xy.config.ts to override`
        });
      }
    }
  },
  resolveFixes(diagnostic) {
    const data = diagnostic.data;
    if (!data) return [];
    if (data.alreadyInTarget ?? false) {
      return [{
        action: "remove",
        dependency: data.dep,
        detail: `removed from peerDependencies (already in ${data.mode === "to-dep" ? "dependencies" : "devDependencies"})`,
        section: "peerDependencies"
      }];
    }
    return [{
      action: "move",
      dependency: data.dep,
      detail: data.mode === "to-dep" ? "moved from peerDependencies to dependencies" : "moved from peerDependencies to devDependencies",
      fromSection: "peerDependencies",
      toSection: data.mode === "to-dep" ? "dependencies" : "devDependencies",
      version: data.version
    }];
  }
};

// src/actions/deplint/versionMismatchFixes.ts
function sectionLookupsFor(context) {
  const {
    dependencies,
    devDependencies,
    peerDependencies,
    dependencyVersions,
    devDependencyVersions,
    peerDependencyVersions
  } = context.packageParams;
  return [
    ["dependencies", dependencies, dependencyVersions],
    ["devDependencies", devDependencies, devDependencyVersions],
    ["peerDependencies", peerDependencies, peerDependencyVersions]
  ];
}
function eligibleSourceBumpSections(dep, sectionLookups) {
  const matches = [];
  for (const [section, names, versions] of sectionLookups) {
    if (!names.includes(dep)) continue;
    const current = versions[dep];
    if (!current || current.startsWith("workspace:")) continue;
    matches.push({ current, section });
  }
  return matches;
}
function addSourceBumpFixes(context, finding, fixes) {
  if (!(finding.installedVersion != null && finding.installedVersion.length > 0) || !finding.mismatchedSources) return;
  const sectionLookups = sectionLookupsFor(context);
  const seen = /* @__PURE__ */ new Set();
  const uniqueSources = finding.mismatchedSources.filter((source) => {
    const dep = source.requiredBy;
    if (seen.has(dep) || dep === context.workspace.name) return false;
    seen.add(dep);
    return true;
  });
  for (const source of uniqueSources) {
    const dep = source.requiredBy;
    for (const { current, section } of eligibleSourceBumpSections(dep, sectionLookups)) {
      fixes.push({
        action: "resolve-peer-bump",
        currentRange: current,
        dependency: dep,
        detail: `bump ${section} range so a newer version of ${dep} is installed that accepts peer ${finding.peer}@${finding.installedVersion}`,
        installedPeerVersion: finding.installedVersion,
        peer: finding.peer,
        section
      });
    }
  }
}
function generateVersionMismatchFixes(context, finding) {
  const fixes = [];
  const devRange = context.packageParams.devDependencyVersions[finding.peer];
  const expectedPeerVersion = resolvePeerVersionForFix(
    context.workspace.location,
    finding.peer,
    devRange,
    context.peerRangeForm,
    context.peerRangeBound
  );
  if (expectedPeerVersion !== "*" && context.packageParams.peerDependencies.includes(finding.peer)) {
    const peerVersion = context.packageParams.peerDependencyVersions[finding.peer];
    if (!peerVersion?.startsWith("workspace:")) {
      fixes.push({
        action: "set-version",
        dependency: finding.peer,
        detail: `updated peerDependency version to match installed (${finding.installedVersion})`,
        section: "peerDependencies",
        version: expectedPeerVersion
      });
    }
  }
  const expectedDevVersion = resolveExpectedDevVersion(context.workspace.location, finding.peer);
  if (expectedDevVersion !== "*" && context.packageParams.devDependencies.includes(finding.peer)) {
    const devVersion = context.packageParams.devDependencyVersions[finding.peer];
    if (devVersion && !devVersion.startsWith("workspace:")) {
      fixes.push({
        action: "set-version",
        dependency: finding.peer,
        detail: `updated devDependency version to match installed (${finding.installedVersion})`,
        section: "devDependencies",
        version: expectedDevVersion
      });
    }
  }
  addSourceBumpFixes(context, finding, fixes);
  return fixes;
}

// src/actions/deplint/rules.ts
function resolvePromotedPeerOptional(context, peer, sources) {
  const override = context.forcePeerOptional.get(peer);
  if (override !== void 0) return override;
  if (!sources || sources.length === 0) return void 0;
  return isPeerOptionalInAll(context.workspace.location, peer, sources);
}
var WORKSPACE_PROTOCOLS = ["workspace:*", "workspace:^", "workspace:~"];
function resolveWorkspaceProtocolOption(options) {
  return WORKSPACE_PROTOCOLS.find((protocol) => protocol === options.protocol);
}
var unlistedDependenciesRule = {
  category: "dependencies",
  id: "deplint.dependencies.unlisted",
  meta: {
    description: "Runtime imports missing from package.json",
    fixable: ["manifest"],
    severity: "error"
  },
  evaluate(context) {
    const findings = findUnlistedDependencies(
      context.workspace.name,
      context.packageParams.dependencies,
      context.packageParams.devDependencies,
      context.packageParams.peerDependencies,
      context.sourceParams.externalDistImports,
      context.sourceParams.externalDistTypeImports
    );
    for (const { imp, section } of findings) {
      if (context.forceDevs.has(imp)) {
        if (context.packageParams.devDependencies.includes(imp)) continue;
        context.report({
          data: { imp, mode: "forced-dev" },
          dependency: imp,
          evidence: context.sourceParams.distImportPaths[imp],
          message: `Missing devDependency in package.json: ${imp}`
        });
        continue;
      }
      const isPeer = !context.isTerminalPackage && section === "dependencies" && !context.forceDeps.has(imp) && shouldBePeerDependency(imp, context.workspace.location, context.packageParams.peerDependencies, context.sourceParams.externalDistImports, context.workspaceNames);
      context.report({
        data: {
          imp,
          mode: isPeer ? "peer-companion" : "direct",
          section
        },
        dependency: imp,
        evidence: context.sourceParams.distImportPaths[imp],
        message: `Missing dependency in package.json: ${imp}`
      });
    }
  },
  resolveFixes(diagnostic, context) {
    const data = diagnostic.data;
    if (!data) return [];
    if (data.mode === "forced-dev") {
      return [resolvedAddFix(context, data.imp, "devDependencies", "added to devDependencies")];
    }
    if (data.mode === "peer-companion") {
      const optional = resolvePromotedPeerOptional(context, data.imp);
      return ["peerDependencies", "devDependencies"].map(
        (section) => resolvedAddFix(
          context,
          data.imp,
          section,
          `added to ${section}`,
          section === "peerDependencies" ? optional : void 0
        )
      );
    }
    return data.section ? [resolvedAddFix(context, data.imp, data.section, `added to ${data.section}`)] : [];
  }
};
var unusedDependenciesRule = {
  category: "dependencies",
  id: "deplint.dependencies.unused",
  meta: {
    description: "Dependencies declared but not used at runtime",
    fixable: ["manifest"],
    severity: "error"
  },
  evaluate(context) {
    const findings = findUnusedDependencies(
      context.workspace.location,
      context.packageParams.dependencies,
      context.packageParams.devDependencies,
      context.sourceParams.externalDistImports,
      context.sourceParams.externalDistTypeImports,
      context.sourceParams.externalAllImports,
      context.unusedDependencyExclude
    );
    for (const finding of findings) {
      context.report({
        data: finding,
        dependency: finding.dep,
        message: finding.kind === "move-to-dev" ? `dependency should be devDependency in package.json: ${finding.dep}${finding.reason != null && finding.reason.length > 0 ? ` (${finding.reason})` : ""}` : `Unused dependency in package.json: ${finding.dep}`
      });
    }
  },
  resolveFixes(diagnostic) {
    const data = diagnostic.data;
    if (!data) return [];
    return [data.kind === "move-to-dev" ? {
      action: "move",
      dependency: data.dep,
      detail: "moved to devDependencies",
      fromSection: "dependencies",
      toSection: "devDependencies"
    } : {
      action: "remove",
      dependency: data.dep,
      detail: "removed from dependencies",
      section: "dependencies"
    }];
  }
};
var unlistedDevDependenciesRule = {
  category: "devDependencies",
  id: "deplint.devDependencies.unlisted",
  meta: {
    description: "Dev-only imports missing from package.json",
    fixable: ["manifest"],
    severity: "error"
  },
  evaluate(context) {
    const findings = findUnlistedDevDeps(
      context.workspace.name,
      context.packageParams.dependencies,
      context.packageParams.devDependencies,
      context.packageParams.peerDependencies,
      context.sourceParams.externalAllImports,
      context.sourceParams.distImports,
      context.sourceParams.externalDistTypeImports
    );
    for (const imp of findings) {
      context.report({
        data: { imp },
        dependency: imp,
        evidence: context.sourceParams.allImportPaths[imp],
        message: `Missing devDependency in package.json: ${imp}`
      });
    }
  },
  resolveFixes(diagnostic, context) {
    const data = diagnostic.data;
    return data ? [resolvedAddFix(context, data.imp, "devDependencies", "added to devDependencies")] : [];
  }
};
var unusedDevDependenciesRule = {
  category: "devDependencies",
  id: "deplint.devDependencies.unused",
  meta: {
    description: "Dev dependencies declared but never referenced",
    fixable: ["manifest"],
    severity: "error"
  },
  evaluate(context) {
    const findings = findUnusedDevDeps(
      context.workspace.location,
      context.packageParams.dependencies,
      context.packageParams.devDependencies,
      context.packageParams.peerDependencies,
      context.sourceParams,
      context.fileContext,
      context.unusedDependencyExclude
    );
    for (const dep of findings) {
      context.report({
        data: { dep },
        dependency: dep,
        message: `Unused devDependency in package.json: ${dep}`
      });
    }
  },
  resolveFixes(diagnostic) {
    const data = diagnostic.data;
    return data ? [{
      action: "remove",
      dependency: data.dep,
      detail: "removed from devDependencies",
      section: "devDependencies"
    }] : [];
  }
};
var redundantDevDependenciesRule = {
  category: "devDependencies",
  id: "deplint.devDependencies.redundant",
  meta: {
    description: "Dependencies duplicated in devDependencies",
    fixable: ["manifest"],
    severity: "error"
  },
  evaluate(context) {
    for (const dep of context.packageParams.devDependencies) {
      if (!context.packageParams.dependencies.includes(dep)) continue;
      if (!context.isTerminalPackage && !context.forceDeps.has(dep) && shouldBePeerDependency(dep, context.workspace.location, context.packageParams.peerDependencies, context.sourceParams.externalDistImports, context.workspaceNames)) {
        continue;
      }
      context.report({
        data: { dep },
        dependency: dep,
        message: `Redundant devDependency ${dep} \u2014 already listed in dependencies`
      });
    }
  },
  resolveFixes(diagnostic) {
    const data = diagnostic.data;
    return data ? [{
      action: "remove",
      dependency: data.dep,
      detail: "removed redundant devDependency (kept in dependencies)",
      section: "devDependencies"
    }] : [];
  }
};
var unsatisfiedPeersRule = {
  category: "peerDependencies",
  id: "deplint.peerDependencies.unsatisfied",
  meta: {
    description: "Missing, under-exposed, or incompatible peer dependencies",
    fixable: ["manifest"],
    severity: "error"
  },
  evaluate(context) {
    const findings = findUnsatisfiedPeers(
      context.workspace,
      context.packageParams,
      context.exclude,
      context.isTerminalPackage,
      context.forcePeerOptional,
      context.forceDevs
    );
    for (const finding of findings) {
      const requiredBy = finding.sources.map((source) => source.requiredBy).join(", ");
      const chain = finding.sources.find((source) => (source.chain && source.chain.length > 0) ?? false)?.chain?.join(" -> ");
      const evidence = chain != null && chain.length > 0 ? [`via ${chain}`] : void 0;
      const message = finding.reason === "version-mismatch" ? `Peer dependency version mismatch ${finding.peer} \u2014 installed ${finding.installedVersion ?? "unknown"} does not satisfy ${finding.versionRange} (required by ${requiredBy})` : finding.reason === "under-exposed" ? `Under-exposed peer dependency ${finding.peer} (required by ${requiredBy}) \u2014 in devDependencies only; must also be in dependencies or peerDependencies` : finding.hasRuntimeSource ? `Unsatisfied peer dependency ${finding.peer} (required by ${requiredBy}) \u2014 must be in dependencies or peerDependencies` : `Unsatisfied peer dependency ${finding.peer} (required by devDependency ${requiredBy}) \u2014 must be in dependencies, devDependencies, or peerDependencies`;
      context.report({
        data: { finding },
        dependency: finding.peer,
        evidence,
        message
      });
    }
  },
  resolveFixes(diagnostic, context) {
    const data = diagnostic.data;
    const finding = data?.finding;
    if (!finding) return [];
    const peerVersion = context.workspaceNames?.has(finding.peer) ?? false ? "workspace:~" : finding.versionRange;
    if (finding.reason === "missing") {
      const optional = resolvePromotedPeerOptional(context, finding.peer, finding.sources);
      return resolvePeerTargetSections(finding.hasRuntimeSource, context.isTerminalPackage).map((section) => ({
        action: "add",
        dependency: finding.peer,
        detail: `added to ${section}`,
        ...section === "peerDependencies" && optional !== void 0 && { optional },
        section,
        version: peerVersion
      }));
    }
    if (finding.reason === "under-exposed") {
      const optional = resolvePromotedPeerOptional(context, finding.peer, finding.sources);
      return [{
        action: "add",
        dependency: finding.peer,
        detail: "added to peerDependencies",
        ...optional !== void 0 && { optional },
        section: "peerDependencies",
        version: peerVersion
      }];
    }
    if (finding.reason === "version-mismatch") {
      return generateVersionMismatchFixes(context, finding);
    }
    return [];
  }
};
var unusedPeerDependenciesRule = {
  category: "peerDependencies",
  id: "deplint.peerDependencies.unused",
  meta: {
    description: "Peer dependencies declared but not used in dist",
    fixable: ["manifest"],
    severity: "error"
  },
  evaluate(context) {
    const findings = findUnusedPeerDeps(
      context.packageParams.peerDependencies,
      context.sourceParams.externalDistImports,
      context.sourceParams.externalDistTypeImports,
      context.unusedPeerDependencyExclude
    );
    for (const dep of findings) {
      context.report({
        data: { dep, alreadyDependency: context.packageParams.dependencies.includes(dep) },
        dependency: dep,
        message: context.packageParams.dependencies.includes(dep) ? `Unused peerDependency [already a dependency] in package.json: ${dep}` : `Unused peerDependency in package.json: ${dep}`
      });
    }
  },
  resolveFixes(diagnostic) {
    const data = diagnostic.data;
    return data ? [{
      action: "remove",
      dependency: data.dep,
      detail: "removed from peerDependencies",
      section: "peerDependencies"
    }] : [];
  }
};
var unrequestedPeerDependenciesRule = {
  category: "peerDependencies",
  id: "deplint.peerDependencies.unrequested",
  meta: {
    description: "Terminal-package peers that should be regular dependencies",
    fixable: ["manifest"],
    severity: "error"
  },
  evaluate(context) {
    if (!context.isTerminalPackage) return;
    const findings = findUnrequestedPeerDeps(
      context.workspace.location,
      context.packageParams,
      context.sourceParams,
      true,
      // rule already early-returned for non-terminal packages
      context.exclude
    );
    for (const dep of findings) {
      context.report({
        data: { dep, version: context.packageParams.peerDependencyVersions[dep] ?? "*" },
        dependency: dep,
        message: `Unnecessary peerDependency ${dep} \u2014 imported in dist but no dependency requires it as a peer; should be a dependency`
      });
    }
  },
  resolveFixes(diagnostic) {
    const data = diagnostic.data;
    return data ? [{
      action: "move",
      dependency: data.dep,
      detail: "moved from peerDependencies to dependencies",
      fromSection: "peerDependencies",
      toSection: "dependencies",
      version: data.version
    }] : [];
  }
};
var redundantPeerDependenciesRule = {
  category: "peerDependencies",
  id: "deplint.peerDependencies.redundant",
  meta: {
    description: "Dependencies duplicated in peerDependencies",
    fixable: ["manifest"],
    severity: "error"
  },
  evaluate(context) {
    const findings = findRedundantPeerDeps(context.packageParams, context.exclude);
    for (const dep of findings) {
      context.report({
        data: { dep },
        dependency: dep,
        message: `Redundant peerDependency ${dep} \u2014 already listed in dependencies`
      });
    }
  },
  resolveFixes(diagnostic) {
    const data = diagnostic.data;
    return data ? [{
      action: "remove",
      dependency: data.dep,
      detail: "removed redundant peerDependency (kept in dependencies)",
      section: "peerDependencies"
    }] : [];
  }
};
var mismatchedPeerDevVersionsRule = {
  category: "peerDependencies",
  id: "deplint.peerDependencies.version-mismatch",
  meta: {
    description: "Peer and dev ranges for the same package are out of sync",
    fixable: ["manifest"],
    severity: "error"
  },
  evaluate(context) {
    const findings = findMismatchedPeerDevVersions(context.packageParams, context.exclude);
    for (const finding of findings) {
      context.report({
        data: finding,
        dependency: finding.dep,
        message: `Peer/dev version mismatch ${finding.dep} \u2014 peer: ${finding.peerVersion}, dev: ${finding.devVersion}`
      });
    }
  },
  resolveFixes(diagnostic, context) {
    const data = diagnostic.data;
    if (!data) return [];
    const expected = resolvePeerVersionForFix(
      context.workspace.location,
      data.dep,
      data.devVersion,
      context.peerRangeForm,
      context.peerRangeBound
    );
    const version = expected === "*" ? data.devVersion : expected;
    return [{
      action: "set-version",
      dependency: data.dep,
      detail: `synced peerDependency to ${context.peerRangeForm} form derived from devDependency`,
      section: "peerDependencies",
      version
    }];
  }
};
var peerDependencyRangeStyleRule = {
  category: "peerDependencies",
  id: "deplint.peerDependencies.range-style",
  meta: {
    description: "Peer dependency ranges should not use broad comparator form by default",
    fixable: ["manifest"],
    severity: "error"
  },
  evaluate(context) {
    const form = resolvePeerRangeFormOption(context.options);
    const boundType = resolvePeerRangeBoundOption(context.options);
    for (const dep of context.packageParams.peerDependencies) {
      const current = context.packageParams.peerDependencyVersions[dep];
      if (shouldSkipPeerRangeStyle(context, dep, current)) continue;
      const devRange = context.packageParams.devDependencyVersions[dep];
      const expected = expectedPeerRangeStyle(context, dep, devRange, form, boundType);
      if (expected === "*" || current === expected) continue;
      if (form === "shorthand" && !isBroadPeerRange(current)) continue;
      context.report({
        data: { dep, expected },
        dependency: dep,
        message: form === "broad" ? `peerDependency ${dep} range ${current} should use broad form ${expected}` : `peerDependency ${dep} range ${current} must not use broad form; use ${expected}`
      });
    }
  },
  resolveFixes(diagnostic) {
    const data = diagnostic.data;
    return data ? [{
      action: "set-version",
      dependency: data.dep,
      detail: `updated peerDependency range to ${data.expected}`,
      section: "peerDependencies",
      version: data.expected
    }] : [];
  }
};
var workspaceVersionProblemsRule = {
  category: "workspace",
  id: "deplint.workspace.protocol",
  meta: {
    description: "Workspace dependencies should use the workspace: protocol",
    fixable: ["manifest"],
    severity: "error"
  },
  evaluate(context) {
    if (!context.workspaceNames) return;
    const configuredProtocol = resolveWorkspaceProtocolOption(context.options);
    const findings = findWorkspaceVersionProblems(context.packageParams, context.workspaceNames, configuredProtocol);
    for (const finding of findings) {
      const expectedVersion = finding.expectedVersion ?? "workspace:~";
      context.report({
        data: { ...finding, expectedVersion },
        dependency: finding.dep,
        message: `Workspace dependency ${finding.dep} in ${finding.section} should use ${configuredProtocol ?? "workspace: protocol"} \u2014 found ${finding.version}`
      });
    }
  },
  resolveFixes(diagnostic) {
    const data = diagnostic.data;
    return data ? [{
      action: "set-version",
      dependency: data.dep,
      detail: `set ${data.expectedVersion ?? "workspace:~"} for ${data.section}`,
      section: data.section,
      version: data.expectedVersion ?? "workspace:~"
    }] : [];
  }
};
function shouldSkipPeerRangeStyle(context, dep, current) {
  return (context.exclude?.has(dep) ?? false) || current === void 0 || current === "*" || current.startsWith("workspace:") || current.startsWith("catalog:") || current.startsWith("npm:") || (context.workspaceNames?.has(dep) ?? false);
}
function expectedPeerRangeStyle(context, dep, devRange, form, boundType) {
  return form === "broad" ? resolveExpectedPeerVersion(context.workspace.location, dep, devRange, boundType) : resolveExpectedPeerShorthandVersion(context.workspace.location, dep, devRange);
}
var deplintRules = [
  unlistedDependenciesRule,
  unusedDependenciesRule,
  misplacedDependenciesRule,
  unlistedDevDependenciesRule,
  unusedDevDependenciesRule,
  redundantDevDependenciesRule,
  unsatisfiedPeersRule,
  unusedPeerDependenciesRule,
  unrequestedPeerDependenciesRule,
  misplacedPeerDependenciesRule,
  redundantPeerDependenciesRule,
  mismatchedPeerDevVersionsRule,
  peerDependencyRangeStyleRule,
  workspaceVersionProblemsRule
];
var builtInDeplintPlugin = { name: "builtin", rules: deplintRules };

// src/actions/deplint/loader.ts
function resolvePluginSpecifier(specifier) {
  if (specifier.startsWith(".") || PATH.isAbsolute(specifier)) {
    return pathToFileURL(PATH.resolve(specifier)).href;
  }
  return specifier;
}
function isPlugin(value) {
  return typeof value === "object" && value !== null && "name" in value && "rules" in value && Array.isArray(value.rules);
}
async function loadDeplintRules(config) {
  const plugins = [builtInDeplintPlugin];
  const pluginSpecifiers = config?.plugins ?? [];
  for (const specifier of pluginSpecifiers) {
    const pluginModule = await import(resolvePluginSpecifier(specifier));
    const plugin = pluginModule.default ?? pluginModule.plugin;
    if (!isPlugin(plugin)) {
      throw new TypeError(`Invalid deplint plugin "${specifier}" - expected a plugin with a name and rules array`);
    }
    plugins.push(plugin);
  }
  return normalizeDeplintRules(
    plugins.flatMap((plugin) => plugin.rules),
    config,
    new Set(builtInDeplintPlugin.rules.map((rule) => rule.id))
  );
}
export {
  loadDeplintRules
};
//# sourceMappingURL=loader.mjs.map
