// src/actions/package/expectedCompileOutputs.ts
import fs from "node:fs";
import path2 from "node:path";
import { cosmiconfig as cosmiconfig2 } from "cosmiconfig";
import { TypeScriptLoader as TypeScriptLoader2 } from "cosmiconfig-typescript-loader";

// 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/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/actions/package/compile/inputs.ts
import chalk2 from "chalk";
import { glob } from "glob";
var getAllInputs = (srcDir, isVerbose = false) => {
  return glob.sync(`${srcDir}/**/*.{ts,tsx,mts,cts}`, { posix: true }).map((file) => {
    const result = file.slice(Math.max(0, srcDir.length + 1));
    if (isVerbose) {
      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, shouldExcludeSpecAndStories = true, isVerbose = false) => {
  let entries;
  switch (entryMode) {
    case "platform": {
      entries = ["index-node.ts", "index-browser.ts"];
      break;
    }
    case "all": {
      entries = (shouldExcludeSpecAndStories ? 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 (isVerbose) console.log(`buildEntries [${entryMode}] ${entries.length}`);
  return entries;
};

// src/actions/package/compile/entryOutputName.ts
import path from "node:path";
var platformSourceSegments = /* @__PURE__ */ new Set(["browser", "neutral", "node"]);
var toPosixPath = (value) => value.split(path.sep).join("/");
var normalizeEntryPath = (entry) => toPosixPath(entry).replace(/^\.?\//u, "");
var customEntryOutputName = (entry) => {
  const parsed = path.posix.parse(normalizeEntryPath(entry));
  const withoutExtension = path.posix.join(parsed.dir, parsed.name);
  const segments = withoutExtension.split("/");
  return segments.length > 1 && platformSourceSegments.has(segments[0]) ? segments.slice(1).join("/") : withoutExtension;
};
var entryOutputBasename = (entry, entryMode) => {
  if (entryMode === "custom") return customEntryOutputName(entry);
  return path.posix.parse(normalizeEntryPath(entry)).name;
};

// src/actions/package/compile/resolveCompilePlatforms.ts
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 isDeprecatedEmptyObject = Object.keys(value).length === 0;
  const entries = resolvePlatformRecord(value);
  return {
    deprecatedEmptyObject: isDeprecatedEmptyObject,
    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 isAnyBuild = node.state === "build" || browser.state === "build" || neutral.state === "build";
  const neutralEntries = neutral.state === "build" ? neutral.entries : !isAnyBuild && 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 : {}
  };
};

// src/actions/package/expectedCompileOutputs.ts
var CONFIG_FILE_NAMES = [
  "xy.config.ts",
  "xy.config.mts",
  "xy.config.cts",
  "xy.config.js",
  "xy.config.mjs",
  "xy.config.cjs"
];
var PRIMARY_INDEX_BASENAMES = /* @__PURE__ */ new Set([
  "index",
  "index-browser",
  "index-neutral",
  "index-node",
  "index.browser",
  "index.node",
  "index.neutral",
  "browser-index",
  "neutral-index",
  "node-index"
]);
function ensureExportsPath(value) {
  return value.startsWith("./") ? value : `./${value}`;
}
function isPrimaryIndexBasename(basename) {
  return PRIMARY_INDEX_BASENAMES.has(basename);
}
function getRootOutDir(options) {
  return options.outDir ?? options.outdir ?? "dist";
}
function pairedDeclarationFile(runtimeFile) {
  const candidates = runtimeFile.endsWith(".mjs") ? [runtimeFile.replace(/\.mjs$/, ".d.mts"), runtimeFile.replace(/\.mjs$/, ".d.ts")] : runtimeFile.endsWith(".cjs") ? [runtimeFile.replace(/\.cjs$/, ".d.cts"), runtimeFile.replace(/\.cjs$/, ".d.ts")] : runtimeFile.endsWith(".js") ? [runtimeFile.replace(/\.js$/, ".d.ts")] : [];
  return candidates.find((candidate) => fs.existsSync(candidate) && fs.statSync(candidate).isFile());
}
function relativeExportsTarget(pkgDir, filePath) {
  return ensureExportsPath(toPosixPath(path2.relative(pkgDir, filePath)));
}
async function loadMergedWorkspaceConfig(pkgDir) {
  const root = await loadConfig();
  const explorer = cosmiconfig2("xy", { cache: true, loaders: { ".ts": TypeScriptLoader2() } });
  const result = await explorer.search(pkgDir);
  if (result?.config === void 0) return root;
  return deepMerge(root, result.config);
}
function hasWorkspaceConfig(pkgDir) {
  return CONFIG_FILE_NAMES.some((name) => fs.existsSync(path2.join(pkgDir, name)));
}
function outputForEntry(pkgDir, platform, rootOutDir, entry, entryMode) {
  const basename = entryOutputBasename(entry, entryMode ?? "single");
  const runtimeAbs = path2.join(pkgDir, rootOutDir, platform, `${basename}.mjs`);
  if (!fs.existsSync(runtimeAbs)) return void 0;
  const runtime = relativeExportsTarget(pkgDir, runtimeAbs);
  const declarationFile = pairedDeclarationFile(runtimeAbs);
  return {
    entry,
    isPrimaryIndex: false,
    platform,
    runtime,
    types: declarationFile === void 0 ? void 0 : relativeExportsTarget(pkgDir, declarationFile)
  };
}
function collectOutputsForPlatform(pkgDir, platform, entries, compile) {
  const outputs = [];
  const entryMode = compile?.entryMode ?? "single";
  for (const [srcDir, options] of Object.entries(entries)) {
    const rootOutDir = getRootOutDir(options);
    const builtEntries = buildEntries(srcDir, entryMode, options, true, false);
    for (const entry of builtEntries) {
      const output = outputForEntry(pkgDir, platform, rootOutDir, entry, entryMode);
      if (output !== void 0) outputs.push(output);
    }
  }
  const byBasename = /* @__PURE__ */ new Map();
  for (const output of outputs) {
    const basename = path2.posix.parse(output.runtime).name;
    const group = byBasename.get(basename) ?? [];
    group.push(output);
    byBasename.set(basename, group);
  }
  for (const output of outputs) {
    const basename = path2.posix.parse(output.runtime).name;
    const group = byBasename.get(basename) ?? [];
    output.isPrimaryIndex = isPrimaryIndexBasename(basename) || group.length === 1;
  }
  return outputs;
}
async function collectExpectedCompileOutputs(pkgDir) {
  if (!hasWorkspaceConfig(pkgDir)) return [];
  const config = await loadMergedWorkspaceConfig(pkgDir);
  const compile = config.compile;
  if (compile === void 0) return [];
  const platforms = resolveCompilePlatforms(compile);
  return [
    ...collectOutputsForPlatform(pkgDir, "node", platforms.node, compile),
    ...collectOutputsForPlatform(pkgDir, "browser", platforms.browser, compile),
    ...collectOutputsForPlatform(pkgDir, "neutral", platforms.neutral, compile)
  ];
}
export {
  collectExpectedCompileOutputs
};
//# sourceMappingURL=expectedCompileOutputs.mjs.map
