
import { A as openGitHubIssueWithCrashReport, D as ConfigValidationError, E as ConfigError, M as shouldReportCrash, N as loadPackageJson, O as JobError, T as getLogs, i as initConfigs, j as printCrashReport, k as logCrashReport, n as buildGraph, r as getSpec, s as generateClientBundle, t as parseOpenApiSpec, u as toCase, w as postprocessOutput, y as getClientPlugin } from "./openApi-B6J9qPwL.mjs";
import "@hey-api/codegen-core";
import colors from "ansi-colors";
import colorSupport from "color-support";
import fs from "node:fs";
import path from "node:path";
import { $RefParser } from "@hey-api/json-schema-ref-parser";

//#region src/config/engine.ts
const checkNodeVersion = () => {
	if (typeof Bun !== "undefined") {
		const [major] = Bun.version.split(".").map(Number);
		if (major < 1) throw new ConfigError(`Unsupported Bun version ${Bun.version}. Please use Bun 1.0.0 or newer.`);
	} else if (typeof process !== "undefined" && process.versions?.node) {
		const [major] = process.versions.node.split(".").map(Number);
		if (major < 20) throw new ConfigError(`Unsupported Node version ${process.versions.node}. Please use Node 20 or newer.`);
	}
};

//#endregion
//#region src/ir/intents.ts
var IntentContext = class {
	spec;
	constructor(spec) {
		this.spec = spec;
	}
	getOperation(path$1, method) {
		const paths = this.spec.paths;
		if (!paths) return;
		return paths[path$1]?.[method];
	}
	setExample(operation, example) {
		const source = this.getOperation(operation.path, operation.method);
		if (!source) return;
		source["x-codeSamples"] ||= [];
		source["x-codeSamples"].push(example);
	}
};

//#endregion
//#region src/generate/output.ts
const generateOutput = async ({ context }) => {
	const outputPath = path.resolve(context.config.output.path);
	if (context.config.output.clean) {
		if (fs.existsSync(outputPath)) fs.rmSync(outputPath, {
			force: true,
			recursive: true
		});
	}
	const client = getClientPlugin(context.config);
	if ("bundle" in client.config && client.config.bundle && !context.config.dryRun) context.config._FRAGILE_CLIENT_BUNDLE_RENAMED = generateClientBundle({
		meta: { importFileExtension: context.config.output.importFileExtension },
		outputPath,
		plugin: client,
		project: context.gen
	});
	for (const plugin of context.registerPlugins()) await plugin.run();
	context.gen.plan();
	const ctx = new IntentContext(context.spec);
	for (const intent of context.intents) await intent.run(ctx);
	for (const file of context.gen.render()) {
		const filePath = path.resolve(outputPath, file.path);
		const dir = path.dirname(filePath);
		if (!context.config.dryRun) {
			fs.mkdirSync(dir, { recursive: true });
			fs.writeFileSync(filePath, file.content, { encoding: "utf8" });
		}
	}
	const { source } = context.config.output;
	if (source.enabled) {
		const sourcePath = source.path === null ? void 0 : path.resolve(outputPath, source.path);
		if (!context.config.dryRun && sourcePath && sourcePath !== outputPath) fs.mkdirSync(sourcePath, { recursive: true });
		const serialized = await source.serialize(context.spec);
		if (!context.config.dryRun && sourcePath) fs.writeFileSync(path.resolve(sourcePath, `${source.fileName}.${source.extension}`), serialized, { encoding: "utf8" });
		if (source.callback) await source.callback(serialized);
	}
};

