Files
kuber/lib/yaml.ts
T
2026-10-06 15:31:51 +00:00

67 lines
1.9 KiB
TypeScript

import z from "zod";
import { readdir } from "node:fs/promises";
import { join } from "node:path";
import type { ComposeSpecification } from "../schema/docker.d";
import { file, YAML } from "bun";
const ComposeFileNames = new Set([
"compose.yml",
"compose.yaml",
"docker-compose.yml",
"docker-compose.yaml",
]);
let composeSchema: Promise<z.ZodType<ComposeSpecification>> | undefined;
function getComposeSchema(): Promise<z.ZodType<ComposeSpecification>> {
if (!composeSchema) {
composeSchema = import("../schema/docker.ts")
.then(
({ default: schema }) =>
z
.fromJSONSchema(
schema as unknown as Parameters<typeof z.fromJSONSchema>[0],
)
.superRefine((value, context) => {
if (!value || typeof value !== "object" || Array.isArray(value))
return;
for (const key of Object.keys(value)) {
if (
Object.hasOwn(schema.properties, key) ||
key.startsWith("x-")
)
continue;
context.addIssue({
code: "custom",
path: [key],
message: `Unrecognized Compose property: ${key}`,
});
}
}) as z.ZodType<ComposeSpecification>,
)
.catch((error) => {
composeSchema = undefined;
throw error;
});
}
return composeSchema;
}
export function readCompose(path: string): Promise<ComposeSpecification> {
return file(path)
.text()
.then(YAML.parse)
.then(async (value) => (await getComposeSchema()).parse(value));
}
export async function resolveComposeFile(
path: string,
): Promise<string | undefined> {
const entries = await readdir(path, { withFileTypes: true });
return entries
.filter((entry) => entry.isFile() && ComposeFileNames.has(entry.name))
.map((entry) => join(path, entry.name))
.sort()[0];
}