Use new playbill updates

This commit is contained in:
Endeavorance 2025-03-21 16:40:47 -04:00
parent c1f3c6cade
commit f7f861a1cb
8 changed files with 81 additions and 210 deletions

View file

@ -1,14 +1,5 @@
import path from "node:path";
import {
type Ability,
type Blueprint,
type Item,
type Method,
Playbill,
type Resource,
type Rule,
type Species,
} from "@proscenium/playbill";
import { type AnyPlaybillComponent, Playbill } from "@proscenium/playbill";
import { Glob } from "bun";
import z from "zod";
import { loadYAMLFileOrFail } from "#util";
@ -33,11 +24,7 @@ const BindingSchema = z.object({
terms: z.record(z.string(), z.string()).default({}),
});
type Binding = z.infer<typeof BindingSchema>;
export interface BoundPlaybill {
_raw: Binding;
// File information
bindingFilePath: string;
bindingFileDirname: string;
@ -93,7 +80,12 @@ export async function loadFromBinding(
const fileGlobs = binding.files;
const bindingFileDirname = path.dirname(resolvedBindingPath);
const playbill = new Playbill();
const playbill = new Playbill(
binding.name,
binding.author,
binding.description,
binding.version,
);
// If this is extending another binding, load that first
for (const includePath of binding.include) {
@ -151,86 +143,15 @@ export async function loadFromBinding(
await Promise.all(fileLoadPromises);
// Decorate the playbill with the binding metadata
playbill.name = binding.name;
playbill.author = binding.author ?? "Anonymous";
playbill.version = binding.version;
playbill.description = binding.description ?? "";
const abilities: Ability[] = [];
const bluprints: Blueprint[] = [];
const methods: Method[] = [];
const species: Species[] = [];
const items: Item[] = [];
const rules: Rule[] = [];
const resources: Resource[] = [];
// Aggregate all components before adding to playbill to allow for
// ensuring components are added in a valid order
// Aggregate all loaded components
const loadedComponents: AnyPlaybillComponent[] = [];
for (const file of componentFiles) {
// Load components from the file into the playbill
for (const component of file.components) {
switch (component.type) {
case "ability":
abilities.push(component.component);
break;
case "blueprint":
bluprints.push(component.component);
break;
case "method":
methods.push(component.component);
break;
case "species":
species.push(component.component);
break;
case "item":
items.push(component.component);
break;
case "rule":
rules.push(component.component);
break;
case "resource":
resources.push(component.component);
break;
default:
throw new Error("Unknown component type");
}
}
loadedComponents.push(...file.components);
}
// Add resources first
for (const resource of resources) {
playbill.addResource(resource);
}
// Add abilities before methods, species, and blueprints
for (const ability of abilities) {
playbill.addAbility(ability);
}
// Add species before blueprints
for (const specie of species) {
playbill.addSpecies(specie);
}
// Add methods after abilities
for (const method of methods) {
playbill.addMethod(method);
}
// Add items
for (const item of items) {
playbill.addItem(item);
}
// Add blueprints after methods, species, items, and abilities
for (const blueprint of bluprints) {
playbill.addBlueprint(blueprint);
}
// Add rules
for (const rule of rules) {
playbill.addRule(rule);
}
// Add all components to the playbill
// (This method ensures proper addition order maintain correctness)
playbill.addManyComponents(loadedComponents);
// Add all definitions
for (const [term, definition] of Object.entries(binding.terms)) {
@ -238,7 +159,6 @@ export async function loadFromBinding(
}
return {
_raw: binding,
bindingFilePath: bindingPath,
bindingFileDirname,
files: filePathsWithoutBindingFile,

View file

@ -1,10 +1,11 @@
import path from "node:path";
import { type ParsedComponent, parsePlaybillComponent } from "define";
import { parsePlaybillComponent } from "define";
import YAML, { YAMLParseError } from "yaml";
import { ZodError } from "zod";
import { loadFileOrFail } from "#util";
import { MalformedResourceFileError } from "./errors";
import { toSlug } from "./slug";
import type { AnyPlaybillComponent } from "@proscenium/playbill";
type FileFormat = "yaml" | "markdown";
@ -45,7 +46,7 @@ function extractMarkdown(content: string): string {
function parseYAMLResourceFile(
filePath: string,
text: string,
): ParsedComponent[] {
): AnyPlaybillComponent[] {
const parsedDocs = YAML.parseAllDocuments(text);
if (parsedDocs.some((doc) => doc.toJS() === null)) {
@ -62,7 +63,7 @@ function parseYAMLResourceFile(
);
}
const collection: ParsedComponent[] = [];
const collection: AnyPlaybillComponent[] = [];
for (const doc of parsedDocs) {
const raw = doc.toJS();
@ -78,7 +79,7 @@ function parseYAMLResourceFile(
function parseMarkdownResourceFile(
filePath: string,
text: string,
): ParsedComponent[] {
): AnyPlaybillComponent[] {
try {
const defaultName = path.basename(filePath, ".md");
const defaultId = toSlug(defaultName);
@ -124,7 +125,7 @@ export class ComponentFile {
private _filePath: string;
private _raw = "";
private _format: FileFormat;
private _components: ParsedComponent[] = [];
private _components: AnyPlaybillComponent[] = [];
private _basename: string;
constructor(filePath: string) {

View file

@ -8,7 +8,7 @@ import { toSlug } from "./slug";
import rehypeRaw from "rehype-raw";
import remarkGfm from "remark-gfm";
import rehypeShiftHeading from "rehype-shift-heading";
import type { TaggedComponent } from "@proscenium/playbill";
import type { AnyPlaybillComponent } from "@proscenium/playbill";
export type MarkdownParserFunction = (input: string) => Promise<string>;
@ -26,9 +26,7 @@ export function createMarkdownRenderer(
.use(remarkGfm)
.use(remarkWikiLink, {
aliasDivider: "|",
permalinks: binding.playbill
.allComponents()
.map((c) => `${c.component.id}`),
permalinks: binding.playbill.allComponents().map((c) => c.id),
pageResolver: (permalink: string) => {
return [toSlug(permalink)];
},
@ -54,21 +52,19 @@ export async function compileMarkdownInPlaybill(
const playbill = boundPlaybill.playbill;
// Define a processor function to iterate over all components and process their markdown
const processMarkdownInComponent = async (entry: TaggedComponent) => {
entry.component.description = await renderMarkdown(
entry.component.description,
);
const processMarkdownInComponent = async (entry: AnyPlaybillComponent) => {
entry.description = await renderMarkdown(entry.description);
if (entry.type === "resource" && entry.component.type === "table") {
if (entry._component === "resource" && entry.type === "table") {
const newData: string[][] = [];
for (const row of entry.component.data) {
for (const row of entry.data) {
const newRow: string[] = [];
for (const cell of row) {
newRow.push(await renderMarkdown(cell));
}
newData.push(newRow);
}
entry.component.data = newData;
entry.data = newData;
}
};