//#endregion
//#region src/openApi/shared/utils/patch.ts
const patchOpenApiSpec = ({ patchOptions, spec: _spec }) => {
	if (!patchOptions) return;
	const spec = _spec;
	if ("swagger" in spec) {
		if (patchOptions.version && spec.swagger) spec.swagger = typeof patchOptions.version === "string" ? patchOptions.version : patchOptions.version(spec.swagger);
		if (patchOptions.meta && spec.info) patchOptions.meta(spec.info);
		if (patchOptions.schemas && spec.definitions) for (const key in patchOptions.schemas) {
			const schema = spec.definitions[key];
			if (!schema || typeof schema !== "object") continue;
			const patchFn = patchOptions.schemas[key];
			patchFn(schema);
		}
		if (patchOptions.operations && spec.paths) for (const key in patchOptions.operations) {
			const [method, path$1] = key.split(" ");
			if (!method || !path$1) continue;
			const pathItem = spec.paths[path$1];
			if (!pathItem) continue;
			const operation = pathItem[method.toLocaleLowerCase()] || pathItem[method.toLocaleUpperCase()];
			if (!operation || typeof operation !== "object") continue;
			const patchFn = patchOptions.operations[key];
			patchFn(operation);
		}
		return;
	}
	if (patchOptions.version && spec.openapi) spec.openapi = typeof patchOptions.version === "string" ? patchOptions.version : patchOptions.version(spec.openapi);
	if (patchOptions.meta && spec.info) patchOptions.meta(spec.info);
	if (spec.components) {
		if (patchOptions.schemas && spec.components.schemas) for (const key in patchOptions.schemas) {
			const schema = spec.components.schemas[key];
			if (!schema || typeof schema !== "object") continue;
			const patchFn = patchOptions.schemas[key];
			patchFn(schema);
		}
		if (patchOptions.parameters && spec.components.parameters) for (const key in patchOptions.parameters) {
			const schema = spec.components.parameters[key];
			if (!schema || typeof schema !== "object") continue;
			const patchFn = patchOptions.parameters[key];
			patchFn(schema);
		}
		if (patchOptions.requestBodies && spec.components.requestBodies) for (const key in patchOptions.requestBodies) {
			const schema = spec.components.requestBodies[key];
			if (!schema || typeof schema !== "object") continue;
			const patchFn = patchOptions.requestBodies[key];
			patchFn(schema);
		}
		if (patchOptions.responses && spec.components.responses) for (const key in patchOptions.responses) {
			const schema = spec.components.responses[key];
			if (!schema || typeof schema !== "object") continue;
			const patchFn = patchOptions.responses[key];
			patchFn(schema);
		}
	}
	if (patchOptions.operations && spec.paths) for (const key in patchOptions.operations) {
		const [method, path$1] = key.split(" ");
		if (!method || !path$1) continue;
		const pathItem = spec.paths[path$1];
		if (!pathItem) continue;
		const operation = pathItem[method.toLocaleLowerCase()] || pathItem[method.toLocaleUpperCase()];
		if (!operation || typeof operation !== "object") continue;
		const patchFn = patchOptions.operations[key];
		patchFn(operation);
	}
};

