// src/actions/lintNext.ts
import { createRequire } from "node:module";
import path from "node:path";
import { pathToFileURL } from "node:url";
import chalk2 from "chalk";

// src/lib/concurrency.ts
import { AsyncLocalStorage } from "node:async_hooks";
var outputStorage = new AsyncLocalStorage();
async function runWithConcurrency(items, concurrency, fn) {
  let next = 0;
  async function worker() {
    while (next < items.length) {
      const i = next++;
      await fn(items[i]);
    }
  }
  await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, () => worker()));
}

// src/lib/crossSpawn.ts
import crossSpawn from "cross-spawn";
function spawn(command, args, options) {
  return crossSpawn(command, args, options);
}

// src/pm/resolveWorkspace.ts
import chalk from "chalk";
function shortName(name) {
  const slash = name.lastIndexOf("/");
  return slash === -1 ? name : name.slice(slash + 1);
}
function resolveWorkspace(workspaces, query) {
  const exact = workspaces.find((ws) => ws.name === query);
  if (exact) return exact;
  const byLocation = workspaces.find((ws) => ws.location === query);
  if (byLocation) return byLocation;
  const byShort = workspaces.filter((ws) => shortName(ws.name) === query);
  if (byShort.length === 1) return byShort[0];
  if (byShort.length > 1) {
    console.error(chalk.red(`Ambiguous workspace "${query}"; matches: ${byShort.map((ws) => ws.name).join(", ")}`));
    return void 0;
  }
  return void 0;
}

