// src/index.ts
import fs2 from "fs";
import path2 from "path";
import { pathToFileURL } from "url";
import {
  build,
  context
} from "esbuild";
import { loadTsConfig } from "load-tsconfig";

// src/utils.ts
import fs from "fs";
import path from "path";
import { createRequire } from "module";
var getPkgType = () => {
  try {
    const pkg = JSON.parse(
      fs.readFileSync(path.resolve("package.json"), "utf-8")
    );
    return pkg.type;
  } catch (error) {
  }
};
function guessFormat(inputFile) {
  if (!usingDynamicImport)
    return "cjs";
  const ext = path.extname(inputFile);
  const type = getPkgType();
  if (ext === ".js") {
    return type === "module" ? "esm" : "cjs";
  } else if (ext === ".ts" || ext === ".mts") {
    return "esm";
  } else if (ext === ".mjs") {
    return "esm";
  }
  return "cjs";
}
var usingDynamicImport = typeof jest === "undefined";
var dynamicImport = async (id, { format }) => {
  const fn = format === "esm" ? (file) => import(file) : true ? createRequire(import.meta.url) : __require;
  return fn(id);
};
var getRandomId = () => {
  return Math.random().toString(36).substring(2, 15);
};

// src/index.ts
var DIRNAME_VAR_NAME = "__injected_dirname__";
var FILENAME_VAR_NAME = "__injected_filename__";
var IMPORT_META_URL_VAR_NAME = "__injected_import_meta_url__";
var JS_EXT_RE = /\.([mc]?[tj]s|[tj]sx)$/;
var PATH_NODE_MODULES_RE = /[\/\\]node_modules[\/\\]/;
function inferLoader(ext) {
  if (ext === ".mjs" || ext === ".cjs")
    return "js";
  if (ext === ".mts" || ext === ".cts")
    return "ts";
  return ext.slice(1);
}
var defaultReadFile = (filepath) => fs2.readFileSync(filepath, "utf-8");
var defaultGetOutputFile = (filepath, format) => filepath.replace(
  JS_EXT_RE,
  `.bundled_${getRandomId()}.${format === "esm" ? "mjs" : "cjs"}`
);
var tsconfigPathsToRegExp = (paths) => {
  return Object.keys(paths || {}).map((key) => {
    return new RegExp(`^${key.replace(/\*/, ".*")}$`);
  });
};
var match = (id, patterns) => {
  if (!patterns)
    return false;
  return patterns.some((p) => {
    if (p instanceof RegExp) {
      return p.test(id);
    }
    return id === p || id.startsWith(p + "/");
  });
};
var externalPlugin = ({
  external,
  notExternal,
  externalNodeModules = true
} = {}) => {
  return {
    name: "bundle-require:external",
    setup(ctx) {
      ctx.onResolve({ filter: /.*/ }, async (args) => {
        if (match(args.path, external)) {
          return {
            external: true
          };
        }
        if (match(args.path, notExternal)) {
          return;
        }
        if (externalNodeModules && args.path.match(PATH_NODE_MODULES_RE)) {
          const resolved = args.path[0] === "." ? path2.resolve(args.resolveDir, args.path) : args.path;
          return {
            path: pathToFileURL(resolved).toString(),
            external: true
          };
        }
        if (args.path[0] === "." || path2.isAbsolute(args.path)) {
          return;
        }
        return {
          external: true
        };
      });
    }
  };
};
var injectFileScopePlugin = ({
  readFile = defaultReadFile
} = {}) => {
  return {
    name: "bundle-require:inject-file-scope",
    setup(ctx) {
      ctx.initialOptions.define = {
        ...ctx.initialOptions.define,
        __dirname: DIRNAME_VAR_NAME,
        __filename: FILENAME_VAR_NAME,
        "import.meta.url": IMPORT_META_URL_VAR_NAME
      };
      ctx.onLoad({ filter: JS_EXT_RE }, (args) => {
        const contents = readFile(args.path);
        const injectLines = [
          `const ${FILENAME_VAR_NAME} = ${JSON.stringify(args.path)};`,
          `const ${DIRNAME_VAR_NAME} = ${JSON.stringify(
            path2.dirname(args.path)
          )};`,
          `const ${IMPORT_META_URL_VAR_NAME} = ${JSON.stringify(
            pathToFileURL(args.path).href
          )};`
        ];
        return {
          contents: injectLines.join("") + contents,
          loader: inferLoader(path2.extname(args.path))
        };
      });
    }
  };
};
function bundleRequire(options) {
  return new Promise((resolve, reject) => {
    var _a, _b, _c, _d, _e;
    if (!JS_EXT_RE.test(options.filepath)) {
      throw new Error(`${options.filepath} is not a valid JS file`);
    }
    const preserveTemporaryFile = (_a = options.preserveTemporaryFile) != null ? _a : !!process.env.BUNDLE_REQUIRE_PRESERVE;
    const cwd = options.cwd || process.cwd();
    const format = (_b = options.format) != null ? _b : guessFormat(options.filepath);
    const tsconfig = options.tsconfig === false ? void 0 : typeof options.tsconfig === "string" || !options.tsconfig ? loadTsConfig(cwd, options.tsconfig) : { data: options.tsconfig, path: void 0 };
    const resolvePaths = tsconfigPathsToRegExp(
      ((_c = tsconfig == null ? void 0 : tsconfig.data.compilerOptions) == null ? void 0 : _c.paths) || {}
    );
    const extractResult = async (result) => {
      if (!result.outputFiles) {
        throw new Error(`[bundle-require] no output files`);
      }
      const { text } = result.outputFiles[0];
      const getOutputFile = options.getOutputFile || defaultGetOutputFile;
      const outfile = getOutputFile(options.filepath, format);
      await fs2.promises.writeFile(outfile, text, "utf8");
      let mod;
      const req = options.require || dynamicImport;
      try {
        mod = await req(
          format === "esm" ? pathToFileURL(outfile).href : outfile,
          { format }
        );
      } finally {
        if (!preserveTemporaryFile) {
          await fs2.promises.unlink(outfile);
        }
      }
      return {
        mod,
        dependencies: result.metafile ? Object.keys(result.metafile.inputs) : []
      };
    };
    const { watch: watchMode, ...restEsbuildOptions } = options.esbuildOptions || {};
    const esbuildOptions = {
      ...restEsbuildOptions,
      entryPoints: [options.filepath],
      absWorkingDir: cwd,
      outfile: "out.js",
      format,
      platform: "node",
      sourcemap: "inline",
      bundle: true,
      metafile: true,
      write: false,
      ...(tsconfig == null ? void 0 : tsconfig.path) ? { tsconfig: tsconfig.path } : { tsconfigRaw: (tsconfig == null ? void 0 : tsconfig.data) || {} },
      plugins: [
        ...((_d = options.esbuildOptions) == null ? void 0 : _d.plugins) || [],
        externalPlugin({
          external: options.external,
          notExternal: [...options.notExternal || [], ...resolvePaths],
          externalNodeModules: (_e = options.externalNodeModules) != null ? _e : !options.filepath.match(PATH_NODE_MODULES_RE)
        }),
        injectFileScopePlugin({
          readFile: options.readFile
        })
      ]
    };
    const run = async () => {
      if (!(watchMode || options.onRebuild)) {
        const result = await build(esbuildOptions);
        resolve(await extractResult(result));
      } else {
        const rebuildCallback = typeof watchMode === "object" && typeof watchMode.onRebuild === "function" ? watchMode.onRebuild : async (error, result) => {
          var _a2, _b2;
          if (error) {
            (_a2 = options.onRebuild) == null ? void 0 : _a2.call(options, { err: error });
          }
          if (result) {
            (_b2 = options.onRebuild) == null ? void 0 : _b2.call(options, await extractResult(result));
          }
        };
        const onRebuildPlugin = () => {
          return {
            name: "bundle-require:on-rebuild",
            setup(ctx2) {
              let count = 0;
              ctx2.onEnd(async (result) => {
                if (count++ === 0) {
                  if (result.errors.length === 0)
                    resolve(await extractResult(result));
                } else {
                  if (result.errors.length > 0) {
                    return rebuildCallback(
                      { errors: result.errors, warnings: result.warnings },
                      null
                    );
                  }
                  if (result) {
                    rebuildCallback(null, result);
                  }
                }
              });
            }
          };
        };
        esbuildOptions.plugins.push(onRebuildPlugin());
        const ctx = await context(esbuildOptions);
        await ctx.watch();
      }
    };
    run().catch(reject);
  });
}
export {
  JS_EXT_RE,
  bundleRequire,
  dynamicImport,
  externalPlugin,
  injectFileScopePlugin,
  loadTsConfig,
  match,
  tsconfigPathsToRegExp
};