//#endregion
//#region src/createClient.ts
const compileInputPath = (input) => {
	const result = {
		...input,
		path: ""
	};
	if (input.path && (typeof input.path !== "string" || input.registry !== "hey-api")) {
		result.path = input.path;
		return result;
	}
	const [basePath, baseQuery] = input.path.split("?");
	const queryPath = (baseQuery || "").split("&").map((part) => part.split("="));
	let path$1 = basePath || "";
	if (path$1.endsWith("/")) path$1 = path$1.slice(0, path$1.length - 1);
	const [, pathUrl] = path$1.split("://");
	const [baseUrl, organization, project] = (pathUrl || "").split("/");
	result.organization = organization || input.organization;
	result.project = project || input.project;
	const queryParams = [];
	const kApiKey = "api_key";
	result.api_key = queryPath.find(([key]) => key === kApiKey)?.[1] || input.api_key || process.env.HEY_API_TOKEN;
	if (result.api_key) queryParams.push(`${kApiKey}=${result.api_key}`);
	const kBranch = "branch";
	result.branch = queryPath.find(([key]) => key === kBranch)?.[1] || input.branch;
	if (result.branch) queryParams.push(`${kBranch}=${result.branch}`);
	const kCommitSha = "commit_sha";
	result.commit_sha = queryPath.find(([key]) => key === kCommitSha)?.[1] || input.commit_sha;
	if (result.commit_sha) queryParams.push(`${kCommitSha}=${result.commit_sha}`);
	const kTags = "tags";
	result.tags = queryPath.find(([key]) => key === kTags)?.[1]?.split(",") || input.tags;
	if (result.tags?.length) queryParams.push(`${kTags}=${result.tags.join(",")}`);
	const kVersion = "version";
	result.version = queryPath.find(([key]) => key === kVersion)?.[1] || input.version;
	if (result.version) queryParams.push(`${kVersion}=${result.version}`);
	if (!result.organization) throw new Error("missing organization - from which Hey API Platform organization do you want to generate your output?");
	if (!result.project) throw new Error("missing project - from which Hey API Platform project do you want to generate your output?");
	const query = queryParams.join("&");
	const platformUrl = baseUrl || "get.heyapi.dev";
	const isLocalhost = platformUrl.startsWith("localhost");
	const platformUrlWithProtocol = [isLocalhost ? "http" : "https", platformUrl].join("://");
	const compiledPath = isLocalhost ? [
		platformUrlWithProtocol,
		"v1",
		"get",
		result.organization,
		result.project
	].join("/") : [
		platformUrlWithProtocol,
		result.organization,
		result.project
	].join("/");
	result.path = query ? `${compiledPath}?${query}` : compiledPath;
	return result;
};
const logInputPaths = (inputPaths, jobIndex) => {
	const lines = [];
	const jobPrefix = colors.gray(`[Job ${jobIndex + 1}] `);
	const count = inputPaths.length;
	const baseString = colors.cyan(`Generating from ${count} ${count === 1 ? "input" : "inputs"}:`);
	lines.push(`${jobPrefix}⏳ ${baseString}`);
	inputPaths.forEach((inputPath, index) => {
		const itemPrefixStr = `  [${index + 1}] `;
		const itemPrefix = colors.cyan(itemPrefixStr);
		const detailIndent = " ".repeat(itemPrefixStr.length);
		if (typeof inputPath.path !== "string") {
			lines.push(`${jobPrefix}${itemPrefix}raw OpenAPI specification`);
			return;
		}
		switch (inputPath.registry) {
			case "hey-api": {
				const baseInput = [inputPath.organization, inputPath.project].filter(Boolean).join("/");
				lines.push(`${jobPrefix}${itemPrefix}${baseInput}`);
				if (inputPath.branch) lines.push(`${jobPrefix}${detailIndent}${colors.gray("branch:")} ${colors.green(inputPath.branch)}`);
				if (inputPath.commit_sha) lines.push(`${jobPrefix}${detailIndent}${colors.gray("commit:")} ${colors.green(inputPath.commit_sha)}`);
				if (inputPath.tags?.length) lines.push(`${jobPrefix}${detailIndent}${colors.gray("tags:")} ${colors.green(inputPath.tags.join(", "))}`);
				if (inputPath.version) lines.push(`${jobPrefix}${detailIndent}${colors.gray("version:")} ${colors.green(inputPath.version)}`);
				lines.push(`${jobPrefix}${detailIndent}${colors.gray("registry:")} ${colors.green("Hey API")}`);
				break;
			}
			case "readme": {
				const baseInput = [inputPath.organization, inputPath.project].filter(Boolean).join("/");
				if (!baseInput) lines.push(`${jobPrefix}${itemPrefix}${inputPath.path}`);
				else lines.push(`${jobPrefix}${itemPrefix}${baseInput}`);
				if (inputPath.uuid) lines.push(`${jobPrefix}${detailIndent}${colors.gray("uuid:")} ${colors.green(inputPath.uuid)}`);
				lines.push(`${jobPrefix}${detailIndent}${colors.gray("registry:")} ${colors.green("ReadMe")}`);
				break;
			}
			case "scalar": {
				const baseInput = [inputPath.organization, inputPath.project].filter(Boolean).join("/");
				lines.push(`${jobPrefix}${itemPrefix}${baseInput}`);
				lines.push(`${jobPrefix}${detailIndent}${colors.gray("registry:")} ${colors.green("Scalar")}`);
				break;
			}
			default:
				lines.push(`${jobPrefix}${itemPrefix}${inputPath.path}`);
				break;
		}
	});
	for (const line of lines) console.log(line);
};
const createClient$1 = async ({ config, dependencies, jobIndex, logger, watches: _watches }) => {
	const watches = _watches || Array.from({ length: config.input.length }, () => ({ headers: new Headers() }));
	const inputPaths = config.input.map((input) => compileInputPath(input));
	if (config.logs.level !== "silent" && !_watches) logInputPaths(inputPaths, jobIndex);
	const getSpecData = async (input, index) => {
		const eventSpec = logger.timeEvent("spec");
		const { arrayBuffer, error, resolvedInput, response } = await getSpec({
			fetchOptions: input.fetch,
			inputPath: inputPaths[index].path,
			timeout: input.watch.timeout,
			watch: watches[index]
		});
		eventSpec.timeEnd();
		if (error && !_watches) throw new Error(`Request failed with status ${response.status}: ${response.statusText}`);
		return {
			arrayBuffer,
			resolvedInput
		};
	};
	const specData = (await Promise.all(config.input.map((input, index) => getSpecData(input, index)))).filter((data) => data.arrayBuffer || data.resolvedInput);
	let context;
	if (specData.length) {
		const refParser = new $RefParser();
		const data = specData.length > 1 ? await refParser.bundleMany({
			arrayBuffer: specData.map((data$1) => data$1.arrayBuffer),
			pathOrUrlOrSchemas: [],
			resolvedInputs: specData.map((data$1) => data$1.resolvedInput)
		}) : await refParser.bundle({
			arrayBuffer: specData[0].arrayBuffer,
			pathOrUrlOrSchema: void 0,
			resolvedInput: specData[0].resolvedInput
		});
		if (config.logs.level !== "silent" && _watches) {
			console.clear();
			logInputPaths(inputPaths, jobIndex);
		}
		const eventInputPatch = logger.timeEvent("input.patch");
		patchOpenApiSpec({
			patchOptions: config.parser.patch,
			spec: data
		});
		eventInputPatch.timeEnd();
		const eventParser = logger.timeEvent("parser");
		context = parseOpenApiSpec({
			config,
			dependencies,
			logger,
			spec: data
		});
		context.graph = buildGraph(context.ir, logger).graph;
		eventParser.timeEnd();
		const eventGenerator = logger.timeEvent("generator");
		await generateOutput({ context });
		eventGenerator.timeEnd();
		const eventPostprocess = logger.timeEvent("postprocess");
		if (!config.dryRun) {
			const jobPrefix = colors.gray(`[Job ${jobIndex + 1}] `);
			postprocessOutput(config.output, jobPrefix);
			if (config.logs.level !== "silent") {
				const outputPath = process.env.INIT_CWD ? `./${path.relative(process.env.INIT_CWD, config.output.path)}` : config.output.path;
				console.log(`${jobPrefix}${colors.green("✅ Done!")} Your output is in ${colors.cyanBright(outputPath)}`);
			}
		}
		eventPostprocess.timeEnd();
	}
	const watchedInput = config.input.find((input, index) => input.watch.enabled && typeof inputPaths[index].path === "string");
	if (watchedInput) setTimeout(() => {
		createClient$1({
			config,
			dependencies,
			jobIndex,
			logger,
			watches
		});
	}, watchedInput.watch.interval);
	return context;
};