// src/pm/workspaces.ts
import { existsSync, readFileSync } from "node:fs";
import PATH from "node:path";
import { globSync } from "glob";
function readJsonFile(path2) {
  if (!existsSync(path2)) return void 0;
  try {
    return JSON.parse(readFileSync(path2, "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/lib/reporting/xyReporter.ts
var strictMode = false;
function isStrictMode() {
  return strictMode || process.env.XY_STRICT === "1";
}

// src/actions/result.ts
function actionResult({
  errorCount,
  exitCode = errorCount,
  warningCount
}) {
  if (errorCount === 0 && warningCount === 0 && exitCode === 0) return 0;
  return {
    envelope: {
      errorCount,
      warningCount
    },
    exitCode
  };
}
function resultFromExitCode(exitCode) {
  return actionResult({
    errorCount: exitCode === 0 ? 0 : Math.max(1, exitCode),
    exitCode,
    warningCount: 0
  });
}

// src/actions/lintNext.ts
var lintNextIgnorePatterns = ["packages/**"];
var lintNextResultMarker = "__XY_LINT_NEXT_RESULT__";
var require2 = createRequire(import.meta.url);
var chalkImportUrl = pathToFileURL(require2.resolve("chalk")).href;
var cycleRuleFilePatterns = [
  "**/*.ts",
  "**/*.tsx",
  "**/*.mts",
  "**/*.cts",
  "**/*.js",
  "**/*.jsx",
  "**/*.cjs",
  "**/*.mjs",
  "**/*.d.ts",
  "**/*.d.tsx",
  "**/*.d.jsx",
  "**/*.d.mts",
  "**/*.d.cts"
];
var lintNextWorkerSource = String.raw`
import path from 'node:path'
import { ESLint } from 'eslint'

const marker = ${JSON.stringify(lintNextResultMarker)}
const options = JSON.parse(process.env.XY_LINT_NEXT_OPTIONS ?? '{}')
const cycleRuleFilePatterns = ${JSON.stringify(cycleRuleFilePatterns)}
const { default: chalk } = await import(process.env.XY_LINT_NEXT_CHALK_URL)
const colors = ['white', 'yellow', 'red']
const severity = ['none', 'warning', 'error']

function dumpMessages(lintResults) {
  for (const lintResult of lintResults) {
    if (lintResult.messages.length === 0) continue
    console.log(chalk.gray('\n' + lintResult.filePath))
    for (const message of lintResult.messages) {
      console.log(
        chalk.gray('\t' + message.line + ':' + message.column),
        chalk[colors[message.severity]]('\t' + severity[message.severity]),
        chalk.white('\t' + message.message),
        chalk.gray('\t' + message.ruleId),
      )
    }
  }
}

try {
  const cwd = process.cwd()
  const cycleOverrideConfig = options.cycleDepth === undefined
    ? undefined
    : {
        files: cycleRuleFilePatterns,
        rules: { 'import-x/no-cycle': ['warn', { maxDepth: options.cycleDepth }] },
      }
  const engine = new ESLint({
    cache: options.cache,
    cacheLocation: path.join(cwd, '.eslintcache'),
    cacheStrategy: 'content',
    cwd,
    fix: options.fix,
    ignorePatterns: options.ignorePatterns,
    overrideConfig: cycleOverrideConfig,
    warnIgnored: false,
  })

  const lintResults = await engine.lintFiles('.')
  dumpMessages(lintResults)

  if (options.fix) {
    await ESLint.outputFixes(lintResults)
  }

  const errors = lintResults.reduce((sum, r) => sum + r.errorCount, 0)
  const warnings = lintResults.reduce((sum, r) => sum + r.warningCount, 0)
  const files = lintResults.length

  if (options.verbose) {
    const filesColor = files < 100 ? 'green' : files < 1000 ? 'yellow' : 'red'
    console.log(chalk.white('  ' + chalk[filesColor](files) + ' files linted'))
  }

  console.log(marker + JSON.stringify({ errors, files, warnings }))
} catch (ex) {
  console.error(ex instanceof Error ? (ex.stack ?? ex.message) : String(ex))
  console.log(marker + JSON.stringify({ errors: 1, files: 0, warnings: 0 }))
  process.exitCode = 1
}
`;
function formatDuration(ms) {
  if (ms < 1e3) return `${ms}ms`;
  return `${(ms / 1e3).toFixed(2)}s`;
}
function resultColor(result) {
  if (result.errors > 0) return "red";
  if (result.warnings > 0) return "yellow";
  return "green";
}
function parseLintNextOutput(output, status) {
  const markerIndex = output.lastIndexOf(lintNextResultMarker);
  if (markerIndex === -1) {
    return {
      errors: status === 0 ? 0 : 1,
      files: 0,
      output,
      warnings: 0
    };
  }
  const beforeMarker = output.slice(0, markerIndex);
  const afterMarker = output.slice(markerIndex + lintNextResultMarker.length);
  const [jsonLine = "", ...remainingLines] = afterMarker.split(/\r?\n/);
  try {
    const parsed = JSON.parse(jsonLine);
    return {
      errors: parsed.errors,
      files: parsed.files,
      output: beforeMarker + remainingLines.join("\n"),
      warnings: parsed.warnings
    };
  } catch {
    return {
      errors: status === 0 ? 0 : 1,
      files: 0,
      output,
      warnings: 0
    };
  }
}
async function lintOnePackageProcess({
  cache,
  cwd,
  cycleDepth,
  fix,
  verbose
}) {
  return await new Promise((resolve) => {
    const output = [];
    const env = {
      ...process.env,
      FORCE_COLOR: "3",
      XY_LINT_NEXT_OPTIONS: JSON.stringify({
        cache,
        cycleDepth,
        fix,
        ignorePatterns: lintNextIgnorePatterns,
        verbose
      }),
      XY_LINT_NEXT_CHALK_URL: chalkImportUrl
    };
    delete env.NO_COLOR;
    delete env.NODE_DISABLE_COLORS;
    const child = spawn(process.execPath, ["--input-type=module", "--eval", lintNextWorkerSource], {
      cwd,
      env,
      stdio: ["ignore", "pipe", "pipe"]
    });
    child.stdout?.on("data", (chunk) => {
      output.push(String(chunk));
    });
    child.stderr?.on("data", (chunk) => {
      output.push(String(chunk));
    });
    child.on("error", (ex) => {
      resolve({
        errors: 1,
        files: 0,
        output: `${ex.message}
`,
        warnings: 0
      });
    });
    child.on("close", (status) => {
      resolve(parseLintNextOutput(output.join(""), status));
    });
  });
}
function printPackageResult(label, result) {
  const color = resultColor(result);
  console.log(
    chalk2[color](`${label} [${result.pkg}]`) + chalk2.gray(` (${result.files} files, ${formatDuration(result.timeMs)})`)
  );
  if (result.output.length > 0) {
    process.stdout.write(result.output.endsWith("\n") ? result.output : `${result.output}
`);
  }
}
function selectLintWorkspaces(allWorkspaces, pkg, targetWorkspaces) {
  if (pkg === void 0) return targetWorkspaces ?? allWorkspaces;
  const targetWorkspace = resolveWorkspace(allWorkspaces, pkg);
  return targetWorkspace === void 0 ? [] : [targetWorkspace];
}
function totalLintResults(results) {
  const total = {
    errors: 0,
    files: 0,
    warnings: 0
  };
  for (const result of results) {
    total.errors += result.errors;
    total.files += result.files;
    total.warnings += result.warnings;
  }
  return total;
}
async function lintNext({
  cache = false,
  cycleDepth,
  fix = false,
  jobs,
  pkg,
  verbose = false,
  workspaces: targetWorkspaces
}) {
  const rootDir = INIT_CWD();
  const pm = getPackageManager();
  const allWorkspaces = pm.listWorkspaces();
  const workspaces = selectLintWorkspaces(allWorkspaces, pkg, targetWorkspaces);
  if (pkg === void 0 && targetWorkspaces !== void 0 && workspaces.length === 0) {
    console.log(chalk2.gray("No workspaces to lint"));
    return 0;
  }
  if (workspaces.length === 0) {
    console.log(chalk2.red(pkg != null && pkg.length > 0 ? `Package "${pkg}" not found` : "No workspaces found"));
    return resultFromExitCode(1);
  }
  const concurrency = jobs;
  const label = fix ? "Fix" : cycleDepth === void 0 ? "Lint" : "Cycle";
  const results = Array.from(
    { length: workspaces.length },
    () => ({
      errors: 0,
      files: 0,
      output: "",
      pkg: "",
      timeMs: 0,
      warnings: 0
    })
  );
  await runWithConcurrency(
    workspaces.map((ws, i) => ({ i, ws })),
    concurrency,
    async ({ i, ws }) => {
      const pkgStart = Date.now();
      const absCwd = path.resolve(rootDir, ws.location);
      const {
        errors,
        files,
        output,
        warnings
      } = await lintOnePackageProcess({
        cache,
        cwd: absCwd,
        cycleDepth,
        fix,
        verbose
      });
      const result = {
        errors,
        files,
        output,
        pkg: ws.name,
        timeMs: Date.now() - pkgStart,
        warnings
      };
      results[i] = result;
      printPackageResult(label, result);
    }
  );
  const {
    errors: totalErrors,
    files: totalFiles,
    warnings: totalWarnings
  } = totalLintResults(results);
  const errColor = totalErrors > 0 ? "red" : "green";
  const warnColor = totalWarnings > 0 ? "yellow" : "green";
  console.log(
    chalk2[errColor](`${totalErrors} errors`) + chalk2.gray(", ") + chalk2[warnColor](`${totalWarnings} warnings`) + chalk2.gray(` across ${totalFiles} files in ${workspaces.length} packages`)
  );
  return actionResult({
    errorCount: totalErrors,
    exitCode: totalErrors + (isStrictMode() ? totalWarnings : 0),
    warningCount: totalWarnings
  });
}
export {
  lintNext
};
//# sourceMappingURL=lintNext.mjs.map
