// src/actions/deplint/checkPackage/getUnnecessaryPeerDependencies.ts
import fs4 from "fs";
import chalk3 from "chalk";

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

// src/actions/deplint/getRequiredPeerDependencies.ts
import fs from "fs";
import path from "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;
  }
}

// src/actions/deplint/packageJsonEditor.ts
function readPackageJson(location) {
  return JSON.parse(fs2.readFileSync(`${location}/package.json`, "utf8"));
}
function writePackageJson(location, pkg) {
  const sorted = sortPackageJson(JSON.stringify(pkg, null, 2));
  fs2.writeFileSync(`${location}/package.json`, `${sorted}
`);
}
function removeDep(pkg, dep, section) {
  const sectionObj = pkg[section];
  if (!sectionObj?.[dep]) return;
  delete sectionObj[dep];
  if (Object.keys(sectionObj).length === 0) {
    delete pkg[section];
  }
}
function logFix(workspace, action, dep, detail) {
  const detailStr = detail ? ` (${detail})` : "";
  console.log(`[${chalk.blue(workspace.name)}] Fixed: ${action} ${chalk.green(dep)}${detailStr}`);
}

// src/actions/deplint/checkPackage/getUnsatisfiedPeerDependencies.ts
import fs3 from "fs";
import chalk2 from "chalk";
import semver from "semver";
import sortPackageJson2 from "sort-package-json";
function readDepPackageJson(location, dep) {
  const depPkgPath = findDepPackageJson(location, dep);
  if (!depPkgPath) return void 0;
  try {
    return JSON.parse(fs3.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 ?? {});
}
var MAX_TRANSITIVE_DEPTH = 2;
function collectPeerSources(location, dependencies, devDependencies) {
  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]);
        }
      }
    }
  }
  collectFromDeps(dependencies, true, []);
  const devOnly = devDependencies.filter((d) => !dependencies.includes(d));
  collectFromDeps(devOnly, false, []);
  return peerSources;
}
function getRequiredTransitivePeers(location, { dependencies, devDependencies }) {
  const peerSources = collectPeerSources(location, dependencies, devDependencies);
  return new Set(peerSources.keys());
}

// 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 }, exclude) {
  const requiredPeers = getRequiredTransitivePeers(location, packageParams);
  const unrequested = [];
  for (const dep of packageParams.peerDependencies) {
    if (exclude?.has(dep)) continue;
    if (packageParams.dependencies.includes(dep)) continue;
    if (!isPeerImportedInDist(dep, externalDistImports, externalDistTypeImports)) continue;
    if (!requiredPeers.has(dep)) {
      unrequested.push(dep);
    }
  }
  return unrequested;
}
function getUnrequestedPeerDependencies({ name, location }, packageParams, sourceParams, exclude) {
  if (!isTerminalPackage(location)) return 0;
  const unrequested = findUnrequestedPeerDeps(location, packageParams, sourceParams, exclude);
  for (const dep of unrequested) {
    console.log(
      `[${chalk3.blue(name)}] Unnecessary peerDependency ${chalk3.red(dep)} \u2014 imported in dist but no dependency requires it as a peer; should be a dependency`
    );
  }
  if (unrequested.length > 0) {
    console.log(`  ${chalk3.yellow(`${location}/package.json`)}
`);
  }
  return unrequested.length;
}
function isTerminalPackage(location) {
  try {
    const pkg = JSON.parse(fs4.readFileSync(`${location}/package.json`, "utf8"));
    return pkg.private === true;
  } catch {
    return false;
  }
}
function fixUnrequestedPeerDependencies(workspace, packageParams, sourceParams, exclude) {
  const unrequested = findUnrequestedPeerDeps(workspace.location, packageParams, sourceParams, exclude);
  if (unrequested.length === 0) return 0;
  const isTerminal = isTerminalPackage(workspace.location);
  const tsconfigExtendsSet = new Set(sourceParams.tsconfigExtends);
  const fixable = isTerminal ? unrequested : unrequested.filter((dep) => tsconfigExtendsSet.has(dep));
  if (fixable.length === 0) return 0;
  const pkg = readPackageJson(workspace.location);
  for (const dep of fixable) {
    const version = packageParams.peerDependencyVersions[dep] ?? "*";
    removeDep(pkg, dep, "peerDependencies");
    pkg.dependencies = pkg.dependencies ?? {};
    pkg.dependencies[dep] = version;
    logFix(workspace, "moved from peerDependencies to dependencies", dep);
  }
  writePackageJson(workspace.location, pkg);
  return fixable.length;
}
function findRedundantPeerDeps({ peerDependencies, dependencies }, exclude) {
  const depsSet = new Set(dependencies);
  const redundant = [];
  for (const dep of peerDependencies) {
    if (exclude?.has(dep)) continue;
    if (depsSet.has(dep)) {
      redundant.push(dep);
    }
  }
  return redundant;
}
function getRedundantPeerDependencies({ name, location }, packageParams, exclude) {
  const redundant = findRedundantPeerDeps(packageParams, exclude);
  for (const dep of redundant) {
    console.log(
      `[${chalk3.blue(name)}] Redundant peerDependency ${chalk3.red(dep)} \u2014 already listed in dependencies`
    );
  }
  if (redundant.length > 0) {
    console.log(`  ${chalk3.yellow(`${location}/package.json`)}
`);
  }
  return redundant.length;
}
function fixRedundantPeerDependencies(workspace, packageParams, exclude) {
  const redundant = findRedundantPeerDeps(packageParams, exclude);
  if (redundant.length === 0) return 0;
  const pkg = readPackageJson(workspace.location);
  for (const dep of redundant) {
    removeDep(pkg, dep, "peerDependencies");
    logFix(workspace, "removed redundant peerDependency (kept in dependencies)", dep);
  }
  writePackageJson(workspace.location, pkg);
  return redundant.length;
}
export {
  findRedundantPeerDeps,
  findUnrequestedPeerDeps,
  fixRedundantPeerDependencies,
  fixUnrequestedPeerDependencies,
  getRedundantPeerDependencies,
  getUnrequestedPeerDependencies
};
//# sourceMappingURL=getUnnecessaryPeerDependencies.mjs.map