//#endregion
//#region src/utils/cli.ts
const textAscii = `
888   |                           e      888~-_   888
888___|  e88~~8e  Y88b  /        d8b     888   \\  888
888   | d888  88b  Y888/        /Y88b    888    | 888
888   | 8888__888   Y8/        /  Y88b   888   /  888
888   | Y888    ,    Y        /____Y88b  888_-~   888
888   |  "88___/    /        /      Y88b 888      888
                  _/
`;
const asciiToLines = (ascii, options) => {
	const lines = [];
	const padding = Array.from({ length: options?.padding ?? 0 }).fill("");
	lines.push(...padding);
	let maxLineLength = 0;
	let line = "";
	for (const char of ascii) if (char === "\n") {
		if (line) {
			lines.push(line);
			maxLineLength = Math.max(maxLineLength, line.length);
			line = "";
		}
	} else line += char;
	lines.push(...padding);
	return {
		lines,
		maxLineLength
	};
};
function printCliIntro() {
	const packageJson = loadPackageJson();
	const text = asciiToLines(textAscii, { padding: 1 });
	for (const line of text.lines) console.log(colors.cyan(line));
	console.log(colors.gray(`${packageJson.name} v${packageJson.version}`));
	console.log("");
}

//#endregion
//#region src/utils/logger.ts
let loggerCounter = 0;
const nameToId = (name) => `${name}-${loggerCounter++}`;
const idEnd = (id) => `${id}-end`;
const idLength = (id) => `${id}-length`;
const idStart = (id) => `${id}-start`;
const getSeverity = (duration, percentage) => {
	if (duration > 200) return {
		color: colors.red,
		type: "duration"
	};
	if (percentage > 30) return {
		color: colors.red,
		type: "percentage"
	};
	if (duration > 50) return {
		color: colors.yellow,
		type: "duration"
	};
	if (percentage > 10) return {
		color: colors.yellow,
		type: "percentage"
	};
};
var Logger = class {
	events = [];
	end(result) {
		let event;
		let events = this.events;
		for (const index of result.position) {
			event = events[index];
			if (event?.events) events = event.events;
		}
		if (event && !event.end) event.end = performance.mark(idEnd(event.id));
	}
	/**
	* Recursively end all unended events in the event tree.
	* This ensures all events have end marks before measuring.
	*/
	endAllEvents(events) {
		for (const event of events) {
			if (!event.end) event.end = performance.mark(idEnd(event.id));
			if (event.events.length > 0) this.endAllEvents(event.events);
		}
	}
	report(print = true) {
		const firstEvent = this.events[0];
		if (!firstEvent) return;
		this.endAllEvents(this.events);
		const lastEvent = this.events[this.events.length - 1];
		const name = "root";
		const id = nameToId(name);
		try {
			const measure = performance.measure(idLength(id), idStart(firstEvent.id), idEnd(lastEvent.id));
			if (print) this.reportEvent({
				end: lastEvent.end,
				events: this.events,
				id,
				indent: 0,
				measure,
				name,
				start: firstEvent.start
			});
			return measure;
		} catch {
			return;
		}
	}
	reportEvent({ indent, ...parent }) {
		const color = !indent ? colors.cyan : colors.gray;
		const lastIndex = parent.events.length - 1;
		parent.events.forEach((event, index) => {
			try {
				const measure = performance.measure(idLength(event.id), idStart(event.id), idEnd(event.id));
				const duration = Math.ceil(measure.duration * 100) / 100;
				const percentage = Math.ceil(measure.duration / parent.measure.duration * 100 * 100) / 100;
				const severity = indent ? getSeverity(duration, percentage) : void 0;
				let durationLabel = `${duration.toFixed(2).padStart(8)}ms`;
				if (severity?.type === "duration") durationLabel = severity.color(durationLabel);
				const branch = index === lastIndex ? "└─ " : "├─ ";
				const prefix = !indent ? "" : "│  ".repeat(indent - 1) + branch;
				const maxLength = 38 - prefix.length;
				const percentageBranch = !indent ? "" : "↳ ";
				let percentageLabel = `${indent ? " ".repeat(indent - 1) + percentageBranch : ""}${percentage.toFixed(2)}%`;
				if (severity?.type === "percentage") percentageLabel = severity.color(percentageLabel);
				const jobPrefix = colors.gray("[root] ");
				console.log(`${jobPrefix}${colors.gray(prefix)}${color(`${event.name.padEnd(maxLength)} ${durationLabel} (${percentageLabel})`)}`);
				this.reportEvent({
					...event,
					indent: indent + 1,
					measure
				});
			} catch {}
		});
	}
	start(id) {
		return performance.mark(idStart(id));
	}
	storeEvent({ result, ...event }) {
		const lastEventIndex = event.events.length - 1;
		const lastEvent = event.events[lastEventIndex];
		if (lastEvent && !lastEvent.end) {
			result.position = [...result.position, lastEventIndex];
			this.storeEvent({
				...event,
				events: lastEvent.events,
				result
			});
			return;
		}
		const length = event.events.push({
			...event,
			events: []
		});
		result.position = [...result.position, length - 1];
	}
	timeEvent(name) {
		const id = nameToId(name);
		const start = this.start(id);
		const event = {
			events: this.events,
			id,
			name,
			start
		};
		const result = { position: [] };
		this.storeEvent({
			...event,
			result
		});
		return {
			mark: start,
			timeEnd: () => this.end(result)
		};
	}
};

