#!/usr/bin/env node

// src/bin/package/build.ts
import { cwd as cwd5 } from "node:process";
import chalk12 from "chalk";

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

// 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 sourceIsArray = Array.isArray(source);
  const targetIsArray = Array.isArray(target);
  if (sourceIsArray !== targetIsArray) {
    return cloneValue(source);
  }
  if (sourceIsArray) {
    return [...target, ...source].map((item) => cloneValue(item));
  }
  return mergeObject(target, source, options);
}

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

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

// src/lib/reporting/xyReporter.ts
var strictMode = false;
function isStrictMode() {
  return strictMode || process.env.XY_STRICT === "1";
}

// src/actions/publint.ts
import chalk11 from "chalk";

// src/actions/package/compile/compile.ts
import { cwd as cwd4 } from "node:process";
import chalk7 from "chalk";

// src/actions/package/compile/packageCompileEsbuild.ts
import fs2 from "node:fs";
import path2 from "node:path";
import { cwd as cwd3 } from "node:process";
import chalk6 from "chalk";
import { build } from "esbuild";

// src/actions/package/compile/inputs.ts
import chalk2 from "chalk";
import { glob } from "glob";
var getAllInputs = (srcDir, verbose2 = false) => {
  return glob.sync(`${srcDir}/**/*.{ts,tsx,mts,cts}`, { posix: true }).map((file) => {
    const result = file.slice(Math.max(0, srcDir.length + 1));
    if (verbose2) {
      console.log(chalk2.gray(`getAllInputs: ${JSON.stringify(result, null, 2)}`));
    }
    return result;
  });
};

// src/actions/package/compile/buildEntries.ts
var bareSpecOrStoryRe = /(?:^|\/)(?:spec|stories)\.(?:ts|tsx|mts|cts)$/;
var isSpecOrStory = (entry) => {
  return entry.includes(".spec.") || entry.includes(".stories.") || entry.startsWith("spec/") || entry.includes("/spec/") || entry.startsWith("stories/") || entry.includes("/stories/") || bareSpecOrStoryRe.test(entry);
};
var isDeclaration = (entry) => /\.d\.(?:ts|mts|cts)$/.test(entry);
var buildEntries = (srcDir, entryMode = "single", options, excludeSpecAndStories = true, verbose2 = false) => {
  let entries;
  switch (entryMode) {
    case "platform": {
      entries = ["index-node.ts", "index-browser.ts"];
      break;
    }
    case "all": {
      entries = (excludeSpecAndStories ? getAllInputs(srcDir).filter((entry) => !isSpecOrStory(entry)) : getAllInputs(srcDir)).filter((entry) => !isDeclaration(entry));
      break;
    }
    case "custom": {
      entries = [];
      break;
    }
    default: {
      entries = ["index.ts"];
      break;
    }
  }
  if (typeof options !== "boolean" && Array.isArray(options?.entry)) {
    entries.push(...options.entry);
  }
  if (verbose2) console.log(`buildEntries [${entryMode}] ${entries.length}`);
  return entries;
};

// src/actions/package/compile/deepMerge.ts
function deepMerge2(target, source) {
  if (!source || typeof source !== "object") return target;
  for (const [key, sourceVal] of Object.entries(source)) {
    if (typeof sourceVal === "object" && sourceVal !== null && !Array.isArray(sourceVal)) {
      if (!Object.hasOwn(target, key) || typeof target[key] !== "object") {
        target[key] = {};
      }
      deepMerge2(target[key], sourceVal);
    } else {
      target[key] = sourceVal;
    }
  }
  return target;
}
function deepMergeObjects(objects) {
  const result = {};
  for (const obj of objects) {
    deepMerge2(result, obj);
  }
  return result;
}

// src/actions/package/compile/resolveCompilePlatforms.ts
import { cwd } from "node:process";
import chalk3 from "chalk";
var resolvePlatformRecord = (value) => {
  if (value === void 0 || value === true) return { src: {} };
  if (value === false) return {};
  const { esbuildOptions: _legacyEsbuildOptions, ...entries } = value;
  return entries;
};
var classifyPlatform = (value) => {
  if (value === void 0) {
    return {
      deprecatedEmptyObject: false,
      entries: {},
      state: "unset"
    };
  }
  if (typeof value === "boolean") {
    return {
      deprecatedEmptyObject: false,
      entries: value ? { src: {} } : {},
      state: value ? "build" : "off"
    };
  }
  const deprecatedEmptyObject = Object.keys(value).length === 0;
  const entries = resolvePlatformRecord(value);
  return {
    deprecatedEmptyObject,
    entries,
    state: Object.keys(entries).length > 0 ? "build" : "off"
  };
};
var resolveCompilePlatforms = (compile) => {
  const node = classifyPlatform(compile?.node);
  const browser = classifyPlatform(compile?.browser);
  const neutral = classifyPlatform(compile?.neutral);
  const anyBuild = node.state === "build" || browser.state === "build" || neutral.state === "build";
  const neutralEntries = neutral.state === "build" ? neutral.entries : !anyBuild && neutral.state === "unset" ? { src: {} } : {};
  const deprecatedEmptyObjectTargets = [
    ...node.deprecatedEmptyObject ? ["node"] : [],
    ...browser.deprecatedEmptyObject ? ["browser"] : [],
    ...neutral.deprecatedEmptyObject ? ["neutral"] : []
  ];
  return {
    browser: browser.state === "build" ? browser.entries : {},
    deprecatedEmptyObjectTargets,
    neutral: neutralEntries,
    node: node.state === "build" ? node.entries : {}
  };
};
var deprecatedEmptyObjectWarned = /* @__PURE__ */ new Set();
var warnDeprecatedEmptyObjectTargets = (targets) => {
  for (const target of targets) {
    const key = `${cwd()}:${target}`;
    if (deprecatedEmptyObjectWarned.has(key)) continue;
    deprecatedEmptyObjectWarned.add(key);
    console.warn(chalk3.yellow(
      `[xy] Deprecated: compile.${target} = {} is treated as "do not build". Set it to \`false\` or remove the field.`
    ));
  }
};

// src/actions/package/compile/runTsc.ts
import { cwd as cwd2 } from "node:process";
import chalk4 from "chalk";
var runTsc = (configPath, verbose2 = false, extraArgs = []) => {
  const args = ["-p", configPath, ...extraArgs];
  if (verbose2) {
    console.log(chalk4.gray(`tsc ${args.join(" ")}`));
  }
  const result = spawnSync("tsc", args, {
    cwd: cwd2(),
    stdio: "inherit"
  });
  return result.status ?? (result.error === void 0 ? 0 : 1);
};

