// src/actions/package/publint.ts
import { promises as fs } from "fs";
import path from "path";
import chalk from "chalk";
import { glob } from "glob";
import sortPackageJson from "sort-package-json";

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

// src/actions/package/compile/XyConfig.ts
var PUBLISH_ONLY_CHECKS = [
  "files",
  "importToDefault",
  "main",
  "module",
  "publint",
  "rootSource",
  "rootTypes",
  "sideEffects",
  "source",
  "types"
];

// src/actions/package/publint.ts
var removeSourceFromExports = (exports) => {
  let removed = false;
  for (const [key, value] of Object.entries(exports)) {
    if (key === "source") {
      delete exports[key];
      removed = true;
    } else if (typeof value === "object" && value !== null && removeSourceFromExports(value)) removed = true;
  }
  return removed;
};
var hasSourceInExports = (exports) => {
  for (const [key, value] of Object.entries(exports)) {
    if (key === "source") return true;
    if (typeof value === "object" && value !== null && hasSourceInExports(value)) return true;
  }
  return false;
};
var hasImportKeyInExports = (exports) => {
  for (const [key, value] of Object.entries(exports)) {
    if (key === "import" && typeof value === "string" && value.endsWith(".mjs")) return true;
    if (typeof value === "object" && value !== null && hasImportKeyInExports(value)) return true;
  }
  return false;
};
var replaceImportWithDefault = (exports) => {
  let modified = false;
  for (const [key, value] of Object.entries(exports)) {
    if (key === "import" && typeof value === "string" && value.endsWith(".mjs")) {
      if (exports.default === void 0) {
        exports.default = value;
      }
      delete exports.import;
      if (exports.types === void 0) {
        exports.types = value.replace(/\.mjs$/, ".d.ts");
      }
      modified = true;
    } else if (typeof value === "object" && value !== null && replaceImportWithDefault(value)) modified = true;
  }
  return modified;
};
var hasTypesInExports = (exports) => {
  for (const [key, value] of Object.entries(exports)) {
    if (key === "types") return true;
    if (typeof value === "object" && value !== null && hasTypesInExports(value)) return true;
  }
  return false;
};
function ensureExportsPath(value) {
  if (value.startsWith("./") || value.startsWith("../")) return value;
  return `./${value}`;
}
function emptyCustomResult() {
  return {
    errors: 0,
    modified: false,
    warnings: 0
  };
}
function mergeResults(target, source) {
  target.errors += source.errors;
  target.warnings += source.warnings;
  target.modified = target.modified || source.modified;
}
function checkFiles(pkg, fix) {
  const result = emptyCustomResult();
  const files = pkg.files;
  if (files === void 0) {
    console.warn(chalk.yellow('Publint [custom]: "files" field is missing'));
    result.warnings++;
  }
  if (Array.isArray(files) && !files.includes("README.md")) {
    files.push("README.md");
    console.warn(chalk.yellow('Publint [custom]: added "README.md" to "files"'));
    result.modified = true;
    result.warnings++;
  }
  if (Array.isArray(files) && files.includes("src")) {
    if (fix) {
      pkg.files = files.filter((f) => f !== "src");
      console.warn(chalk.yellow('Publint [custom]: removed "src" from "files"'));
      result.modified = true;
    } else {
      console.warn(chalk.yellow('Publint [custom]: "src" should not be in "files" (use --fix to remove)'));
    }
    result.warnings++;
  }
  return result;
}
function checkExportsSource(pkg, fix) {
  const result = emptyCustomResult();
  const exports = pkg.exports;
  if (exports && typeof exports === "object" && hasSourceInExports(exports)) {
    if (fix) {
      removeSourceFromExports(exports);
      console.warn(chalk.yellow('Publint [custom]: removed "source" entries from "exports"'));
      result.modified = true;
    } else {
      console.warn(chalk.yellow('Publint [custom]: "source" entries should not be in "exports" (use --fix to remove)'));
    }
    result.warnings++;
  }
  return result;
}
function migrateFieldToExports(pkg, field, exportKey, fix) {
  const result = emptyCustomResult();
  if (pkg[field] === void 0) return result;
  const fieldValue = pkg[field];
  if (!fieldValue.endsWith(".js") && !fieldValue.endsWith(".mjs") && !fieldValue.endsWith(".cjs")) return result;
  if (fix) {
    const exportValue = ensureExportsPath(fieldValue);
    const exports = pkg.exports;
    if (exports && typeof exports === "object") {
      const dot = exports["."];
      if (dot && typeof dot === "object" && !dot[exportKey]) {
        dot[exportKey] = exportValue;
        console.warn(chalk.yellow(`Publint [custom]: migrated "${field}" to "exports['.'].${exportKey}" (${fieldValue})`));
      }
    } else if (!pkg.exports) {
      pkg.exports = { ".": { [exportKey]: exportValue } };
      console.warn(chalk.yellow(`Publint [custom]: migrated "${field}" to "exports" (.\u2192${fieldValue})`));
    }
    delete pkg[field];
    console.warn(chalk.yellow(`Publint [custom]: removed deprecated "${field}" field`));
    result.modified = true;
  } else {
    console.warn(chalk.yellow(`Publint [custom]: "${field}" field is deprecated, use "exports" instead (use --fix to remove)`));
  }
  result.warnings++;
  return result;
}
function checkSideEffects(pkg) {
  const result = emptyCustomResult();
  if (pkg.sideEffects !== false) {
    console.warn(chalk.yellow('Publint [custom]: "sideEffects" field should be set to false'));
    result.warnings++;
  }
  return result;
}
function checkRootSource(pkg, fix) {
  const result = emptyCustomResult();
  for (const field of ["source", "src"]) {
    if (pkg[field] !== void 0) {
      if (fix) {
        delete pkg[field];
        console.warn(chalk.yellow(`Publint [custom]: removed root-level "${field}" field`));
        result.modified = true;
      } else {
        console.warn(chalk.yellow(`Publint [custom]: root-level "${field}" field should not be in package.json (use --fix to remove)`));
      }
      result.warnings++;
    }
  }
  return result;
}
function checkResolutions(pkg) {
  const result = emptyCustomResult();
  if (pkg.resolutions !== void 0) {
    console.warn(chalk.yellow('Publint [custom]: "resolutions" in use'));
    console.warn(chalk.gray(JSON.stringify(pkg.resolutions, null, 2)));
    result.warnings++;
  }
  return result;
}
function checkImportToDefault(pkg, fix) {
  const result = emptyCustomResult();
  const exports = pkg.exports;
  if (!exports || typeof exports !== "object") return result;
  if (!hasImportKeyInExports(exports)) return result;
  if (fix) {
    replaceImportWithDefault(exports);
    console.warn(chalk.yellow('Publint [custom]: renamed "import" to "default" in "exports" and ensured "types" siblings'));
    result.modified = true;
  } else {
    console.warn(chalk.yellow('Publint [custom]: "import" entries in "exports" should use "default" instead (use --fix to rename)'));
  }
  result.warnings++;
  return result;
}
function checkRootTypes(pkg, fix) {
  const result = emptyCustomResult();
  if (pkg.types === void 0) return result;
  const exports = pkg.exports;
  if (!exports || typeof exports !== "object" || !hasTypesInExports(exports)) return result;
  if (fix) {
    delete pkg.types;
    console.warn(chalk.yellow('Publint [custom]: removed redundant root "types" field (already defined in "exports")'));
    result.modified = true;
  } else {
    console.warn(chalk.yellow('Publint [custom]: root "types" field is redundant when "exports" defines types (use --fix to remove)'));
  }
  result.warnings++;
  return result;
}
function customPubLint(pkg, fix = false, exclude = /* @__PURE__ */ new Set()) {
  const result = emptyCustomResult();
  if (!exclude.has("files")) mergeResults(result, checkFiles(pkg, fix));
  if (!exclude.has("source")) mergeResults(result, checkExportsSource(pkg, fix));
  if (!exclude.has("rootSource")) mergeResults(result, checkRootSource(pkg, fix));
  if (!exclude.has("main")) mergeResults(result, migrateFieldToExports(pkg, "main", "default", fix));
  if (!exclude.has("types")) mergeResults(result, migrateFieldToExports(pkg, "types", "types", fix));
  if (!exclude.has("module")) mergeResults(result, migrateFieldToExports(pkg, "module", "default", fix));
  if (!exclude.has("importToDefault")) mergeResults(result, checkImportToDefault(pkg, fix));
  if (!exclude.has("rootTypes")) mergeResults(result, checkRootTypes(pkg, fix));
  if (!exclude.has("sideEffects")) mergeResults(result, checkSideEffects(pkg));
  if (!exclude.has("resolutions")) mergeResults(result, checkResolutions(pkg));
  return [result.errors, result.warnings, result.modified];
}
var ALWAYS_INCLUDED_PATTERNS = [
  "package.json",
  "README",
  "README.*",
  "LICENCE",
  "LICENCE.*",
  "LICENSE",
  "LICENSE.*",
  "CHANGELOG",
  "CHANGELOG.*"
];
async function resolvePackFiles(pkgDir, filesField) {
  const patterns = [...ALWAYS_INCLUDED_PATTERNS];
  if (filesField) {
    for (const pattern of filesField) {
      if (pattern.startsWith("!")) {
        patterns.push(pattern);
      } else {
        patterns.push(pattern, `${pattern}/**`);
      }
    }
  }
  const matched = await glob(patterns, {
    cwd: pkgDir,
    nodir: true,
    dot: false
  });
  const files = await Promise.all(
    matched.map(async (rel) => {
      const abs = path.join(pkgDir, rel);
      const data = await fs.readFile(abs, "utf8").catch(() => "");
      return { name: path.join(pkgDir, rel), data };
    })
  );
  return files;
}
async function runPublintLibrary(pkgDir, pkg, strict, pack) {
  const { publint } = await import("publint");
  let packOption = false;
  if (pack) {
    const files = await resolvePackFiles(pkgDir, pkg.files);
    packOption = { files };
  }
  const { messages } = await publint({
    level: "suggestion",
    pack: packOption,
    pkgDir,
    strict
  });
  const { formatMessage } = await import("publint/utils");
  for (const message of messages) {
    switch (message.type) {
      case "error": {
        console.error(chalk.red(`[${message.code}] ${formatMessage(message, pkg)}`));
        break;
      }
      case "warning": {
        console.warn(chalk.yellow(`[${message.code}] ${formatMessage(message, pkg)}`));
        break;
      }
      default: {
        console.log(chalk.white(`[${message.code}] ${formatMessage(message, pkg)}`));
        break;
      }
    }
  }
  return {
    errors: messages.filter((message) => message.type === "error").length,
    total: messages.length
  };
}
var packagePublint = async ({
  exclude = /* @__PURE__ */ new Set(),
  fix = false,
  pack = true,
  pkgDir: pkgDirParam,
  strict = true,
  verbose: _verbose = false
} = {}) => {
  const pkgDir = pkgDirParam ?? INIT_CWD();
  const sortedPkg = sortPackageJson(await fs.readFile(`${pkgDir}/package.json`, "utf8"));
  await fs.writeFile(`${pkgDir}/package.json`, sortedPkg);
  const pkg = JSON.parse(await fs.readFile(`${pkgDir}/package.json`, "utf8"));
  const effectiveExclude = pkg.private ? /* @__PURE__ */ new Set([...exclude, ...PUBLISH_ONLY_CHECKS]) : exclude;
  console.log(chalk.green(`Publint: ${String(pkg.name)}${pkg.private ? chalk.gray(" (private)") : ""}`));
  console.log(chalk.gray(pkgDir));
  let libraryErrors = 0;
  if (!effectiveExclude.has("publint")) {
    const library = await runPublintLibrary(pkgDir, pkg, strict, pack);
    libraryErrors = library.errors;
  }
  const [errorCount, _warningCount, modified] = customPubLint(pkg, fix, effectiveExclude);
  if (modified) {
    const sorted = sortPackageJson(JSON.stringify(pkg, null, 2));
    await fs.writeFile(`${pkgDir}/package.json`, sorted);
  }
  return libraryErrors + errorCount;
};
export {
  packagePublint
};
//# sourceMappingURL=publint.mjs.map