//#endregion
//#region src/generate.ts
/**
* Generate a client from the provided configuration.
*
* @param userConfig User provided {@link UserConfig} configuration(s).
*/
const createClient = async (userConfig, logger = new Logger()) => {
	const resolvedConfig = typeof userConfig === "function" ? await userConfig() : userConfig;
	const userConfigs = resolvedConfig ? resolvedConfig instanceof Array ? resolvedConfig : [resolvedConfig] : [];
	let rawLogs = userConfigs.find((config) => getLogs(config).level !== "silent")?.logs;
	if (typeof rawLogs === "string") rawLogs = getLogs({ logs: rawLogs });
	let configs;
	try {
		checkNodeVersion();
		const eventCreateClient = logger.timeEvent("createClient");
		const eventConfig = logger.timeEvent("config");
		configs = await initConfigs({
			logger,
			userConfigs
		});
		if (configs.results.some((result$1) => result$1.config.logs.level !== "silent")) printCliIntro();
		eventConfig.timeEnd();
		const allConfigErrors = configs.results.flatMap((result$1) => result$1.errors.map((error) => ({
			error,
			jobIndex: result$1.jobIndex
		})));
		if (allConfigErrors.length) throw new ConfigValidationError(allConfigErrors);
		const result = (await Promise.all(configs.results.map(async (result$1) => {
			try {
				return await createClient$1({
					config: result$1.config,
					dependencies: configs.dependencies,
					jobIndex: result$1.jobIndex,
					logger
				});
			} catch (error) {
				throw new JobError("", {
					error,
					jobIndex: result$1.jobIndex
				});
			}
		}))).filter((client) => Boolean(client));
		eventCreateClient.timeEnd();
		const printLogs = configs.results.some((result$1) => result$1.config.logs.level === "debug");
		logger.report(printLogs);
		return result;
	} catch (error) {
		const results = configs?.results ?? [];
		const logs = results.find((result) => result.config.logs.level !== "silent")?.config.logs ?? results[0]?.config.logs ?? rawLogs;
		const dryRun = results.some((result) => result.config.dryRun) ?? userConfigs.some((config) => config.dryRun) ?? false;
		const logPath = logs?.file && !dryRun ? logCrashReport(error, logs.path ?? "") : void 0;
		if (!logs || logs.level !== "silent") {
			printCrashReport({
				error,
				logPath
			});
			if (await shouldReportCrash({
				error,
				isInteractive: results.some((result) => result.config.interactive) ?? userConfigs.some((config) => config.interactive) ?? false
			})) await openGitHubIssueWithCrashReport(error);
		}
		throw error;
	}
};

//#endregion
//#region src/utils/exports.ts
/**
* Utilities shared across the package.
*/
const utils = {
	stringCase({ case: casing, stripLeadingSeparators, value }) {
		return toCase(value, casing, { stripLeadingSeparators });
	},
	toCase
};

//#endregion
//#region src/index.ts
colors.enabled = colorSupport().hasBasic;
/**
* Type helper for openapi-ts.config.ts, returns {@link MaybeArray<UserConfig>} object(s)
*/
const defineConfig = async (config) => typeof config === "function" ? await config() : config;

//#endregion
export { Logger as i, utils as n, createClient as r, defineConfig as t };
//# sourceMappingURL=src-BehyjtZ7.mjs.map