refactor: reorg

This commit is contained in:
2026-03-03 10:54:20 +08:00
parent 6b77653d27
commit 4280da9fec
3 changed files with 180 additions and 176 deletions
+122
View File
@@ -0,0 +1,122 @@
import {createEffect, createResource } from "solid-js";
import type {OptionsResult, RuntimeResult} from "../../yarn-spinner/runtime/results";
import {compile, parseYarn, YarnRunner} from "../../yarn-spinner";
import {loadElementSrc, resolvePath} from "../utils/path";
import {createStore} from "solid-js/store";
import {RunnerOptions} from "../../yarn-spinner/runtime/runner";
type YarnSpinnerStore = {
dialogueHistory: (RuntimeResult | OptionsResult['options'][0])[],
currentOptions: OptionsResult | null,
isEnded: boolean,
runnerInstance: YarnRunner | null,
}
export function createYarnStore(element: HTMLElement, props: RunnerOptions){
const [store, setStore] = createStore<YarnSpinnerStore>({
dialogueHistory: [],
currentOptions: null,
isEnded: false,
runnerInstance: null
});
// 获取文件路径
const {articlePath, rawSrc} = loadElementSrc(element);
const yarnPaths = (rawSrc || '').split(',')
.map((s: string) => resolvePath(articlePath, s.trim()))
.filter(Boolean);
// 加载 yarn 内容
const [yarnContent] = createResource(() => yarnPaths, loadYarnFiles);
// 创建 runner
const createRunner = () => {
const content = yarnContent();
if (!content) return null;
try {
const ast = parseYarn(content);
const program = compile(ast);
return new YarnRunner(program, props);
} catch (error) {
console.error('Failed to initialize YarnRunner:', error);
return null;
}
};
function advance(index?: number){
const runner = store.runnerInstance;
if(!runner) return;
if(index === undefined && runner.currentResult?.isDialogueEnd) return;
if(runner.currentResult?.type === 'options'){
if(index === undefined)return;
const option = runner.currentResult.options[index];
setStore('dialogueHistory', [...store.dialogueHistory, option]);
}
runner.advance(index);
processRunnerOutput();
}
createEffect(() => {
if(!yarnContent()) return;
setStore('runnerInstance', createRunner());
requestAnimationFrame(function(){
advance();
});
});
// 处理 runner 输出
const processRunnerOutput = () => {
const runner = store.runnerInstance;
if(!runner)return;
const result = runner.currentResult;
if (!result) return;
if(result.type === 'options'){
setStore('currentOptions', result);
}else{
setStore('currentOptions', null);
}
setStore('dialogueHistory', [...store.dialogueHistory, result]);
};
// 重新开始
const restart = () => {
setStore({
dialogueHistory: [],
currentOptions: null,
isEnded: false,
runnerInstance: createRunner(),
});
processRunnerOutput();
};
return {
store,
advance,
restart,
}
}
// 缓存已加载的 yarn 文件内容
const yarnCache = new Map<string, string>();
// 加载 yarn 文件内容
async function loadYarnFile(path: string): Promise<string> {
if (yarnCache.has(path)) {
return yarnCache.get(path)!;
}
const response = await fetch(path);
const content = await response.text();
yarnCache.set(path, content);
return content;
}
// 加载多个 yarn 文件并拼接
async function loadYarnFiles(paths: string[]): Promise<string> {
const contents = await Promise.all(paths.map(path => loadYarnFile(path)));
return contents.join('\n');
}