// src/actions/package/compile/validateFullPackage.ts
import fs from "node:fs";
import path from "node:path";
import chalk5 from "chalk";
import ts, { formatDiagnosticsWithColorAndContext, sys } from "typescript";
var toPosixPath = (value) => value.split(path.sep).join("/");
var relativePath = (from, to) => {
  const result = toPosixPath(path.relative(from, to));
  return result.startsWith(".") ? result : `./${result}`;
};
var formatTsConfigDiagnostics = (diagnostics, pkg) => {
  return formatDiagnosticsWithColorAndContext(diagnostics, {
    getCanonicalFileName: (fileName) => fileName,
    getCurrentDirectory: () => pkg,
    getNewLine: () => sys.newLine
  });
};
var isInPackageSubdirectory = (pkg, fileName, directoryName) => {
  const relative = toPosixPath(path.relative(path.resolve(pkg, directoryName), fileName));
  return relative !== "" && !relative.startsWith("../") && relative !== "..";
};
var createFullValidationConfig = (pkg, tsconfigPath) => {
  const configFile = ts.readConfigFile(tsconfigPath, (fileName) => ts.sys.readFile(fileName));
  if (configFile.error) {
    return { configPath: tsconfigPath, diagnostics: [configFile.error] };
  }
  const parsed = ts.parseJsonConfigFileContent(
    configFile.config,
    ts.sys,
    pkg,
    void 0,
    tsconfigPath
  );
  const buildDir = path.resolve(pkg, "build");
  fs.mkdirSync(buildDir, { recursive: true });
  const configPath = path.resolve(buildDir, "tsconfig.package-validate.json");
  const files = parsed.fileNames.filter((fileName) => !isInPackageSubdirectory(pkg, fileName, "packages")).map((fileName) => relativePath(buildDir, fileName));
  if (files.length === 0) {
    const emptyFile = path.resolve(buildDir, "tsconfig.package-validate-empty.d.ts");
    fs.writeFileSync(emptyFile, "");
    files.push(relativePath(buildDir, emptyFile));
  }
  fs.writeFileSync(
    configPath,
    `${JSON.stringify({
      compilerOptions: {
        noEmit: true,
        rootDir: relativePath(buildDir, pkg)
      },
      extends: relativePath(buildDir, tsconfigPath),
      files,
      include: []
    }, null, 2)}
`
  );
  return { configPath, diagnostics: parsed.errors };
};
var validateFullPackage = (pkg, verbose2 = false) => {
  const tsconfigPath = path.resolve(pkg, "tsconfig.json");
  if (!fs.existsSync(tsconfigPath)) {
    console.warn(chalk5.yellow("Compile:Validate skipped \u2014 tsconfig.json not found"));
    return 0;
  }
  if (verbose2) {
    console.log(chalk5.cyan("Compile:Validate [tsconfig.json]"));
  }
  const { configPath, diagnostics } = createFullValidationConfig(pkg, tsconfigPath);
  if (diagnostics.length > 0) {
    console.error(formatTsConfigDiagnostics(diagnostics, pkg));
    return 1;
  }
  const result = runTsc(configPath, verbose2);
  if (result !== 0) {
    console.error(chalk5.red(`Compile:Validate failed (tsc exit code ${result})`));
  }
  return result;
};

