Support for updated shapes
This commit is contained in:
parent
9d4907aa25
commit
d8ddff01a6
6 changed files with 58 additions and 65 deletions
4
bun.lock
4
bun.lock
|
@ -4,7 +4,7 @@
|
||||||
"": {
|
"": {
|
||||||
"name": "@proscenium/muse",
|
"name": "@proscenium/muse",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@proscenium/playbill": "0.0.14",
|
"@proscenium/playbill": "0.0.1",
|
||||||
"chalk": "^5.4.1",
|
"chalk": "^5.4.1",
|
||||||
"yaml": "^2.7.0",
|
"yaml": "^2.7.0",
|
||||||
"zod": "^3.24.1",
|
"zod": "^3.24.1",
|
||||||
|
@ -37,7 +37,7 @@
|
||||||
|
|
||||||
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@1.9.4", "", { "os": "win32", "cpu": "x64" }, "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA=="],
|
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@1.9.4", "", { "os": "win32", "cpu": "x64" }, "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA=="],
|
||||||
|
|
||||||
"@proscenium/playbill": ["@proscenium/playbill@0.0.14", "https://git.astral.camp/api/packages/proscenium/npm/%40proscenium%2Fplaybill/-/0.0.14/playbill-0.0.14.tgz", { "peerDependencies": { "typescript": "^5" } }, "sha512-Fbo7IHTeRBDLwh6olETphh2duhMRrUx7dclFGT3VRhbCeCIqp+64N93M3fWlvOUrEyIU75WgpxkOz7FzfecAzg=="],
|
"@proscenium/playbill": ["@proscenium/playbill@0.0.1", "https://git.astral.camp/api/packages/proscenium/npm/%40proscenium%2Fplaybill/-/0.0.1/playbill-0.0.1.tgz", { "peerDependencies": { "typescript": "^5" } }, "sha512-oKOqGMKeIrmHOmBvk65RFTBfbXH8KjxR+4PMtZQ2KLVGpYPexj60muf7SmG54K32Vd10xXpBqMAG5BvGZvhLeg=="],
|
||||||
|
|
||||||
"@types/bun": ["@types/bun@1.2.3", "", { "dependencies": { "bun-types": "1.2.3" } }, "sha512-054h79ipETRfjtsCW9qJK8Ipof67Pw9bodFWmkfkaUaRiIQ1dIV2VTlheshlBx3mpKr0KeK8VqnMMCtgN9rQtw=="],
|
"@types/bun": ["@types/bun@1.2.3", "", { "dependencies": { "bun-types": "1.2.3" } }, "sha512-054h79ipETRfjtsCW9qJK8Ipof67Pw9bodFWmkfkaUaRiIQ1dIV2VTlheshlBx3mpKr0KeK8VqnMMCtgN9rQtw=="],
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
"chalk": "^5.4.1",
|
"chalk": "^5.4.1",
|
||||||
"yaml": "^2.7.0",
|
"yaml": "^2.7.0",
|
||||||
"zod": "^3.24.1",
|
"zod": "^3.24.1",
|
||||||
"@proscenium/playbill": "0.0.14"
|
"@proscenium/playbill": "0.0.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"fmt": "bunx --bun biome check --fix",
|
"fmt": "bunx --bun biome check --fix",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
$binding: playbill
|
$binding: playbill
|
||||||
extends: ../extend-me/binding.yaml
|
extends: ../extend-me
|
||||||
id: the-great-spires
|
id: the-great-spires
|
||||||
name: The Great Spires
|
name: The Great Spires
|
||||||
author: "Endeavorance <hello@endeavorance.camp>"
|
author: "Endeavorance <hello@endeavorance.camp>"
|
||||||
|
|
|
@ -3,11 +3,12 @@ import { Glob } from "bun";
|
||||||
import z from "zod";
|
import z from "zod";
|
||||||
import {
|
import {
|
||||||
getEmptyPlaybill,
|
getEmptyPlaybill,
|
||||||
type AnyResource,
|
type UnknownResource,
|
||||||
type Playbill,
|
type Playbill,
|
||||||
} from "@proscenium/playbill";
|
} from "@proscenium/playbill";
|
||||||
import { loadYAMLFileOrFail } from "./files";
|
import { loadYAMLFileOrFail } from "./files";
|
||||||
import { loadResourceFile } from "./resource";
|
import { loadResourceFile } from "./resource";
|
||||||
|
import { FileNotFoundError } from "./errors";
|
||||||
|
|
||||||
const BindingFileSchema = z.object({
|
const BindingFileSchema = z.object({
|
||||||
$binding: z.literal("playbill"),
|
$binding: z.literal("playbill"),
|
||||||
|
@ -39,21 +40,42 @@ export interface PlaybillBinding {
|
||||||
playbill: Playbill;
|
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(
|
export async function loadFromBinding(
|
||||||
filePath: string,
|
bindingPath: string,
|
||||||
): Promise<PlaybillBinding> {
|
): Promise<PlaybillBinding> {
|
||||||
const yamlContent = await loadYAMLFileOrFail(filePath);
|
const resolvedBindingPath = await resolveBindingPath(bindingPath);
|
||||||
|
const yamlContent = await loadYAMLFileOrFail(resolvedBindingPath);
|
||||||
const binding = BindingFileSchema.parse(yamlContent);
|
const binding = BindingFileSchema.parse(yamlContent);
|
||||||
const fileGlobs = binding.files;
|
const fileGlobs = binding.files;
|
||||||
const bindingFileDirname = filePath.split("/").slice(0, -1).join("/");
|
const bindingFileDirname = bindingPath.split("/").slice(0, -1).join("/");
|
||||||
|
|
||||||
let basePlaybill: Playbill | null = null;
|
let basePlaybill: Playbill | null = null;
|
||||||
|
|
||||||
// If this is extending another binding, load that first
|
// If this is extending another binding, load that first
|
||||||
if (binding.extends) {
|
if (binding.extends) {
|
||||||
// TODO: Allow extending built playbills in addition to bindings
|
const pathFromHere = path.resolve(bindingFileDirname, binding.extends);
|
||||||
const extendBindingPath = path.resolve(bindingFileDirname, binding.extends);
|
const extendBindingPath = await resolveBindingPath(pathFromHere);
|
||||||
basePlaybill = (await loadFromBinding(extendBindingPath)).playbill;
|
const loadedBinding = await loadFromBinding(extendBindingPath);
|
||||||
|
basePlaybill = loadedBinding.playbill;
|
||||||
}
|
}
|
||||||
|
|
||||||
const allFilePaths: string[] = [];
|
const allFilePaths: string[] = [];
|
||||||
|
@ -71,13 +93,13 @@ export async function loadFromBinding(
|
||||||
allFilePaths.push(...results);
|
allFilePaths.push(...results);
|
||||||
}
|
}
|
||||||
|
|
||||||
const bindingFileAbsolutePath = path.resolve(filePath);
|
const bindingFileAbsolutePath = path.resolve(bindingPath);
|
||||||
const filePathsWithoutBindingFile = allFilePaths.filter((filePath) => {
|
const filePathsWithoutBindingFile = allFilePaths.filter((filePath) => {
|
||||||
return filePath !== bindingFileAbsolutePath;
|
return filePath !== bindingFileAbsolutePath;
|
||||||
});
|
});
|
||||||
|
|
||||||
// -- LOAD ASSOCIATED RESOURCE FILES -- //
|
// -- LOAD ASSOCIATED RESOURCE FILES -- //
|
||||||
const loadedResources: AnyResource[] = [];
|
const loadedResources: UnknownResource[] = [];
|
||||||
for (const filepath of filePathsWithoutBindingFile) {
|
for (const filepath of filePathsWithoutBindingFile) {
|
||||||
const loaded = await loadResourceFile(filepath);
|
const loaded = await loadResourceFile(filepath);
|
||||||
loadedResources.push(...loaded);
|
loadedResources.push(...loaded);
|
||||||
|
@ -93,43 +115,17 @@ export async function loadFromBinding(
|
||||||
playbill.description = binding.description ?? "";
|
playbill.description = binding.description ?? "";
|
||||||
|
|
||||||
for (const resource of loadedResources) {
|
for (const resource of loadedResources) {
|
||||||
switch (resource.$define) {
|
const resourceType = resource.$define;
|
||||||
case "ability":
|
const resourceMap = playbill[resourceType] as Record<
|
||||||
playbill.abilities.push(resource);
|
string,
|
||||||
break;
|
typeof resource
|
||||||
case "species":
|
>;
|
||||||
playbill.species.push(resource);
|
resourceMap[resource.id] = resource;
|
||||||
break;
|
|
||||||
case "entity":
|
|
||||||
playbill.entities.push(resource);
|
|
||||||
break;
|
|
||||||
case "item":
|
|
||||||
playbill.items.push(resource);
|
|
||||||
break;
|
|
||||||
case "tag":
|
|
||||||
playbill.tags.push(resource);
|
|
||||||
break;
|
|
||||||
case "method":
|
|
||||||
playbill.methods.push(resource);
|
|
||||||
break;
|
|
||||||
case "lore":
|
|
||||||
playbill.lore.push(resource);
|
|
||||||
break;
|
|
||||||
case "rule":
|
|
||||||
playbill.rules.push(resource);
|
|
||||||
break;
|
|
||||||
case "guide":
|
|
||||||
playbill.guides.push(resource);
|
|
||||||
break;
|
|
||||||
case "glossary":
|
|
||||||
playbill.glossaries.push(resource);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
_raw: binding,
|
_raw: binding,
|
||||||
bindingFilePath: filePath,
|
bindingFilePath: bindingPath,
|
||||||
includedFiles: filePathsWithoutBindingFile,
|
includedFiles: filePathsWithoutBindingFile,
|
||||||
|
|
||||||
id: binding.id,
|
id: binding.id,
|
||||||
|
|
16
src/index.ts
16
src/index.ts
|
@ -1,7 +1,7 @@
|
||||||
import { parseArgs } from "node:util";
|
import { parseArgs } from "node:util";
|
||||||
import { ValidatedPlaybillSchema, checkDirectives } from "@proscenium/playbill";
|
import { ValidatedPlaybillSchema } from "@proscenium/playbill";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
import { loadFromBinding } from "./binding";
|
import { loadFromBinding, resolveBindingPath } from "./binding";
|
||||||
import { usage } from "./usage";
|
import { usage } from "./usage";
|
||||||
import { CLIError, MuseError } from "./errors";
|
import { CLIError, MuseError } from "./errors";
|
||||||
|
|
||||||
|
@ -74,7 +74,8 @@ async function main(): Promise<number> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- BINDING FILE -- //
|
// -- BINDING FILE -- //
|
||||||
const bindingPath = args[0] ?? "./binding.yaml";
|
const bindingPathInput = args[0] ?? "./binding.yaml";
|
||||||
|
const bindingPath = await resolveBindingPath(bindingPathInput);
|
||||||
|
|
||||||
verboseLog(`Building Playbill with binding: ${bindingPath}`);
|
verboseLog(`Building Playbill with binding: ${bindingPath}`);
|
||||||
|
|
||||||
|
@ -94,19 +95,12 @@ async function main(): Promise<number> {
|
||||||
return ExitCode.Error;
|
return ExitCode.Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
const directiveValidationResult = checkDirectives(validatedPlaybill.data);
|
|
||||||
|
|
||||||
if (!directiveValidationResult) {
|
|
||||||
console.error("Error validating playbill directives");
|
|
||||||
return ExitCode.Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
verboseLog("Playbill validated");
|
verboseLog("Playbill validated");
|
||||||
|
|
||||||
// -- EXIT EARLY IF JUST CHECKING VALIDATION --//
|
// -- EXIT EARLY IF JUST CHECKING VALIDATION --//
|
||||||
if (options.check) {
|
if (options.check) {
|
||||||
console.log(chalk.green("Playbill validated successfully"));
|
console.log(chalk.green("Playbill validated successfully"));
|
||||||
return ExitCode.Error;
|
return ExitCode.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- SERIALIZE TO JSON --//
|
// -- SERIALIZE TO JSON --//
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import {
|
import {
|
||||||
type AnyResource,
|
type UnknownResource,
|
||||||
AnyResourceSchema,
|
UnknownResourceSchema,
|
||||||
ResourceMap,
|
ResourceMap,
|
||||||
} from "@proscenium/playbill";
|
} from "@proscenium/playbill";
|
||||||
import YAML, { YAMLParseError } from "yaml";
|
import YAML, { YAMLParseError } from "yaml";
|
||||||
|
@ -15,7 +15,10 @@ function determineFileFormat(filePath: string): FileFormat {
|
||||||
return filePath.split(".").pop() === "md" ? "markdown" : "yaml";
|
return filePath.split(".").pop() === "md" ? "markdown" : "yaml";
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadYamlResourceFile(filePath: string, text: string): AnyResource[] {
|
function loadYamlResourceFile(
|
||||||
|
filePath: string,
|
||||||
|
text: string,
|
||||||
|
): UnknownResource[] {
|
||||||
const parsedDocs = YAML.parseAllDocuments(text);
|
const parsedDocs = YAML.parseAllDocuments(text);
|
||||||
|
|
||||||
if (parsedDocs.some((doc) => doc.toJS() === null)) {
|
if (parsedDocs.some((doc) => doc.toJS() === null)) {
|
||||||
|
@ -32,11 +35,11 @@ function loadYamlResourceFile(filePath: string, text: string): AnyResource[] {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const collection: AnyResource[] = [];
|
const collection: UnknownResource[] = [];
|
||||||
|
|
||||||
for (const doc of parsedDocs) {
|
for (const doc of parsedDocs) {
|
||||||
const raw = doc.toJS();
|
const raw = doc.toJS();
|
||||||
const parsed = AnyResourceSchema.safeParse(raw);
|
const parsed = UnknownResourceSchema.safeParse(raw);
|
||||||
|
|
||||||
if (!parsed.success) {
|
if (!parsed.success) {
|
||||||
throw new MalformedResourceFileError(
|
throw new MalformedResourceFileError(
|
||||||
|
@ -59,7 +62,7 @@ function loadYamlResourceFile(filePath: string, text: string): AnyResource[] {
|
||||||
function loadMarkdownResourceFile(
|
function loadMarkdownResourceFile(
|
||||||
filePath: string,
|
filePath: string,
|
||||||
text: string,
|
text: string,
|
||||||
): AnyResource[] {
|
): UnknownResource[] {
|
||||||
try {
|
try {
|
||||||
const frontmatter = extractFrontmatter(text);
|
const frontmatter = extractFrontmatter(text);
|
||||||
const markdown = extractMarkdown(text);
|
const markdown = extractMarkdown(text);
|
||||||
|
@ -69,7 +72,7 @@ function loadMarkdownResourceFile(
|
||||||
description: markdown,
|
description: markdown,
|
||||||
};
|
};
|
||||||
|
|
||||||
const parsed = AnyResourceSchema.parse(together);
|
const parsed = UnknownResourceSchema.parse(together);
|
||||||
return [parsed];
|
return [parsed];
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof YAMLParseError) {
|
if (e instanceof YAMLParseError) {
|
||||||
|
@ -102,7 +105,7 @@ function loadMarkdownResourceFile(
|
||||||
*/
|
*/
|
||||||
export async function loadResourceFile(
|
export async function loadResourceFile(
|
||||||
filePath: string,
|
filePath: string,
|
||||||
): Promise<AnyResource[]> {
|
): Promise<UnknownResource[]> {
|
||||||
const text = await loadFileOrFail(filePath);
|
const text = await loadFileOrFail(filePath);
|
||||||
const format = determineFileFormat(filePath);
|
const format = determineFileFormat(filePath);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue