"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var project_exports = {};
__export(project_exports, {
  BUILD_INFO_LOCATION: () => BUILD_INFO_LOCATION,
  COMPILED_CONFIG_PATH: () => COMPILED_CONFIG_PATH,
  Project: () => Project
});
module.exports = __toCommonJS(project_exports);
var import_esbuild = require("esbuild");
var import_promises = require("node:fs/promises");
var import_node_os = require("node:os");
var import_node_path = require("node:path");
var import_errors = require("../util/errors.js");
var import_package = require("../util/package.js");
/**
 * @license
 * Copyright 2022-2026 Greg Lauckhart <greg@lauckhart.com>
 * SPDX-License-Identifier: Apache-2.0
 */
const BUILD_INFO_LOCATION = "build/info.json";
const COMPILED_CONFIG_PATH = "build/build.config.js";
class Project {
  pkg;
  #config;
  #configured;
  constructor(source = ".") {
    if (typeof source === "string") {
      this.pkg = new import_package.Package({ path: source });
    } else {
      this.pkg = source;
    }
    if (!this.pkg.hasSrc) {
      throw new Error(
        `Found package ${this.pkg.json.name} but src directory is not present or not referenced in tsconfig.json`
      );
    }
  }
  async buildSource(format) {
    await this.#build(format, "src", `dist/${format}`);
    await this.#configureFormat("dist", format, true);
  }
  async buildTests(format) {
    if (this.pkg.hasDirectory("test")) {
      await this.#build(format, "test", `build/${format}/test`);
    }
    const src = (0, import_node_path.join)("dist", format);
    const dest = (0, import_node_path.join)("build", format, "src");
    try {
      const destPath = this.pkg.resolve(dest);
      await (0, import_promises.mkdir)((0, import_node_path.dirname)(destPath), { recursive: true });
      await (0, import_errors.ignoreError)("EEXIST", async () => await (0, import_promises.symlink)((0, import_node_path.join)("..", "..", src), destPath));
    } catch (e) {
      if (e.code === "EPERM" && (0, import_node_os.platform)() === "win32") {
        await (0, import_promises.cp)(this.pkg.resolve(src), this.pkg.resolve(dest), {
          recursive: true,
          force: true
        });
      } else {
        throw e;
      }
    }
    await this.#configureFormat("build", format, false);
  }
  async clean() {
    for (const dir of ["build", "dist"]) {
      await (0, import_promises.rm)(this.pkg.resolve(dir), { recursive: true, force: true });
    }
  }
  get hasDeclarations() {
    return this.pkg.hasDirectory("build/types");
  }
  async recordBuildInfo(info) {
    await (0, import_promises.mkdir)(this.pkg.resolve("build"), { recursive: true });
    info.timestamp = (/* @__PURE__ */ new Date()).toISOString();
    await (0, import_promises.writeFile)(this.pkg.resolve(BUILD_INFO_LOCATION), JSON.stringify(info, void 0, 4));
  }
  async configure() {
    if (this.#configured) {
      return this.#config;
    }
    if (!this.pkg.hasConfig) {
      return {};
    }
    const configPath = this.pkg.resolve(import_package.CONFIG_PATH);
    const outfile = this.pkg.resolve(COMPILED_CONFIG_PATH).replaceAll("\\", "/");
    await (0, import_esbuild.build)({
      entryPoints: [configPath],
      outfile,
      sourcemap: true
    });
    this.#config = await import(`file://${outfile}`);
    this.#configured = true;
    if (this.#config?.startup) {
      await this.#config?.startup({
        project: this
      });
    }
    return this.#config;
  }
  /**
   * Copy files into dist for supported formats.
   */
  async copyToDist(source, dest) {
    const formats = Array();
    if (this.pkg.supportsEsm) {
      formats.push("esm");
    }
    if (this.pkg.supportsCjs) {
      formats.push("cjs");
    }
    for (const format of formats) {
      await (0, import_promises.cp)(this.pkg.resolve(source), this.pkg.resolve((0, import_node_path.join)("dist", format, dest)), {
        recursive: true,
        force: true
      });
    }
  }
  async #build(format, indir, outdir) {
    const entryPoints = await this.#targetsOf(indir, outdir, "ts", "js");
    const configPath = this.pkg.resolve(import_package.CONFIG_PATH);
    for (const entry of entryPoints) {
      if (entry.in === configPath) {
        continue;
      }
      entry.out = entry.out.replace(/\.[jt]s$/, "");
    }
    await (0, import_esbuild.build)({
      entryPoints,
      outdir: this.pkg.path,
      format,
      sourcemap: true,
      sourcesContent: false,
      absWorkingDir: (0, import_node_path.dirname)(this.pkg.resolve(indir)),
      // This is necessary to downlevel "using"
      target: "es2022",
      logOverride: {
        "direct-eval": "silent"
      }
    });
    for (const entry of await this.#targetsOf(indir, outdir, "d.ts", "cjs", "mjs", "d.cts", "d.mts")) {
      await (0, import_promises.cp)(entry.in, entry.out);
    }
  }
  async #configureFormat(dir, format, isDist) {
    let { imports } = this.pkg.json;
    if (isDist && typeof imports === "object") {
      imports = { ...imports };
      for (const key in imports) {
        const value = imports[key];
        if (typeof value === "string") {
          imports[key] = value.replace(/^\.\/src\//, "./");
        }
      }
    }
    const path = this.pkg.resolve(`${dir}/${format}/package.json`);
    const json = {
      type: format === "cjs" ? "commonjs" : "module",
      imports
    };
    await (0, import_promises.writeFile)(path, JSON.stringify(json, void 0, 4));
  }
  async #targetsOf(indir, outdir, ...extensions) {
    const inputPrefixLength = this.pkg.resolve(indir).length + 1;
    outdir = this.pkg.resolve(outdir).replace(/\\/g, "/");
    return (await this.pkg.glob(extensions.map((ext) => `${indir}/**/*.${ext}`))).map((file) => ({
      in: file,
      out: `${outdir}/${file.slice(inputPrefixLength)}`
    }));
  }
}
//# sourceMappingURL=project.js.map
