yarn-spinner-runner-ts
Version:
TypeScript parser, compiler, and runtime for Yarn Spinner 3.x with React adapter [NPM package](https://www.npmjs.com/package/yarn-spinner-runner-ts)
84 lines (74 loc) • 3.19 kB
text/typescript
/**
* Scene configuration parser using js-yaml
* Supports YAML string or plain object
*/
import yaml from "js-yaml";
import type { SceneCollection, SceneConfig, ActorConfig } from "./types.js";
/**
* Parse scene configuration from YAML string or object
*/
export function parseScenes(input: string | Record<string, unknown>): SceneCollection {
// If already an object, use it directly
if (typeof input === "object" && input !== null) {
return parseScenesFromObject(input);
}
// Parse YAML string
try {
const parsed = yaml.load(input) as Record<string, unknown>;
return parseScenesFromObject(parsed || {});
} catch (error) {
console.error("Failed to parse YAML scene config:", error);
throw new Error(`Invalid YAML scene configuration: ${error instanceof Error ? error.message : String(error)}`);
}
}
function parseScenesFromObject(obj: Record<string, unknown>): SceneCollection {
const scenes: Record<string, SceneConfig> = {};
// Extract global actors if defined separately
const globalActors: Record<string, ActorConfig> = {};
if (typeof obj.actors === "object" && obj.actors !== null) {
for (const [actorName, actorData] of Object.entries(obj.actors)) {
if (typeof actorData === "object" && actorData !== null) {
// Nested format: actorName: { image: "..." }
globalActors[actorName] = {
image: typeof actorData.image === "string" ? actorData.image : undefined,
};
} else if (typeof actorData === "string") {
// Shorthand: actorName: "/path/to/image.png"
globalActors[actorName] = { image: actorData };
}
}
}
// Parse scenes
if (typeof obj.scenes === "object" && obj.scenes !== null) {
const scenesObj = obj.scenes as Record<string, unknown>;
for (const [sceneName, sceneData] of Object.entries(scenesObj)) {
if (typeof sceneData === "object" && sceneData !== null) {
const data = sceneData as Record<string, unknown>;
const sceneActors: Record<string, ActorConfig> = { ...globalActors }; // Start with global actors
// Override with scene-specific actors if defined
if (typeof data.actors === "object" && data.actors !== null) {
for (const [actorName, actorData] of Object.entries(data.actors)) {
if (typeof actorData === "object" && actorData !== null) {
sceneActors[actorName] = {
image: typeof actorData.image === "string" ? actorData.image : undefined,
};
} else if (typeof actorData === "string") {
sceneActors[actorName] = { image: actorData };
}
}
}
scenes[sceneName] = {
background: typeof data.background === "string" ? data.background : "",
actors: sceneActors,
};
} else if (typeof sceneData === "string") {
// Shorthand: scene1: "/path/to/background.png" (uses global actors)
scenes[sceneName] = {
background: sceneData,
actors: { ...globalActors },
};
}
}
}
return { scenes };
}