Organize into folders

This commit is contained in:
Endeavorance 2025-03-10 20:58:11 -04:00
parent 84b8f1c9d6
commit 2e0d4b45ea
12 changed files with 121 additions and 64 deletions

151
src/lib/binding.ts Normal file
View file

@ -0,0 +1,151 @@
import path from "node:path";
import {
type Playbill,
type UnknownResource,
getEmptyPlaybill,
} from "@proscenium/playbill";
import { Glob } from "bun";
import z from "zod";
import { FileNotFoundError } from "#lib/errors";
import { loadYAMLFileOrFail } from "#util/files";
import { loadResourceFile } from "./resource";
const HTMLRenderOptionsSchema = z.object({
styles: z.array(z.string()).optional(),
});
const BindingFileSchema = z.object({
$binding: z.literal("playbill"),
extends: z.string().optional(),
id: z.string(),
name: z.string().default("Unnamed playbill"),
author: z.string().optional(),
description: z.string().optional(),
version: z.string(),
files: z.array(z.string()).default(["**/*.yaml", "**/*.md"]),
html: HTMLRenderOptionsSchema.optional(),
});
type BindingFileContent = z.infer<typeof BindingFileSchema>;
export interface PlaybillBinding {
_raw: BindingFileContent;
// File information
bindingFilePath: string;
bindingFileDirname: string;
includedFiles: string[];
// Binding properties
id: string;
name: string;
author: string;
version: string;
description: string;
html?: z.infer<typeof HTMLRenderOptionsSchema>;
playbill: Playbill;
}
export async function resolveBindingPath(bindingPath: string): Promise<string> {
// If the path does not specify a filename, use binding.yamk
const inputLocation = Bun.file(bindingPath);
// If it is a directory, try again seeking a binding.yaml inside
const stat = await inputLocation.stat();
if (stat.isDirectory()) {
return resolveBindingPath(path.resolve(bindingPath, "binding.yaml"));
}
// If it doesnt exist, bail
if (!(await inputLocation.exists())) {
throw new FileNotFoundError(bindingPath);
}
// Resolve the path
return path.resolve(bindingPath);
}
export async function loadFromBinding(
bindingPath: string,
): Promise<PlaybillBinding> {
const resolvedBindingPath = await resolveBindingPath(bindingPath);
const yamlContent = await loadYAMLFileOrFail(resolvedBindingPath);
const binding = BindingFileSchema.parse(yamlContent);
const fileGlobs = binding.files;
const bindingFileDirname = bindingPath.split("/").slice(0, -1).join("/");
let basePlaybill: Playbill | null = null;
// If this is extending another binding, load that first
if (binding.extends) {
const pathFromHere = path.resolve(bindingFileDirname, binding.extends);
const extendBindingPath = await resolveBindingPath(pathFromHere);
const loadedBinding = await loadFromBinding(extendBindingPath);
basePlaybill = loadedBinding.playbill;
}
const allFilePaths: string[] = [];
for (const thisGlob of fileGlobs) {
const glob = new Glob(thisGlob);
const results = glob.scanSync({
cwd: bindingFileDirname,
absolute: true,
followSymlinks: true,
onlyFiles: true,
});
allFilePaths.push(...results);
}
const bindingFileAbsolutePath = path.resolve(bindingPath);
const filePathsWithoutBindingFile = allFilePaths.filter((filePath) => {
return filePath !== bindingFileAbsolutePath;
});
// -- LOAD ASSOCIATED RESOURCE FILES -- //
const loadedResources: UnknownResource[] = [];
for (const filepath of filePathsWithoutBindingFile) {
const loaded = await loadResourceFile(filepath);
loadedResources.push(...loaded);
}
// -- COMPILE PLAYBILL FROM RESOURCES --//
const playbill = basePlaybill ?? getEmptyPlaybill();
playbill.id = binding.id;
playbill.name = binding.name;
playbill.author = binding.author ?? "Anonymous";
playbill.version = binding.version;
playbill.description = binding.description ?? "";
for (const resource of loadedResources) {
const resourceType = resource.$define;
const resourceMap = playbill[resourceType] as Record<
string,
typeof resource
>;
resourceMap[resource.id] = resource;
}
return {
_raw: binding,
bindingFilePath: bindingPath,
bindingFileDirname,
includedFiles: filePathsWithoutBindingFile,
id: binding.id,
name: binding.name,
author: binding.author ?? "Anonymous",
description: binding.description ?? "",
version: binding.version,
html: binding.html,
playbill,
};
}