// src/actions/package/compile/packageCompileEsbuild.ts
var isBuildFormat = (value) => {
  return typeof value === "string" && ["cjs", "esm", "iife"].includes(value);
};
var legacyIgnoredOptions = /* @__PURE__ */ new Set([
  "clean",
  "cjsInterop",
  "dts",
  "entry",
  "outDir",
  "silent",
  "skipNodeModulesBundle"
]);
var supportedEsbuildOptions = /* @__PURE__ */ new Set([
  "absWorkingDir",
  "alias",
  "allowOverwrite",
  "assetNames",
  "banner",
  "bundle",
  "charset",
  "chunkNames",
  "color",
  "conditions",
  "define",
  "drop",
  "dropLabels",
  "entryNames",
  "entryPoints",
  "external",
  "footer",
  "format",
  "globalName",
  "ignoreAnnotations",
  "inject",
  "jsx",
  "jsxDev",
  "jsxFactory",
  "jsxFragment",
  "jsxImportSource",
  "jsxSideEffects",
  "keepNames",
  "legalComments",
  "lineLimit",
  "loader",
  "logLevel",
  "logLimit",
  "logOverride",
  "mainFields",
  "mangleCache",
  "mangleProps",
  "mangleQuoted",
  "metafile",
  "minify",
  "minifyIdentifiers",
  "minifySyntax",
  "minifyWhitespace",
  "nodePaths",
  "outExtension",
  "outbase",
  "outdir",
  "outfile",
  "packages",
  "platform",
  "plugins",
  "preserveSymlinks",
  "publicPath",
  "pure",
  "reserveProps",
  "resolveExtensions",
  "sourcemap",
  "sourceRoot",
  "sourcesContent",
  "splitting",
  "stdin",
  "supported",
  "target",
  "treeShaking",
  "tsconfig",
  "tsconfigRaw",
  "watch",
  "write"
]);
var toPosixPath2 = (value) => value.split(path2.sep).join("/");
var relativePath2 = (from, to) => {
  const result = toPosixPath2(path2.relative(from, to));
  return result.startsWith(".") ? result : `./${result}`;
};
var safeFilePart = (value) => value.replaceAll(/[^\dA-Za-z-]+/g, "-").replaceAll(/(?:^-|-$)/g, "") || "src";
var platformSourceSegments = /* @__PURE__ */ new Set(["browser", "neutral", "node"]);
var normalizeEntryPath = (entry) => toPosixPath2(entry).replace(/^\.?\//u, "");
var customEntryOutputName = (entry) => {
  const parsed = path2.posix.parse(normalizeEntryPath(entry));
  const withoutExtension = path2.posix.join(parsed.dir, parsed.name);
  const segments = withoutExtension.split("/");
  return segments.length > 1 && platformSourceSegments.has(segments[0]) ? segments.slice(1).join("/") : withoutExtension;
};
var createEsbuildEntryPoints = (srcDir, entries, entryMode = "single") => {
  if (entryMode !== "custom") {
    return entries.map((entry) => `${srcDir}/${normalizeEntryPath(entry)}`);
  }
  const entryPoints = {};
  for (const entry of entries) {
    const outputName = customEntryOutputName(entry);
    if (entryPoints[outputName] !== void 0) {
      throw new Error(`Duplicate custom entry output "${outputName}" from "${entry}"`);
    }
    entryPoints[outputName] = `${srcDir}/${normalizeEntryPath(entry)}`;
  }
  return entryPoints;
};
var createTypescriptConfig = ({
  declaration = false,
  outDir,
  pkg,
  srcDir
}) => {
  const buildDir = path2.resolve(pkg, "build");
  const sourceRoot = path2.resolve(pkg, srcDir);
  return {
    compilerOptions: {
      ...declaration ? {
        declaration: true,
        declarationMap: true,
        emitDeclarationOnly: true,
        noEmit: false,
        outDir: outDir === void 0 ? void 0 : relativePath2(buildDir, path2.resolve(pkg, outDir))
      } : { noEmit: true },
      rootDir: relativePath2(buildDir, sourceRoot)
    },
    exclude: [
      `${relativePath2(buildDir, sourceRoot)}/**/*.spec.*`,
      `${relativePath2(buildDir, sourceRoot)}/**/*.stories.*`,
      `${relativePath2(buildDir, sourceRoot)}/**/*.example.*`,
      `${relativePath2(buildDir, sourceRoot)}/**/spec/**`,
      `${relativePath2(buildDir, sourceRoot)}/**/stories/**`
    ],
    extends: relativePath2(buildDir, path2.resolve(pkg, "tsconfig.json")),
    include: [`${relativePath2(buildDir, sourceRoot)}/**/*`]
  };
};
var writeTypescriptConfig = (pkg, platform, srcDir, declaration, outDir) => {
  const buildDir = path2.resolve(pkg, "build");
  fs2.mkdirSync(buildDir, { recursive: true });
  const configPath = path2.resolve(buildDir, `tsconfig.package-${declaration ? "dts" : "check"}-${platform}-${safeFilePart(srcDir)}.json`);
  fs2.writeFileSync(
    configPath,
    `${JSON.stringify(createTypescriptConfig({
      declaration,
      outDir,
      pkg,
      srcDir
    }), null, 2)}
`
  );
  return configPath;
};
function copyDeclarationFiles(fromDir, toDir) {
  if (path2.resolve(fromDir) === path2.resolve(toDir) || !fs2.existsSync(fromDir)) return;
  const copyFrom = (dir) => {
    for (const entry of fs2.readdirSync(dir, { withFileTypes: true })) {
      const sourcePath = path2.join(dir, entry.name);
      const relative = path2.relative(fromDir, sourcePath);
      const targetPath = path2.join(toDir, relative);
      if (entry.isDirectory()) {
        copyFrom(sourcePath);
      } else if (entry.isFile() && (entry.name.endsWith(".d.ts") || entry.name.endsWith(".d.ts.map"))) {
        fs2.mkdirSync(path2.dirname(targetPath), { recursive: true });
        fs2.copyFileSync(sourcePath, targetPath);
      }
    }
  };
  copyFrom(fromDir);
}
var normalizeOptions = (options = {}, verbose2 = false) => {
  const normalized = {};
  const ignored = [];
  for (const [key, value] of Object.entries(options)) {
    if (legacyIgnoredOptions.has(key)) {
      ignored.push(key);
      continue;
    }
    if (key === "format" && Array.isArray(value)) {
      if (isBuildFormat(value[0])) {
        normalized.format = value[0];
      }
      continue;
    }
    if (key === "outExtension" && typeof value === "function") {
      ignored.push(key);
      continue;
    }
    if (supportedEsbuildOptions.has(key)) {
      normalized[key] = value;
      continue;
    }
    ignored.push(key);
  }
  if (verbose2 && ignored.length > 0) {
    console.warn(chalk6.yellow(`[xy] Ignoring unsupported compile options for esbuild: ${[...new Set(ignored)].toSorted((a, b) => a.localeCompare(b)).join(", ")}`));
  }
  return normalized;
};
var esbuildOptions = (options = [], verbose2 = false) => {
  const standardLoaders = {
    ".gif": "copy",
    ".html": "copy",
    ".jpg": "copy",
    ".json": "json",
    ".png": "copy",
    ".svg": "text",
    ".webp": "copy"
  };
  const standardOptions = {
    bundle: true,
    format: "esm",
    loader: standardLoaders,
    outExtension: { ".js": ".mjs" },
    packages: "external",
    sourcemap: true,
    target: "esnext"
  };
  return deepMergeObjects([standardOptions, ...options.map((option) => normalizeOptions(option, verbose2))]);
};
var resolvePlatformEsbuildOptions = (value) => {
  if (typeof value !== "object" || value === null) return {};
  const entry = value.esbuildOptions;
  return entry ?? {};
};
var getRootOutDir = (options) => {
  return options.outDir ?? options.outdir ?? "dist";
};
var compileFolder = async (srcDir, entries, options, platform, outDir, checkTypes, emitDeclarations, entryMode, verbose2) => {
  const pkg = cwd3();
  if (verbose2) {
    console.log(chalk6.gray(`compileFolder [${srcDir}, ${outDir}]`));
  }
  if (!fs2.existsSync(path2.resolve(pkg, srcDir))) {
    if (verbose2) {
      console.warn(chalk6.yellow(`No source directory found in ${srcDir} to compile`));
    }
    return 0;
  }
  if (entries.length === 0) {
    console.warn(chalk6.yellow(`No entries found in ${srcDir} to compile`));
    return 0;
  }
  if (checkTypes) {
    const checkConfig = writeTypescriptConfig(pkg, platform, srcDir, false);
    const checkResult = runTsc(checkConfig, verbose2);
    if (checkResult !== 0) {
      console.error(chalk6.red(`Compile:Validation had ${checkResult} errors`));
      return checkResult;
    }
  }
  const declarationResult = await emitDeclarations();
  if (declarationResult !== 0) {
    console.error(chalk6.red(`Compile:Declaration emit had ${declarationResult} errors`));
    return declarationResult;
  }
  const buildOptions = {
    ...options,
    entryPoints: createEsbuildEntryPoints(srcDir, entries, entryMode),
    outbase: srcDir,
    outdir: outDir,
    platform,
    tsconfig: "tsconfig.json"
  };
  if (verbose2) {
    console.log(chalk6.cyan(`ESBUILD:build:start [${srcDir}]`));
    const pluginNames = buildOptions.plugins?.map((plugin) => plugin.name);
    const loggedOptions = { ...buildOptions, plugins: pluginNames };
    console.log(chalk6.gray(`ESBUILD:build:options [${JSON.stringify(loggedOptions, null, 2)}]`));
  }
  await build(buildOptions);
  if (verbose2) {
    console.log(chalk6.cyan(`ESBUILD:build:stop [${srcDir}]`));
  }
  return 0;
};
function createDeclarationEmitter(verbose2 = false) {
  const declarationPromises = /* @__PURE__ */ new Map();
  return async (srcDir, rootOutDir, platform, outDir) => {
    const key = `${srcDir}\0${rootOutDir}`;
    let promise = declarationPromises.get(key);
    if (!promise) {
      promise = (async () => {
        const dtsConfig = writeTypescriptConfig(cwd3(), platform, srcDir, true, outDir);
        return { outDir, result: runTsc(dtsConfig, verbose2) };
      })();
      declarationPromises.set(key, promise);
    }
    const emitted = await promise;
    if (emitted.result !== 0) return emitted.result;
    copyDeclarationFiles(emitted.outDir, outDir);
    return 0;
  };
}
function resolveCompileMode(config2, mode) {
  const compile = config2?.compile;
  const verbose2 = config2?.verbose ?? false;
  const shouldEmit = !mode.validateOnly;
  const shouldRunFullValidation = !mode.emitOnly && (compile?.validate ?? true);
  return {
    compile,
    shouldEmit,
    shouldRunFolderChecks: !shouldRunFullValidation && !mode.emitOnly,
    shouldRunFullValidation,
    verbose: verbose2
  };
}
async function compilePlatformEntries({
  checkTypes,
  compile,
  emitDeclarations,
  entries,
  legacyTsupOptions,
  platform,
  platformEsbuild,
  verbose: verbose2
}) {
  const results = await Promise.all(
    Object.entries(entries).map(async ([srcDir, options]) => {
      const rootOutDir = getRootOutDir(options);
      const outDir = `${rootOutDir}/${platform}`;
      const entry = buildEntries(srcDir, compile?.entryMode, options, true, verbose2);
      return compileFolder(
        srcDir,
        entry,
        esbuildOptions([
          platformEsbuild,
          legacyTsupOptions ?? {},
          compile?.esbuild?.options ?? {},
          options,
          { outdir: outDir }
        ], verbose2),
        platform,
        outDir,
        checkTypes,
        () => emitDeclarations(srcDir, rootOutDir, platform, outDir),
        compile?.entryMode,
        verbose2
      );
    })
  );
  return results.reduce((prev, value) => prev + value, 0);
}
var packageCompileEsbuild = async (config2, mode = {}) => {
  const {
    compile,
    shouldEmit,
    shouldRunFolderChecks,
    shouldRunFullValidation,
    verbose: verbose2
  } = resolveCompileMode(config2, mode);
  if (verbose2) {
    console.log("Compiling with esbuild and tsc");
  }
  if (shouldRunFullValidation) {
    const validateResult = validateFullPackage(cwd3(), verbose2);
    if (validateResult !== 0) {
      return validateResult;
    }
  }
  if (!shouldEmit) return 0;
  const platforms = resolveCompilePlatforms(compile);
  warnDeprecatedEmptyObjectTargets(platforms.deprecatedEmptyObjectTargets);
  const compileForNode = platforms.node;
  const compileForBrowser = platforms.browser;
  const compileForNeutral = platforms.neutral;
  const nodeEsbuild = resolvePlatformEsbuildOptions(compile?.node);
  const browserEsbuild = resolvePlatformEsbuildOptions(compile?.browser);
  const neutralEsbuild = resolvePlatformEsbuildOptions(compile?.neutral);
  const legacyTsupOptions = compile?.tsup?.options;
  const emitDeclarations = createDeclarationEmitter(verbose2);
  const [nodeErrors, browserErrors, neutralErrors] = await Promise.all([
    compilePlatformEntries({
      checkTypes: shouldRunFolderChecks,
      compile,
      emitDeclarations,
      entries: compileForNode,
      legacyTsupOptions,
      platform: "node",
      platformEsbuild: nodeEsbuild,
      verbose: verbose2
    }),
    compilePlatformEntries({
      checkTypes: shouldRunFolderChecks,
      compile,
      emitDeclarations,
      entries: compileForBrowser,
      legacyTsupOptions,
      platform: "browser",
      platformEsbuild: browserEsbuild,
      verbose: verbose2
    }),
    compilePlatformEntries({
      checkTypes: shouldRunFolderChecks,
      compile,
      emitDeclarations,
      entries: compileForNeutral,
      legacyTsupOptions,
      platform: "neutral",
      platformEsbuild: neutralEsbuild,
      verbose: verbose2
    })
  ]);
  return nodeErrors + browserErrors + neutralErrors;
};

// src/actions/package/compile/compile.ts
var packageCompile = async (inConfig = {}, mode = {}) => {
  const pkg = cwd4();
  console.log(chalk7.green(`Compiling ${pkg}`));
  const config2 = await loadConfig(inConfig);
  return await packageCompileEsbuild(config2, mode);
};

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

// src/actions/package/publint.ts
import { promises as fs5 } from "node:fs";
import path5 from "node:path";
import chalk10 from "chalk";
import { glob as glob2 } from "glob";
import sortPackageJson from "sort-package-json";

// src/actions/package/compileTargetsPublint.ts
import fs3 from "node:fs";
import path3 from "node:path";
import chalk8 from "chalk";
import ts2 from "typescript";
var COMPILE_TARGET_NAMES = /* @__PURE__ */ new Set(["browser", "neutral", "node"]);
var CONFIG_FILE_NAMES = [
  "xy.config.ts",
  "xy.config.mts",
  "xy.config.cts",
  "xy.config.js",
  "xy.config.mjs",
  "xy.config.cjs"
];
function emptyResult() {
  return {
    errors: 0,
    modified: false,
    warnings: 0
  };
}
function findConfigFile(pkgDir) {
  for (const name of CONFIG_FILE_NAMES) {
    const candidate = path3.join(pkgDir, name);
    if (fs3.existsSync(candidate)) return candidate;
  }
  return void 0;
}
function getPropertyName(prop) {
  if (!ts2.isPropertyAssignment(prop)) return void 0;
  const { name } = prop;
  if (ts2.isIdentifier(name) || ts2.isStringLiteral(name)) return name.text;
  return void 0;
}
function collectEmptyTargetProps(sourceFile) {
  const found = [];
  function visit(node) {
    if (ts2.isPropertyAssignment(node) && getPropertyName(node) === "compile" && ts2.isObjectLiteralExpression(node.initializer)) {
      for (const prop of node.initializer.properties) {
        if (ts2.isPropertyAssignment(prop) && COMPILE_TARGET_NAMES.has(getPropertyName(prop) ?? "") && ts2.isObjectLiteralExpression(prop.initializer) && prop.initializer.properties.length === 0) {
          found.push(prop);
        }
      }
    }
    ts2.forEachChild(node, visit);
  }
  visit(sourceFile);
  return found;
}
function isWhitespace(char) {
  return char !== void 0 && /\s/.test(char);
}
function removeProperties(text, props, sourceFile) {
  const sorted = props.toSorted((a, b) => b.getStart(sourceFile) - a.getStart(sourceFile));
  let result = text;
  for (const prop of sorted) {
    let start = prop.getFullStart();
    let end = prop.getEnd();
    let cursor = end;
    while (isWhitespace(result[cursor])) cursor++;
    if (result[cursor] === ",") {
      end = cursor + 1;
    } else {
      let back = prop.getStart(sourceFile) - 1;
      while (back >= 0 && isWhitespace(result[back])) back--;
      if (result[back] === ",") start = back;
    }
    result = result.slice(0, start) + result.slice(end);
  }
  return result;
}
function checkCompileTargets(pkgDir, fix) {
  const result = emptyResult();
  const configPath = findConfigFile(pkgDir);
  if (configPath === void 0) return result;
  const text = fs3.readFileSync(configPath, "utf8");
  const sourceFile = ts2.createSourceFile(path3.basename(configPath), text, ts2.ScriptTarget.Latest, true, ts2.ScriptKind.TS);
  const emptyProps = collectEmptyTargetProps(sourceFile);
  if (emptyProps.length === 0) return result;
  const configName = path3.basename(configPath);
  if (fix) {
    fs3.writeFileSync(configPath, removeProperties(text, emptyProps, sourceFile));
    for (const prop of emptyProps) {
      console.warn(chalk8.yellow(`Publint [compileTargets]: removed deprecated empty "compile.${getPropertyName(prop)}" target from ${configName}`));
    }
    result.modified = true;
  } else {
    for (const prop of emptyProps) {
      console.warn(chalk8.yellow(
        `Publint [compileTargets]: "compile.${getPropertyName(prop)} = {}" is treated as "do not build" \u2014 set it to \`false\` or remove it (use --fix to remove) in ${configName}`
      ));
    }
  }
  result.warnings += emptyProps.length;
  return result;
}

// src/actions/package/platformPublint.ts
import fs4 from "node:fs";
import { builtinModules } from "node:module";
import path4 from "node:path";
import chalk9 from "chalk";
import { globSync } from "glob";
import ts3 from "typescript";
var platformSegments = /* @__PURE__ */ new Set(["browser", "neutral", "node"]);
var nodeConditionNames = /* @__PURE__ */ new Set(["node", "node-addons"]);
var browserConditionNames = /* @__PURE__ */ new Set(["browser", "web", "webworker", "worker"]);
var neutralConditionNames = /* @__PURE__ */ new Set(["neutral"]);
var builtinModuleNames = new Set(
  builtinModules.map((mod) => mod.replace(/^node:/, "")).filter((mod) => !mod.startsWith("_"))
);
var codeExtensions = [".mjs", ".cjs", ".js"];
var declarationExtensions = [".d.mts", ".d.cts", ".d.ts"];
function emptyResult2() {
  return {
    errors: 0,
    modified: false,
    warnings: 0
  };
}
function toPosixPath3(value) {
  return value.split(path4.sep).join("/");
}
function relativePath3(pkgDir, filePath) {
  return toPosixPath3(path4.relative(pkgDir, filePath));
}
function isSubpathExportKey(key) {
  return key === "." || key.startsWith("./");
}
function formatExportPath(pathParts) {
  return pathParts.map((part, index) => {
    if (index === 0) return part;
    if (part.startsWith("[")) return part;
    return /^[a-zA-Z_$][\w$]*$/.test(part) ? `.${part}` : `[${JSON.stringify(part)}]`;
  }).join("");
}
function conditionPlatform(key) {
  if (nodeConditionNames.has(key)) return "node";
  if (browserConditionNames.has(key)) return "browser";
  if (neutralConditionNames.has(key)) return "neutral";
  return void 0;
}
function getConditionPlatform(conditionPath) {
  for (const condition of conditionPath.toReversed()) {
    const platform = conditionPlatform(condition);
    if (platform) return platform;
  }
  return void 0;
}
function getPathPlatform(target) {
  const segments = target.replace(/^\.\//, "").split(/[\\/]+/);
  const distIndex = segments.indexOf("dist");
  const platform = distIndex === -1 ? void 0 : segments[distIndex + 1];
  return platformSegments.has(platform) ? platform : void 0;
}
function collectExportTargets(value, pathParts = ["exports"], conditionPath = []) {
  if (typeof value === "string") {
    if (!value.startsWith("./")) return [];
    return [{
      conditionPath,
      conditionPlatform: getConditionPlatform(conditionPath),
      exportPath: formatExportPath(pathParts),
      pathPlatform: getPathPlatform(value),
      target: value
    }];
  }
  if (Array.isArray(value)) {
    return value.flatMap((entry, index) => collectExportTargets(entry, [...pathParts, `[${index}]`], conditionPath));
  }
  if (typeof value !== "object" || value === null) return [];
  return Object.entries(value).flatMap(([key, nested]) => {
    const nextConditionPath = isSubpathExportKey(key) ? conditionPath : [...conditionPath, key];
    return collectExportTargets(nested, [...pathParts, key], nextConditionPath);
  });
}
function isDeclarationFile(filePath) {
  return declarationExtensions.some((ext) => filePath.endsWith(ext));
}
function isCodeFile(filePath) {
  return codeExtensions.some((ext) => filePath.endsWith(ext));
}
function hasCodeOrDeclarationExtension(filePath) {
  return isCodeFile(filePath) || isDeclarationFile(filePath);
}
function pathCandidates(filePath, extensions) {
  const candidates = [filePath];
  const parsed = path4.parse(filePath);
  const withoutExtension = parsed.ext ? filePath.slice(0, -parsed.ext.length) : filePath;
  for (const ext of extensions) {
    candidates.push(`${withoutExtension}${ext}`, `${filePath}${ext}`, path4.join(filePath, `index${ext}`));
  }
  return [...new Set(candidates)];
}
function declarationCandidates(filePath) {
  const extensionCandidates = filePath.endsWith(".mjs") ? [filePath.replace(/\.mjs$/, ".d.mts"), filePath.replace(/\.mjs$/, ".d.ts")] : filePath.endsWith(".cjs") ? [filePath.replace(/\.cjs$/, ".d.cts"), filePath.replace(/\.cjs$/, ".d.ts")] : filePath.endsWith(".js") ? [filePath.replace(/\.js$/, ".d.ts")] : [];
  return [.../* @__PURE__ */ new Set([filePath, ...extensionCandidates, ...pathCandidates(filePath, declarationExtensions)])];
}
function resolveExistingFile(filePath, declaration) {
  const candidates = declaration ? declarationCandidates(filePath) : pathCandidates(filePath, codeExtensions);
  return candidates.find((candidate) => fs4.existsSync(candidate) && fs4.statSync(candidate).isFile());
}
function resolveExportTargetFiles(pkgDir, target) {
  if (!hasCodeOrDeclarationExtension(target) && !target.includes("*")) return [];
  const relativeTarget = target.replace(/^\.\//, "");
  if (relativeTarget.includes("*")) {
    return globSync(relativeTarget, {
      cwd: pkgDir,
      nodir: true,
      absolute: true
    }).filter(hasCodeOrDeclarationExtension);
  }
  const absoluteTarget = path4.resolve(pkgDir, relativeTarget);
  const exact = fs4.existsSync(absoluteTarget) && fs4.statSync(absoluteTarget).isFile() ? absoluteTarget : resolveExistingFile(absoluteTarget, isDeclarationFile(relativeTarget));
  return exact ? [exact] : [];
}
function isNodeBuiltin(specifier) {
  const normalized = specifier.replace(/^node:/, "");
  return specifier === "node" || specifier.startsWith("node:") || builtinModuleNames.has(normalized) || builtinModuleNames.has(normalized.split("/", 1)[0] ?? "");
}
function parseSourceFile(filePath) {
  const sourceCode = fs4.readFileSync(filePath, "utf8");
  const scriptKind = isCodeFile(filePath) ? ts3.ScriptKind.JS : ts3.ScriptKind.TS;
  return ts3.createSourceFile(path4.basename(filePath), sourceCode, ts3.ScriptTarget.Latest, true, scriptKind);
}
function stringLiteralText(node) {
  return node && ts3.isStringLiteral(node) ? node.text : void 0;
}
function collectModuleSpecifiers(sourceFile) {
  const specifiers = [];
  function addSpecifier(node) {
    const text = stringLiteralText(node);
    if (text) specifiers.push(text);
  }
  function visit(node) {
    if (ts3.isImportDeclaration(node) || ts3.isExportDeclaration(node)) {
      addSpecifier(node.moduleSpecifier);
    } else if (ts3.isCallExpression(node) && node.expression.kind === ts3.SyntaxKind.ImportKeyword) {
      addSpecifier(node.arguments[0]);
    } else if (ts3.isCallExpression(node) && ts3.isIdentifier(node.expression) && node.expression.text === "require" && node.arguments.length > 0) {
      addSpecifier(node.arguments[0]);
    } else if (ts3.isImportTypeNode(node)) {
      if (ts3.isLiteralTypeNode(node.argument)) addSpecifier(node.argument.literal);
    } else if (ts3.isImportEqualsDeclaration(node) && ts3.isExternalModuleReference(node.moduleReference)) {
      addSpecifier(node.moduleReference.expression);
    }
    ts3.forEachChild(node, visit);
  }
  visit(sourceFile);
  for (const ref of sourceFile.typeReferenceDirectives) {
    specifiers.push(ref.fileName);
  }
  return specifiers;
}
function resolveLocalSpecifier(filePath, specifier, declaration) {
  if (!specifier.startsWith(".")) return void 0;
  return resolveExistingFile(path4.resolve(path4.dirname(filePath), specifier), declaration);
}
function nodeAmbientGlobalFromName(name) {
  if (name === "NodeJS") return "NodeJS";
  if (name === "Buffer") return "Buffer";
  if (name === "process") return "process";
  return void 0;
}
function getQualifiedRootName(name) {
  return ts3.isIdentifier(name) ? name.text : getQualifiedRootName(name.left);
}
function getPropertyAccessRootName(expression) {
  let current = expression;
  while (ts3.isPropertyAccessExpression(current)) {
    current = current.expression;
  }
  return ts3.isIdentifier(current) ? current.text : "";
}
function getNodeAmbientGlobal(sourceFile) {
  let ambient;
  function visit(node) {
    if (ambient) return;
    if (ts3.isTypeReferenceNode(node)) {
      ambient = nodeAmbientGlobalFromName(getQualifiedRootName(node.typeName));
    } else if (ts3.isExpressionWithTypeArguments(node) && ts3.isIdentifier(node.expression)) {
      ambient = nodeAmbientGlobalFromName(node.expression.text);
    } else if (ts3.isExpressionWithTypeArguments(node) && ts3.isPropertyAccessExpression(node.expression)) {
      ambient = nodeAmbientGlobalFromName(getPropertyAccessRootName(node.expression));
    } else if (ts3.isTypeQueryNode(node)) {
      ambient = nodeAmbientGlobalFromName(getQualifiedRootName(node.exprName));
    }
    ts3.forEachChild(node, visit);
  }
  visit(sourceFile);
  return ambient;
}
function scanFileGraph(rootFile, platform, target) {
  const declaration = isDeclarationFile(rootFile);
  const queue = [rootFile];
  const seen = /* @__PURE__ */ new Set();
  const diagnostics = [];
  while (queue.length > 0) {
    const file = queue.shift();
    if (!file || seen.has(file)) continue;
    seen.add(file);
    const sourceFile = parseSourceFile(file);
    for (const specifier of collectModuleSpecifiers(sourceFile)) {
      if (isNodeBuiltin(specifier)) {
        diagnostics.push({
          detail: specifier,
          exportPath: target.exportPath,
          file,
          kind: "node-builtin-import",
          platform,
          target: target.target
        });
      }
      const resolved = resolveLocalSpecifier(file, specifier, declaration);
      if (resolved && !seen.has(resolved)) queue.push(resolved);
    }
    if (declaration) {
      const ambient = getNodeAmbientGlobal(sourceFile);
      if (ambient) {
        diagnostics.push({
          detail: ambient,
          exportPath: target.exportPath,
          file,
          kind: "node-ambient-type",
          platform,
          target: target.target
        });
      }
    }
  }
  return diagnostics;
}
function shouldScanForNodeUsage(target) {
  if (target.pathPlatform === "browser" || target.pathPlatform === "neutral") return target.pathPlatform;
  if (target.conditionPlatform === "browser" || target.conditionPlatform === "neutral") return target.conditionPlatform;
  return void 0;
}
function collectConditionTargetDiagnostics(targets) {
  const diagnostics = [];
  for (const target of targets) {
    const { conditionPlatform: condition, pathPlatform: output } = target;
    if (!condition || !output) continue;
    if (condition === "browser" && output === "node" || condition === "node" && output === "browser" || condition === "neutral" && output !== "neutral") {
      diagnostics.push({
        detail: `${condition} condition points to ${output} output`,
        exportPath: target.exportPath,
        kind: "condition-target-mismatch",
        platform: condition,
        target: target.target
      });
    }
  }
  return diagnostics;
}
function isRuntimeTarget(target) {
  return codeExtensions.some((ext) => target.target.endsWith(ext));
}
function isPortableTarget(target) {
  return target.conditionPlatform === "browser" || target.conditionPlatform === "neutral" || target.pathPlatform === "browser" || target.pathPlatform === "neutral" || !target.conditionPlatform && !target.pathPlatform;
}
function isNodeTarget(target) {
  return target.conditionPlatform === "node" || target.pathPlatform === "node";
}
function isNodeOnlyPackage(pkg, targets) {
  const runtimeTargets = targets.filter(isRuntimeTarget);
  const platformTargets = runtimeTargets.length > 0 ? runtimeTargets : targets;
  if (platformTargets.length === 0) return pkg.bin !== void 0;
  return platformTargets.some(isNodeTarget) && !platformTargets.some(isPortableTarget);
}
function readRootTsconfigTypes(pkgDir) {
  const configPath = path4.join(pkgDir, "tsconfig.json");
  if (!fs4.existsSync(configPath)) return [];
  const parsed = ts3.parseConfigFileTextToJson(configPath, fs4.readFileSync(configPath, "utf8"));
  const config2 = parsed.config;
  const types = config2?.compilerOptions?.types;
  return Array.isArray(types) ? types.filter((value) => typeof value === "string") : [];
}
function collectTsconfigDiagnostics(pkgDir, pkg, targets) {
  if (targets.length === 0) return [];
  if (isNodeOnlyPackage(pkg, targets)) return [];
  const types = readRootTsconfigTypes(pkgDir);
  return types.includes("node") ? [{
    detail: 'compilerOptions.types includes "node"',
    file: path4.join(pkgDir, "tsconfig.json"),
    kind: "tsconfig-node-types"
  }] : [];
}
function diagnosticKey(pkgDir, diagnostic) {
  return [
    diagnostic.kind,
    diagnostic.platform ?? "",
    diagnostic.target ?? "",
    diagnostic.exportPath ?? "",
    diagnostic.file ? relativePath3(pkgDir, diagnostic.file) : "",
    diagnostic.detail ?? ""
  ].join("\0");
}
function dedupeDiagnostics(pkgDir, diagnostics) {
  const seen = /* @__PURE__ */ new Set();
  const result = [];
  for (const diagnostic of diagnostics) {
    const key = diagnosticKey(pkgDir, diagnostic);
    if (seen.has(key)) continue;
    seen.add(key);
    result.push(diagnostic);
  }
  return result;
}
function renderDiagnostic(pkgDir, diagnostic) {
  switch (diagnostic.kind) {
    case "condition-target-mismatch": {
      return `Publint [platform]: ${diagnostic.detail} at ${diagnostic.exportPath} (${diagnostic.target})`;
    }
    case "node-builtin-import": {
      const file = relativePath3(pkgDir, diagnostic.file ?? "");
      return `Publint [platform]: ${diagnostic.platform} export ${diagnostic.target} imports Node builtin "${diagnostic.detail}" in ${file} (${diagnostic.exportPath})`;
    }
    case "node-ambient-type": {
      const file = relativePath3(pkgDir, diagnostic.file ?? "");
      return `Publint [platform]: ${diagnostic.platform} declaration ${diagnostic.target} exposes Node ambient "${diagnostic.detail}" in ${file} (${diagnostic.exportPath})`;
    }
    case "tsconfig-node-types": {
      return 'Publint [platform]: non-node package tsconfig.json should not include compilerOptions.types "node"';
    }
  }
}
function checkPlatform(pkgDir, pkg) {
  const result = emptyResult2();
  const targets = collectExportTargets(pkg.exports);
  const diagnostics = [...collectConditionTargetDiagnostics(targets)];
  for (const target of targets) {
    const platform = shouldScanForNodeUsage(target);
    if (!platform) continue;
    for (const file of resolveExportTargetFiles(pkgDir, target.target)) {
      diagnostics.push(...scanFileGraph(file, platform, target));
    }
  }
  diagnostics.push(...collectTsconfigDiagnostics(pkgDir, pkg, targets));
  for (const diagnostic of dedupeDiagnostics(pkgDir, diagnostics)) {
    console.error(chalk9.red(renderDiagnostic(pkgDir, diagnostic)));
    result.errors++;
  }
  return result;
}

// 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(chalk10.yellow('Publint [custom]: "files" field is missing'));
    result.warnings++;
  }
  if (Array.isArray(files) && !files.includes("README.md")) {
    files.push("README.md");
    console.warn(chalk10.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(chalk10.yellow('Publint [custom]: removed "src" from "files"'));
      result.modified = true;
    } else {
      console.warn(chalk10.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(chalk10.yellow('Publint [custom]: removed "source" entries from "exports"'));
      result.modified = true;
    } else {
      console.warn(chalk10.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" && !Object.hasOwn(dot, exportKey)) {
        dot[exportKey] = exportValue;
        console.warn(chalk10.yellow(`Publint [custom]: migrated "${field}" to "exports['.'].${exportKey}" (${fieldValue})`));
      }
    } else if (!pkg.exports) {
      pkg.exports = { ".": { [exportKey]: exportValue } };
      console.warn(chalk10.yellow(`Publint [custom]: migrated "${field}" to "exports" (.\u2192${fieldValue})`));
    }
    delete pkg[field];
    console.warn(chalk10.yellow(`Publint [custom]: removed deprecated "${field}" field`));
    result.modified = true;
  } else {
    console.warn(chalk10.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(chalk10.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(chalk10.yellow(`Publint [custom]: removed root-level "${field}" field`));
        result.modified = true;
      } else {
        console.warn(chalk10.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(chalk10.yellow('Publint [custom]: "resolutions" in use'));
    console.warn(chalk10.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(chalk10.yellow('Publint [custom]: renamed "import" to "default" in "exports" and ensured "types" siblings'));
    result.modified = true;
  } else {
    console.warn(chalk10.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(chalk10.yellow('Publint [custom]: removed redundant root "types" field (already defined in "exports")'));
    result.modified = true;
  } else {
    console.warn(chalk10.yellow('Publint [custom]: root "types" field is redundant when "exports" defines types (use --fix to remove)'));
  }
  result.warnings++;
  return result;
}
function customPubLint(pkgDir, 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("platform")) mergeResults(result, checkPlatform(pkgDir, pkg));
  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 glob2(patterns, {
    cwd: pkgDir,
    nodir: true,
    dot: false
  });
  const files = await Promise.all(
    matched.map(async (rel) => {
      const abs = path5.join(pkgDir, rel);
      let data = "";
      try {
        data = await fs5.readFile(abs, "utf8");
      } catch {
      }
      return { name: path5.join(pkgDir, rel), data };
    })
  );
  return files;
}
function logPublintMessage(message, pkg, formatMessage) {
  const formatted = `[${message.code}] ${formatMessage(message, pkg) ?? message.code}`;
  switch (message.type) {
    case "error": {
      console.error(chalk10.red(formatted));
      return;
    }
    case "warning": {
      console.warn(chalk10.yellow(formatted));
      return;
    }
    default: {
      console.log(chalk10.white(formatted));
    }
  }
}
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) {
    logPublintMessage(message, pkg, formatMessage);
  }
  return {
    errors: messages.filter((message) => message.type === "error").length,
    warnings: messages.filter((message) => message.type !== "error").length
  };
}
var packagePublintDetailed = async ({
  exclude = /* @__PURE__ */ new Set(),
  fix = false,
  pack = true,
  pkgDir: pkgDirParam,
  strict = isStrictMode(),
  verbose: _verbose = false
} = {}) => {
  const pkgDir = path5.resolve(pkgDirParam ?? INIT_CWD());
  const sortedPkg = sortPackageJson(await fs5.readFile(`${pkgDir}/package.json`, "utf8"));
  await fs5.writeFile(`${pkgDir}/package.json`, sortedPkg);
  const pkg = JSON.parse(await fs5.readFile(`${pkgDir}/package.json`, "utf8"));
  const effectiveExclude = pkg.private ? /* @__PURE__ */ new Set([...exclude, ...PUBLISH_ONLY_CHECKS]) : exclude;
  console.log(chalk10.green(`Publint: ${String(pkg.name)}${pkg.private ? chalk10.gray(" (private)") : ""}`));
  console.log(chalk10.gray(pkgDir));
  let libraryErrors = 0;
  let libraryWarnings = 0;
  if (!effectiveExclude.has("publint")) {
    const library = await runPublintLibrary(pkgDir, pkg, strict, pack);
    libraryErrors = library.errors;
    libraryWarnings = library.warnings;
  }
  const [errorCount, warningCount, modified] = customPubLint(pkgDir, pkg, fix, effectiveExclude);
  if (modified) {
    const sorted = sortPackageJson(JSON.stringify(pkg, null, 2));
    await fs5.writeFile(`${pkgDir}/package.json`, sorted);
  }
  const compileTargets = effectiveExclude.has("compileTargets") ? { errors: 0, warnings: 0 } : checkCompileTargets(pkgDir, fix);
  return {
    errors: libraryErrors + errorCount + compileTargets.errors,
    warnings: libraryWarnings + warningCount + compileTargets.warnings
  };
};
var packagePublint = async (params = {}) => {
  const result = await packagePublintDetailed(params);
  return result.errors + (isStrictMode() ? result.warnings : 0);
};

// src/actions/publint.ts
function resolveExclude(publintConfig, cliExclude, cliInclude) {
  const hasExclude = (publintConfig.exclude?.length ?? 0) > 0 || (cliExclude?.length ?? 0) > 0;
  const hasInclude = (publintConfig.include?.length ?? 0) > 0 || (cliInclude?.length ?? 0) > 0;
  if (hasExclude && hasInclude) {
    console.error(chalk11.red("Publint: --include and --exclude cannot be used together"));
    return void 0;
  }
  if (hasInclude) {
    const include = /* @__PURE__ */ new Set([
      ...publintConfig.include ?? [],
      ...cliInclude ?? []
    ]);
    return new Set(ALL_PUBLINT_CHECKS.filter((c) => !include.has(c)));
  }
  return /* @__PURE__ */ new Set([
    ...publintConfig.exclude ?? [],
    ...cliExclude ?? []
  ]);
}
function normalizePublintConfig(value) {
  if (typeof value === "object") return value;
  return {};
}
async function loadPublintOptions() {
  const config2 = await loadConfig();
  const publintConfig = normalizePublintConfig(config2.commands?.publint ?? config2.publint);
  const exclude = resolveExclude(publintConfig) ?? /* @__PURE__ */ new Set();
  return { exclude, pack: publintConfig.pack ?? true };
}

// src/bin/package/build.ts
var verbose = process.argv.includes("-v") || process.argv.includes("--verbose");
var packageBuild = async () => {
  const compileResult = await packageCompile({ verbose });
  if (compileResult !== 0) return compileResult;
  const { exclude, pack } = await loadPublintOptions();
  return await packagePublint({
    exclude,
    pack,
    pkgDir: cwd5(),
    verbose
  });
};
try {
  const value = await packageBuild();
  if (value > 0) {
    process.exit(value);
  }
} catch (reason) {
  console.error(chalk12.red(reason));
  process.exit(-1);
}
//# sourceMappingURL=build.mjs.map
