// src/actions/packman/lint.ts
import {
  existsSync as existsSync3,
  readFileSync as readFileSync2,
  writeFileSync
} from "node:fs";
import PATH2 from "node:path";
import chalk2 from "chalk";

// src/lib/deepMerge.ts
var UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
function isPlainObject(value) {
  if (typeof value !== "object" || value === null) return false;
  const proto = Object.getPrototypeOf(value);
  return proto === Object.prototype || proto === null;
}
function isMergeable(value) {
  return Array.isArray(value) || isPlainObject(value);
}
function cloneValue(value) {
  if (Array.isArray(value)) {
    return value.map((item) => cloneValue(item));
  }
  if (isPlainObject(value)) {
    const result = {};
    for (const [key, item] of Object.entries(value)) {
      if (UNSAFE_KEYS.has(key)) continue;
      result[key] = cloneValue(item);
    }
    return result;
  }
  return value;
}
function mergeObject(target, source, options) {
  const destination = {};
  if (isPlainObject(target)) {
    for (const [key, item] of Object.entries(target)) {
      if (UNSAFE_KEYS.has(key)) continue;
      destination[key] = cloneValue(item);
    }
  }
  for (const [key, sourceValue] of Object.entries(source)) {
    if (UNSAFE_KEYS.has(key)) continue;
    if (Object.hasOwn(target, key) && isMergeable(sourceValue)) {
      const customMerge = options.customMerge?.(key);
      destination[key] = (customMerge ?? deepMerge)(target[key], sourceValue, options);
    } else {
      destination[key] = cloneValue(sourceValue);
    }
  }
  return destination;
}
function deepMerge(target, source, options = {}) {
  const isSourceIsArray = Array.isArray(source);
  const isTargetIsArray = Array.isArray(target);
  if (isSourceIsArray !== isTargetIsArray) {
    return cloneValue(source);
  }
  if (isSourceIsArray) {
    return [...target, ...source].map((item) => cloneValue(item));
  }
  return mergeObject(target, source, options);
}

// 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/lib/loadConfig.ts
import chalk from "chalk";
import { cosmiconfig } from "cosmiconfig";
import { TypeScriptLoader } from "cosmiconfig-typescript-loader";
var configState = {
  config: void 0,
  rootConfigPath: void 0
};
function createExplorer() {
  return cosmiconfig("xy", { cache: true, loaders: { ".ts": TypeScriptLoader() } });
}
var loadConfig = async (params) => {
  if (configState.config === void 0) {
    const cosmicConfigResult = await createExplorer().search();
    configState.config = cosmicConfigResult?.config ?? {};
    configState.rootConfigPath = cosmicConfigResult?.filepath;
    const configFilePath = cosmicConfigResult?.filepath;
    if (configFilePath !== void 0) {
      console.log(chalk.green(`Loaded config from ${configFilePath}`));
      if (Boolean(configState.config.verbose)) {
        console.log(chalk.gray(JSON.stringify(configState.config, null, 2)));
      }
    }
  }
  return deepMerge(configState.config, params ?? {});
};

// src/lib/pnpmConfig/readMinReleaseAge.ts
import * as yaml from "yaml";
var DEFAULT_MINIMUM_RELEASE_AGE_MINUTES = 1440;

