// src/actions/package-lint-deps.ts
import { readFileSync as readFileSync2, writeFileSync } from "node:fs";
import PATH2 from "node:path";
import chalk from "chalk";
import semver from "semver";

// src/pm/workspaces.ts
import { existsSync, readFileSync } from "node:fs";
import PATH from "node:path";
import { globSync } from "glob";
function readJsonFile(path) {
  if (!existsSync(path)) return void 0;
  try {
    return JSON.parse(readFileSync(path, "utf8"));
  } catch {
    return void 0;
  }
}
function readRootPackageJson(cwd = process.cwd()) {
  return readJsonFile(PATH.resolve(cwd, "package.json"));
}
function detectPackageManagerFromPackageJson(cwd = process.cwd()) {
  const packageManager = readRootPackageJson(cwd)?.packageManager;
  if (!(packageManager != null && packageManager.length > 0)) return void 0;
  return packageManager.split("@", 1)[0];
}

// src/pm/detectPackageManager.ts
import { existsSync as existsSync2 } from "node:fs";
var knownPackageManagers = /* @__PURE__ */ new Set(["bun", "npm", "pnpm", "yarn"]);
function detectPackageManager() {
  const packageManager = detectPackageManagerFromPackageJson();
  if (packageManager != null && packageManager.length > 0 && knownPackageManagers.has(packageManager)) {
    return packageManager;
  }
  if (existsSync2("pnpm-lock.yaml") || existsSync2("pnpm-workspace.yaml")) return "pnpm";
  if (existsSync2("bun.lock") || existsSync2("bun.lockb")) return "bun";
  if (existsSync2("yarn.lock") || existsSync2(".yarnrc.yml")) return "yarn";
  if (existsSync2("package-lock.json") || existsSync2("npm-shrinkwrap.json")) return "npm";
  return "yarn";
}

// src/pm/registry.ts
var implementations = /* @__PURE__ */ new Map();
function getPackageManager(name) {
  const pmName = name ?? detectPackageManager();
  const pm = implementations.get(pmName);
  if (!pm) {
    throw new Error(
      `No package manager implementation registered for "${pmName}". Ensure registerPackageManager() has been called before getPackageManager().`
    );
  }
  return pm;
}

// src/lib/initCwd.ts
function INIT_CWD() {
  return process.env.INIT_CWD ?? process.cwd();
}

// src/actions/package-lint-deps.ts
function readWorkspacePackageJson(cwd, location) {
  const pkgPath = PATH2.resolve(cwd, location, "package.json");
  try {
    return JSON.parse(readFileSync2(pkgPath, "utf8"));
  } catch {
    return void 0;
  }
}
function writeWorkspacePackageJson(cwd, location, pkg) {
  const pkgPath = PATH2.resolve(cwd, location, "package.json");
  writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}
