yarn-spinner-runner-ts 0.1.4-a → 0.1.4-c
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/markup/parser.js +15 -2
- package/dist/markup/parser.js.map +1 -1
- package/dist/react/DialogueExample.js +4 -4
- package/dist/react/DialogueExample.js.map +1 -1
- package/dist/react/DialogueView.d.ts +2 -1
- package/dist/react/DialogueView.js +29 -17
- package/dist/react/DialogueView.js.map +1 -1
- package/dist/react/MarkupRenderer.js +1 -1
- package/dist/react/MarkupRenderer.js.map +1 -1
- package/dist/react/useYarnRunner.js +60 -16
- package/dist/react/useYarnRunner.js.map +1 -1
- package/dist/tests/dialogue_view.test.d.ts +1 -0
- package/dist/tests/dialogue_view.test.js +18 -0
- package/dist/tests/dialogue_view.test.js.map +1 -0
- package/dist/tests/markup.test.js +7 -0
- package/dist/tests/markup.test.js.map +1 -1
- package/docs/markup.md +33 -33
- package/eslint.config.cjs +39 -39
- package/package.json +1 -1
- package/src/markup/parser.ts +56 -43
- package/src/react/DialogueExample.tsx +10 -9
- package/src/react/DialogueView.tsx +312 -297
- package/src/react/MarkupRenderer.tsx +1 -2
- package/src/react/useYarnRunner.tsx +101 -46
- package/src/tests/dialogue_view.test.tsx +26 -0
- package/src/tests/markup.test.ts +17 -1
|
@@ -1,47 +1,102 @@
|
|
|
1
|
-
import { useState, useCallback, useRef } from "react";
|
|
2
|
-
import { YarnRunner, type RunnerOptions } from "../runtime/runner.js";
|
|
3
|
-
import type { IRProgram } from "../compile/ir.js";
|
|
4
|
-
import type { RuntimeResult } from "../runtime/results.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
): {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
1
|
+
import { useState, useCallback, useRef, useEffect } from "react";
|
|
2
|
+
import { YarnRunner, type RunnerOptions } from "../runtime/runner.js";
|
|
3
|
+
import type { IRProgram } from "../compile/ir.js";
|
|
4
|
+
import type { RuntimeResult } from "../runtime/results.js";
|
|
5
|
+
|
|
6
|
+
function haveFunctionsChanged(
|
|
7
|
+
prev: RunnerOptions["functions"],
|
|
8
|
+
next: RunnerOptions["functions"]
|
|
9
|
+
): boolean {
|
|
10
|
+
const prevFns = prev ?? {};
|
|
11
|
+
const nextFns = next ?? {};
|
|
12
|
+
|
|
13
|
+
const prevKeys = Object.keys(prevFns);
|
|
14
|
+
const nextKeys = Object.keys(nextFns);
|
|
15
|
+
|
|
16
|
+
if (prevKeys.length !== nextKeys.length) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
for (const key of prevKeys) {
|
|
21
|
+
if (!Object.prototype.hasOwnProperty.call(nextFns, key) || prevFns[key] !== nextFns[key]) {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function haveVariablesChanged(
|
|
30
|
+
prev: RunnerOptions["variables"],
|
|
31
|
+
next: RunnerOptions["variables"]
|
|
32
|
+
): boolean {
|
|
33
|
+
const prevVars = prev ?? {};
|
|
34
|
+
const nextVars = next ?? {};
|
|
35
|
+
return JSON.stringify(prevVars) !== JSON.stringify(nextVars);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function useYarnRunner(
|
|
39
|
+
program: IRProgram,
|
|
40
|
+
options: RunnerOptions
|
|
41
|
+
): {
|
|
42
|
+
result: RuntimeResult | null;
|
|
43
|
+
advance: (optionIndex?: number) => void;
|
|
44
|
+
runner: YarnRunner;
|
|
45
|
+
} {
|
|
46
|
+
const runnerRef = useRef<YarnRunner | null>(null);
|
|
47
|
+
const optionsRef = useRef(options);
|
|
48
|
+
const programRef = useRef(program);
|
|
49
|
+
const [result, setResult] = useState<RuntimeResult | null>(() => {
|
|
50
|
+
const runner = new YarnRunner(program, options);
|
|
51
|
+
runnerRef.current = runner;
|
|
52
|
+
optionsRef.current = options;
|
|
53
|
+
programRef.current = program;
|
|
54
|
+
return runner.currentResult;
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
const prevProgram = programRef.current;
|
|
59
|
+
const prevOptions = optionsRef.current;
|
|
60
|
+
|
|
61
|
+
const programChanged = prevProgram !== program;
|
|
62
|
+
const functionsChanged = haveFunctionsChanged(prevOptions?.functions, options.functions);
|
|
63
|
+
const startNodeChanged = prevOptions?.startAt !== options.startAt;
|
|
64
|
+
const variablesChanged = haveVariablesChanged(prevOptions?.variables, options.variables);
|
|
65
|
+
const handlersChanged =
|
|
66
|
+
prevOptions?.handleCommand !== options.handleCommand ||
|
|
67
|
+
prevOptions?.commandHandler !== options.commandHandler ||
|
|
68
|
+
prevOptions?.onStoryEnd !== options.onStoryEnd;
|
|
69
|
+
|
|
70
|
+
if (
|
|
71
|
+
!runnerRef.current ||
|
|
72
|
+
programChanged ||
|
|
73
|
+
functionsChanged ||
|
|
74
|
+
startNodeChanged ||
|
|
75
|
+
variablesChanged ||
|
|
76
|
+
handlersChanged
|
|
77
|
+
) {
|
|
78
|
+
const runner = new YarnRunner(program, options);
|
|
79
|
+
runnerRef.current = runner;
|
|
80
|
+
setResult(runner.currentResult);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
programRef.current = program;
|
|
84
|
+
optionsRef.current = options;
|
|
85
|
+
}, [program, options]);
|
|
86
|
+
|
|
87
|
+
const advance = useCallback((optionIndex?: number) => {
|
|
88
|
+
const runner = runnerRef.current;
|
|
89
|
+
if (!runner) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
runner.advance(optionIndex);
|
|
93
|
+
setResult(runner.currentResult);
|
|
94
|
+
}, []);
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
result,
|
|
98
|
+
advance,
|
|
99
|
+
runner: runnerRef.current as YarnRunner,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
47
102
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { test } from "node:test";
|
|
2
|
+
import { ok } from "node:assert";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { renderToStaticMarkup } from "react-dom/server";
|
|
5
|
+
import { parseYarn } from "../parse/parser.js";
|
|
6
|
+
import { compile } from "../compile/compiler.js";
|
|
7
|
+
import { DialogueView } from "../react/DialogueView.js";
|
|
8
|
+
|
|
9
|
+
test("DialogueView renders initial variables provided via props", () => {
|
|
10
|
+
const yarn = `
|
|
11
|
+
title: Start
|
|
12
|
+
---
|
|
13
|
+
Narrator: Hello {$playerName}!
|
|
14
|
+
===`;
|
|
15
|
+
|
|
16
|
+
const program = compile(parseYarn(yarn));
|
|
17
|
+
|
|
18
|
+
const html = renderToStaticMarkup(
|
|
19
|
+
<DialogueView program={program} startNode="Start" variables={{ playerName: "V" }} />
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
ok(
|
|
23
|
+
html.includes("Hello V"),
|
|
24
|
+
"Expected rendered dialogue to include the interpolated variable value from props"
|
|
25
|
+
);
|
|
26
|
+
});
|
package/src/tests/markup.test.ts
CHANGED
|
@@ -43,6 +43,23 @@ test("parseMarkup handles self-closing tags", () => {
|
|
|
43
43
|
);
|
|
44
44
|
});
|
|
45
45
|
|
|
46
|
+
test("parseMarkup handles br line breaks", () => {
|
|
47
|
+
const result = parseMarkup("Line one[br]Line two[/br][br/]Line three");
|
|
48
|
+
strictEqual(result.text, "Line one\nLine two\nLine three");
|
|
49
|
+
|
|
50
|
+
const brSegments = result.segments.filter(
|
|
51
|
+
(segment) => segment.selfClosing && segment.wrappers.some((wrapper) => wrapper.name === "br")
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
strictEqual(brSegments.length, 2);
|
|
55
|
+
ok(
|
|
56
|
+
brSegments.every((segment) =>
|
|
57
|
+
segment.wrappers.some((wrapper) => wrapper.name === "br" && wrapper.type === "default")
|
|
58
|
+
),
|
|
59
|
+
"Expected br wrappers to use default HTML type"
|
|
60
|
+
);
|
|
61
|
+
});
|
|
62
|
+
|
|
46
63
|
test("parseMarkup respects nomarkup blocks and escaping", () => {
|
|
47
64
|
const result = parseMarkup(`[nomarkup][b] raw [/b][/nomarkup] and \\[escaped\\]`);
|
|
48
65
|
strictEqual(result.text, "[b] raw [/b] and [escaped]");
|
|
@@ -59,4 +76,3 @@ function findSegment(result: MarkupParseResult, target: string) {
|
|
|
59
76
|
return text === target;
|
|
60
77
|
});
|
|
61
78
|
}
|
|
62
|
-
|