// src/actions/packman/lint.ts
var DEFAULT_RELEASE_AGE_EXCLUDES = ["'@xylabs/*'", "'@xyo-network/*'"];
var DEFAULT_VERIFY_DEPS_BEFORE_RUN = "warn";
function resolvePackmanConfig(cfg) {
  return {
    minimumReleaseAge: cfg?.minimumReleaseAge ?? DEFAULT_MINIMUM_RELEASE_AGE_MINUTES,
    minimumReleaseAgeExclude: cfg?.minimumReleaseAgeExclude ?? DEFAULT_RELEASE_AGE_EXCLUDES
  };
}
function readPnpmWorkspaceYaml(cwd) {
  const wsPath = PATH2.join(cwd, "pnpm-workspace.yaml");
  if (!existsSync3(wsPath)) return void 0;
  return readFileSync2(wsPath, "utf8");
}
function writePnpmWorkspaceYaml(cwd, content) {
  writeFileSync(PATH2.join(cwd, "pnpm-workspace.yaml"), content, "utf8");
}
function parseYamlListSection(content, sectionName) {
  const items = [];
  let isInSection = false;
  for (const line of content.split("\n")) {
    const sectionPattern = new RegExp(String.raw`^${sectionName}\s*:`);
    if (sectionPattern.test(line)) {
      isInSection = true;
      continue;
    }
    if (isInSection) {
      const match = /^\s+-\s+(.+)$/.exec(line);
      if (match) {
        items.push(match[1].trim());
      } else if (line.trim() && !/^\s/.test(line)) {
        break;
      }
    }
  }
  return items;
}
function shouldCheckEnableScripts(cwd, isVerbose, isSilent) {
  const yarnrcPath = PATH2.join(cwd, ".yarnrc.yml");
  if (!existsSync3(yarnrcPath)) {
    if (isVerbose ?? false) console.log(chalk2.gray("  No .yarnrc.yml found, skipping enableScripts check"));
    return true;
  }
  const content = readFileSync2(yarnrcPath, "utf8");
  for (const line of content.split("\n")) {
    const trimmed = line.trim();
    if (/^enableScripts\s*:/.test(trimmed)) {
      const value = trimmed.replace(/^enableScripts\s*:\s*/, "").trim();
      if (value === "false") {
        if (isVerbose ?? false) console.log(chalk2.green("  enableScripts is correctly set to false"));
        return true;
      }
      if (!(isSilent ?? false)) console.log(chalk2.red("  enableScripts is set to", value, "(expected false)"));
      return false;
    }
  }
  if (!(isSilent ?? false)) console.log(chalk2.red("  enableScripts is not set in .yarnrc.yml (expected false)"));
  return false;
}
function shouldFixEnableScripts(cwd) {
  const yarnrcPath = PATH2.join(cwd, ".yarnrc.yml");
  if (!existsSync3(yarnrcPath)) return true;
  const content = readFileSync2(yarnrcPath, "utf8");
  const lines = content.split("\n");
  let isFound = false;
  const newLines = lines.map((line) => {
    if (/^\s*enableScripts\s*:/.test(line)) {
      isFound = true;
      return "enableScripts: false";
    }
    return line;
  });
  if (!isFound) {
    let isInserted = false;
    for (let i = 0; i < newLines.length; i++) {
      const trimmed = newLines[i].trim();
      if (trimmed && !trimmed.startsWith("#") && trimmed > "enableScripts:") {
        newLines.splice(i, 0, "enableScripts: false", "");
        isInserted = true;
        break;
      }
    }
    if (!isInserted) {
      const lastLine = newLines.at(-1);
      if (lastLine === "") {
        newLines.splice(-1, 0, "enableScripts: false", "");
      } else {
        newLines.push("", "enableScripts: false");
      }
    }
  }
  writeFileSync(yarnrcPath, newLines.join("\n"), "utf8");
  console.log(chalk2.green("  Fixed: enableScripts set to false"));
  return true;
}
function shouldCheckMinimumReleaseAge(cwd, config, isVerbose, isSilent) {
  const content = readPnpmWorkspaceYaml(cwd);
  if (!(content != null && content.length > 0)) {
    if (!(isSilent ?? false)) console.log(chalk2.red("  No pnpm-workspace.yaml found"));
    return false;
  }
  const { minimumReleaseAge } = config;
  for (const line of content.split("\n")) {
    const match = /^minimumReleaseAge\s*:\s*(\d+)/.exec(line.trim());
    if (match) {
      const value = Number(match[1]);
      if (value >= minimumReleaseAge) {
        if (isVerbose ?? false) console.log(chalk2.green(`  minimumReleaseAge is ${value} (>= ${minimumReleaseAge})`));
        return true;
      }
      if (!(isSilent ?? false)) console.log(chalk2.red(`  minimumReleaseAge is ${value} (expected >= ${minimumReleaseAge})`));
      return false;
    }
  }
  if (!(isSilent ?? false)) console.log(chalk2.red(`  minimumReleaseAge is not set in pnpm-workspace.yaml (expected >= ${minimumReleaseAge})`));
  return false;
}
function shouldFixMinimumReleaseAge(cwd, config) {
  const content = readPnpmWorkspaceYaml(cwd);
  if (!(content != null && content.length > 0)) return false;
  const { minimumReleaseAge } = config;
  const lines = content.split("\n");
  let isFound = false;
  const newLines = lines.map((line) => {
    if (/^minimumReleaseAge\s*:/.test(line)) {
      isFound = true;
      return `minimumReleaseAge: ${minimumReleaseAge}`;
    }
    return line;
  });
  if (!isFound) {
    const lastLine = newLines.at(-1);
    if (lastLine === "") {
      newLines.pop();
      newLines.push(`minimumReleaseAge: ${minimumReleaseAge}`, "");
    } else {
      newLines.push(`minimumReleaseAge: ${minimumReleaseAge}`);
    }
  }
  writePnpmWorkspaceYaml(cwd, newLines.join("\n"));
  console.log(chalk2.green(`  Fixed: minimumReleaseAge set to ${minimumReleaseAge}`));
  return true;
}
function shouldCheckMinimumReleaseAgeExclude(cwd, config, isVerbose, isSilent) {
  const content = readPnpmWorkspaceYaml(cwd);
  if (!(content != null && content.length > 0)) {
    if (!(isSilent ?? false)) console.log(chalk2.red("  No pnpm-workspace.yaml found"));
    return false;
  }
  const excludes = parseYamlListSection(content, "minimumReleaseAgeExclude");
  const missing = config.minimumReleaseAgeExclude.filter((scope) => !excludes.includes(scope));
  if (missing.length === 0) {
    if (isVerbose ?? false) console.log(chalk2.green("  minimumReleaseAgeExclude includes all required scopes"));
    return true;
  }
  if (!(isSilent ?? false)) console.log(chalk2.red(`  minimumReleaseAgeExclude is missing: ${missing.join(", ")}`));
  return false;
}
function shouldFixMinimumReleaseAgeExclude(cwd, config) {
  const content = readPnpmWorkspaceYaml(cwd);
  if (!(content != null && content.length > 0)) return false;
  const existingExcludes = parseYamlListSection(content, "minimumReleaseAgeExclude");
  const toAdd = config.minimumReleaseAgeExclude.filter((scope) => !existingExcludes.includes(scope));
  if (toAdd.length === 0) return true;
  const lines = content.split("\n");
  const sectionIndex = lines.findIndex((line) => /^minimumReleaseAgeExclude\s*:/.test(line));
  if (sectionIndex === -1) {
    const newSection = ["minimumReleaseAgeExclude:", ...config.minimumReleaseAgeExclude.map((s) => `  - ${s}`)];
    const lastLine = lines.at(-1);
    if (lastLine === "") {
      lines.splice(-1, 0, ...newSection);
    } else {
      lines.push(...newSection);
    }
  } else {
    let insertAt = sectionIndex + 1;
    while (insertAt < lines.length && /^\s+-/.test(lines[insertAt])) {
      insertAt++;
    }
    for (const scope of toAdd) {
      lines.splice(insertAt, 0, `  - ${scope}`);
      insertAt++;
    }
  }
  writePnpmWorkspaceYaml(cwd, lines.join("\n"));
  console.log(chalk2.green(`  Fixed: added ${toAdd.join(", ")} to minimumReleaseAgeExclude`));
  return true;
}
function hasPnpmWorkspaceSetting(content, key) {
  if (!(content != null && content.length > 0)) return false;
  const keyPattern = new RegExp(String.raw`^${key}\s*:`, "m");
  return keyPattern.test(content);
}
function shouldCheckVerifyDepsBeforeRun(cwd, isVerbose, isSilent) {
  const content = readPnpmWorkspaceYaml(cwd);
  if (!(content != null && content.length > 0)) {
    if (!(isSilent ?? false)) console.log(chalk2.red("  No pnpm-workspace.yaml found"));
    return false;
  }
  if (hasPnpmWorkspaceSetting(content, "verifyDepsBeforeRun")) {
    if (isVerbose ?? false) console.log(chalk2.green("  verifyDepsBeforeRun is set"));
    return true;
  }
  if (!(isSilent ?? false)) {
    console.log(chalk2.red(`  verifyDepsBeforeRun is not set in pnpm-workspace.yaml (expected ${DEFAULT_VERIFY_DEPS_BEFORE_RUN})`));
  }
  return false;
}
function shouldFixVerifyDepsBeforeRun(cwd) {
  const content = readPnpmWorkspaceYaml(cwd);
  if (!(content != null && content.length > 0)) return false;
  const lines = content.split("\n");
  const newLines = [...lines];
  const lastLine = newLines.at(-1);
  const setting = `verifyDepsBeforeRun: ${DEFAULT_VERIFY_DEPS_BEFORE_RUN}`;
  if (lastLine === "") {
    newLines.splice(-1, 0, setting, "");
  } else {
    newLines.push(setting);
  }
  writePnpmWorkspaceYaml(cwd, newLines.join("\n"));
  console.log(chalk2.green(`  Fixed: verifyDepsBeforeRun set to ${DEFAULT_VERIFY_DEPS_BEFORE_RUN}`));
  return true;
}
function recordCheckFailure(hasPassed, fix, shouldApplyFix) {
  if (hasPassed) return 0;
  if (fix ?? false) return shouldApplyFix() ? 0 : 1;
  return 1;
}
function runYarnLintChecks(cwd, fix, isVerbose) {
  return recordCheckFailure(
    shouldCheckEnableScripts(cwd, isVerbose, fix),
    fix,
    () => shouldFixEnableScripts(cwd)
  );
}
function runPnpmLintChecks(cwd, config, fix, isVerbose) {
  let failures = 0;
  failures += recordCheckFailure(
    shouldCheckMinimumReleaseAge(cwd, config, isVerbose, fix),
    fix,
    () => shouldFixMinimumReleaseAge(cwd, config)
  );
  failures += recordCheckFailure(
    shouldCheckMinimumReleaseAgeExclude(cwd, config, isVerbose, fix),
    fix,
    () => shouldFixMinimumReleaseAgeExclude(cwd, config)
  );
  failures += recordCheckFailure(
    shouldCheckVerifyDepsBeforeRun(cwd, isVerbose, fix),
    fix,
    () => shouldFixVerifyDepsBeforeRun(cwd)
  );
  return failures;
}
function resolvePackmanConfigFromRoot(rootConfig) {
  const commands = rootConfig.commands;
  return resolvePackmanConfig(commands?.packman);
}
async function packmanLint({ fix, isVerbose } = {}) {
  const cwd = process.cwd();
  const pm = detectPackageManager();
  if (pm === "npm" || pm === "bun") {
    console.log(chalk2.green(`packman lint: no manager-specific checks are currently required for ${pm}`));
    return 0;
  }
  let failures = 0;
  if (pm === "yarn") {
    failures += runYarnLintChecks(cwd, fix, isVerbose);
  } else if (pm === "pnpm") {
    const rootConfig = await loadConfig();
    failures += runPnpmLintChecks(
      cwd,
      resolvePackmanConfigFromRoot(rootConfig),
      fix,
      isVerbose
    );
  }
  if (failures > 0) {
    console.log(chalk2.red(`
packman lint: ${failures} check(s) failed`));
    if (!(fix ?? false)) {
      console.log(chalk2.yellow("Run with --fix to auto-fix issues"));
    }
  } else {
    console.log(chalk2.green("\npackman lint: all checks hasPassed"));
  }
  return failures > 0 ? 1 : 0;
}
export {
  packmanLint
};
//# sourceMappingURL=lint.mjs.map