`, "utf8");
}
function buildWorkspaceVersionMap(cwd, workspaces) {
  const map = /* @__PURE__ */ new Map();
  for (const { location, name } of workspaces) {
    if (location === ".") continue;
    const pkg = readWorkspacePackageJson(cwd, location);
    if (!pkg) continue;
    const version = pkg.version;
    if (version != null && version.length > 0) map.set(name, version);
  }
  return map;
}
function internalWorkspaceEntries(deps, workspaceVersions) {
  return Object.entries(deps).flatMap(([dep, version]) => {
    const targetVersion = workspaceVersions.get(dep);
    return targetVersion != null && targetVersion.length > 0 ? [[dep, version, targetVersion]] : [];
  });
}
function workspaceProtocolEntries(deps, workspaceNames) {
  return Object.entries(deps).filter(([dep]) => workspaceNames.has(dep));
}
function internalPeerEntries(peerDeps, workspaceVersions, shouldRewriteWorkspaceProtocol) {
  return Object.entries(peerDeps).flatMap(([dep, version]) => {
    const targetVersion = workspaceVersions.get(dep);
    if (!(targetVersion != null && targetVersion.length > 0)) return [];
    if (shouldRewriteWorkspaceProtocol && version.startsWith("workspace:")) return [];
    return [[dep, version, targetVersion]];
  });
}
function forEachReadableWorkspace(cwd, workspaces, callback) {
  for (const { location, name } of workspaces) {
    const pkg = readWorkspacePackageJson(cwd, location);
    if (!pkg) continue;
    callback(pkg, location, name);
  }
}
function forEachDependencyField(pkg, callback) {
  for (const depField of ["dependencies", "devDependencies"]) {
    const deps = pkg[depField];
    if (!deps) continue;
    callback(depField, deps);
  }
}
function internalPeerVersionIssue(name, location, dep, version, targetVersion, devDepVersion, shouldRewriteWorkspaceProtocol) {
  if (version.startsWith("workspace:")) {
    if (shouldRewriteWorkspaceProtocol) return void 0;
    const expected2 = expectedPeerRange(devDepVersion, targetVersion);
    return `${name} (${location}) peerDependencies.${dep} uses workspace: protocol \u2014 should be "${expected2}"`;
  }
  const expected = expectedPeerRange(devDepVersion, targetVersion);
  if (version !== expected && !semver.satisfies(targetVersion, version)) {
    return `${name} (${location}) peerDependencies.${dep} is "${version}" \u2014 current version ${targetVersion} is not satisfied; expected "${expected}"`;
  }
  return void 0;
}
function expectedPeerRange(devDepVersion, targetVersion) {
  const parsed = semver.parse(targetVersion);
  if (!parsed) return `~${targetVersion}`;
  if (devDepVersion === "workspace:^") {
    return `^${parsed.major}`;
  }
  return `~${parsed.major}.${parsed.minor}`;
}
function checkVersionConsistency(cwd, rootPkg, workspaces) {
  const result = {
    errors: [],
    fixable: [],
    warnings: []
  };
  if (rootPkg.version !== void 0) {
    result.fixable.push('Root package.json should not have a "version" field in a monorepo');
  }
  const versions = /* @__PURE__ */ new Map();
  for (const { location, name } of workspaces) {
    if (location === ".") continue;
    const pkg = readWorkspacePackageJson(cwd, location);
    if (!pkg) continue;
    const version = pkg.version;
    if (version != null && version.length > 0) {
      versions.set(name, version);
    } else {
      result.errors.push(`${name} (${location}) is missing a "version" field`);
    }
  }
  const uniqueVersions = new Set(versions.values());
  if (uniqueVersions.size > 1) {
    const versionList = [...uniqueVersions].toSorted(semver.rcompare);
    for (const [name, version] of versions) {
      if (version !== versionList[0]) {
        result.fixable.push(`${name} has version ${version} (expected ${versionList[0]})`);
      }
    }
  }
  return result;
}
function fixVersionConsistency(cwd, rootPkg, writeRootPackageJson, workspaces) {
  if (rootPkg.version !== void 0) {
    delete rootPkg.version;
    writeRootPackageJson(cwd, rootPkg);
    console.log(chalk.green('  \u2714 Fixed: removed "version" from root package.json'));
  }
  const versions = [];
  for (const { location } of workspaces) {
    if (location === ".") continue;
    const pkg = readWorkspacePackageJson(cwd, location);
    if (!pkg) continue;
    const version = pkg.version;
    const validVersion = version === void 0 ? null : semver.valid(version);
    if (version !== void 0 && version.length > 0 && validVersion !== null && validVersion.length > 0) {
      versions.push(version);
    }
  }
  if (versions.length === 0) return;
  const highest = versions.toSorted(semver.rcompare)[0];
  for (const { location, name } of workspaces) {
    if (location === ".") continue;
    const pkg = readWorkspacePackageJson(cwd, location);
    if (!pkg) continue;
    if (pkg.version !== highest) {
      pkg.version = highest;
      writeWorkspacePackageJson(cwd, location, pkg);
      console.log(chalk.green(`  \u2714 Fixed: set version to ${highest} in ${name} (${location})`));
    }
  }
}
function expectedDepVersion(targetVersion) {
  const parsed = semver.parse(targetVersion);
  if (!parsed) return `~${targetVersion}`;
  return `~${targetVersion}`;
}
function checkInternalDepVersions(cwd, workspaces) {
  const result = {
    errors: [],
    fixable: [],
    warnings: []
  };
  const workspaceVersions = buildWorkspaceVersionMap(cwd, workspaces);
  forEachReadableWorkspace(cwd, workspaces, (pkg, location, name) => {
    forEachDependencyField(pkg, (depField, deps) => {
      for (const [dep, version, targetVersion] of internalWorkspaceEntries(deps, workspaceVersions)) {
        const expected = expectedDepVersion(targetVersion);
        if (version.startsWith("workspace:")) {
          result.fixable.push(
            `${name} (${location}) ${depField}.${dep} is "${version}" \u2014 should be "${expected}" (not workspace: protocol)`
          );
        } else if (version !== expected) {
          result.fixable.push(
            `${name} (${location}) ${depField}.${dep} is "${version}" \u2014 should be "${expected}"`
          );
        }
      }
    });
  });
  return result;
}
function fixInternalDepVersions(cwd, workspaces) {
  const workspaceVersions = buildWorkspaceVersionMap(cwd, workspaces);
  forEachReadableWorkspace(cwd, workspaces, (pkg, location, name) => {
    let isModified = false;
    forEachDependencyField(pkg, (depField, deps) => {
      for (const [dep, version, targetVersion] of internalWorkspaceEntries(deps, workspaceVersions)) {
        const expected = expectedDepVersion(targetVersion);
        if (version !== expected) {
          deps[dep] = expected;
          console.log(chalk.green(`  \u2714 Fixed: set ${depField}.${dep} to "${expected}" in ${name} (${location})`));
          isModified = true;
        }
      }
    });
    if (isModified) {
      writeWorkspacePackageJson(cwd, location, pkg);
    }
  });
}
function checkWorkspaceProtocol(cwd, workspaces) {
  const result = {
    errors: [],
    fixable: [],
    warnings: []
  };
  const workspaceNames = new Set(workspaces.map((w) => w.name));
  forEachReadableWorkspace(cwd, workspaces, (pkg, location, name) => {
    forEachDependencyField(pkg, (depField, deps) => {
      for (const [dep, version] of workspaceProtocolEntries(deps, workspaceNames)) {
        if (!version.startsWith("workspace:")) {
          result.fixable.push(
            `${name} (${location}) ${depField}.${dep} is "${version}" \u2014 should use workspace: protocol`
          );
        }
      }
    });
  });
  return result;
}
function fixWorkspaceProtocol(cwd, workspaces) {
  const workspaceNames = new Set(workspaces.map((w) => w.name));
  forEachReadableWorkspace(cwd, workspaces, (pkg, location, name) => {
    let isModified = false;
    forEachDependencyField(pkg, (depField, deps) => {
      for (const [dep, version] of workspaceProtocolEntries(deps, workspaceNames)) {
        if (!version.startsWith("workspace:")) {
          deps[dep] = "workspace:~";
          console.log(chalk.green(`  \u2714 Fixed: set ${depField}.${dep} to "workspace:~" in ${name} (${location})`));
          isModified = true;
        }
      }
    });
    if (isModified) {
      writeWorkspacePackageJson(cwd, location, pkg);
    }
  });
}
function checkInternalPeerVersions(cwd, workspaces) {
  const result = {
    errors: [],
    fixable: [],
    warnings: []
  };
  const workspaceVersions = buildWorkspaceVersionMap(cwd, workspaces);
  const pmName = getPackageManager().name;
  const isRewritesWorkspaceProtocol = pmName === "pnpm" || pmName === "bun";
  for (const { location, name } of workspaces) {
    const pkg = readWorkspacePackageJson(cwd, location);
    if (!pkg) continue;
    const peerDeps = pkg.peerDependencies;
    if (!peerDeps) continue;
    const devDeps = pkg.devDependencies;
    for (const [dep, version, targetVersion] of internalPeerEntries(peerDeps, workspaceVersions, isRewritesWorkspaceProtocol)) {
      const issue = internalPeerVersionIssue(name, location, dep, version, targetVersion, devDeps?.[dep], isRewritesWorkspaceProtocol);
      if (issue != null && issue.length > 0) result.fixable.push(issue);
    }
  }
  return result;
}
function fixInternalPeerVersions(cwd, workspaces) {
  const workspaceVersions = buildWorkspaceVersionMap(cwd, workspaces);
  const pmName = getPackageManager().name;
  const isRewritesWorkspaceProtocol = pmName === "pnpm" || pmName === "bun";
  for (const { location, name } of workspaces) {
    const pkg = readWorkspacePackageJson(cwd, location);
    if (!pkg) continue;
    const peerDeps = pkg.peerDependencies;
    if (!peerDeps) continue;
    const devDeps = pkg.devDependencies;
    let isModified = false;
    for (const [dep, version, targetVersion] of internalPeerEntries(peerDeps, workspaceVersions, isRewritesWorkspaceProtocol)) {
      const expected = expectedPeerRange(devDeps?.[dep], targetVersion);
      if (version !== expected) {
        peerDeps[dep] = expected;
        console.log(chalk.green(`  \u2714 Fixed: set peerDependencies.${dep} to "${expected}" in ${name} (${location})`));
        isModified = true;
      }
    }
    if (isModified) {
      writeWorkspacePackageJson(cwd, location, pkg);
    }
  }
}
function syncInternalPeerVersions({ verbose = false } = {}) {
  const cwd = INIT_CWD();
  const pm = getPackageManager();
  const workspaces = pm.listWorkspaces();
  const isRewritesWorkspaceProtocol = pm.name === "pnpm" || pm.name === "bun";
  if (verbose) {
    console.log(chalk.gray(`Internal peer sync: scanning ${workspaces.length} workspaces`));
  }
  const workspaceVersions = buildWorkspaceVersionMap(cwd, workspaces);
  let updated = 0;
  let scanned = 0;
  for (const { location, name } of workspaces) {
    const pkg = readWorkspacePackageJson(cwd, location);
    if (!pkg) continue;
    scanned++;
    const peerDeps = pkg.peerDependencies;
    if (!peerDeps) continue;
    const devDeps = pkg.devDependencies;
    let isModified = false;
    for (const [dep, version, targetVersion] of internalPeerEntries(peerDeps, workspaceVersions, isRewritesWorkspaceProtocol)) {
      const expected = expectedPeerRange(devDeps?.[dep], targetVersion);
      if (version !== expected) {
        peerDeps[dep] = expected;
        console.log(chalk.green(`Internal peer sync: updated ${name} peerDependencies.${dep} to "${expected}"`));
        isModified = true;
        updated++;
      }
    }
    if (isModified) {
      writeWorkspacePackageJson(cwd, location, pkg);
    }
  }
  if (verbose) {
    console.log(chalk.gray(`Internal peer sync: scanned ${scanned} workspaces, updated ${updated} peerDependency range${updated === 1 ? "" : "s"}.`));
  }
  return updated;
}
function logMonorepoVersion() {
  const cwd = INIT_CWD();
  const workspaces = getPackageManager().listWorkspaces();
  for (const { location } of workspaces) {
    if (location === ".") continue;
    const pkg = readWorkspacePackageJson(cwd, location);
    if (!pkg) continue;
    const version = pkg.version;
    if (version != null && version.length > 0) {
      console.log(chalk.green(`
Deployed version: ${chalk.bold(version)}`));
      return;
    }
  }
}
export {
  checkInternalDepVersions,
  checkInternalPeerVersions,
  checkVersionConsistency,
  checkWorkspaceProtocol,
  fixInternalDepVersions,
  fixInternalPeerVersions,
  fixVersionConsistency,
  fixWorkspaceProtocol,
  logMonorepoVersion,
  syncInternalPeerVersions
};
//# sourceMappingURL=package-lint-deps.mjs.map
