@elvishscout/mdstory 0.1.1 → 0.1.3
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/README.md +292 -2
- package/dist/base/chapter.js +73 -47
- package/dist/base/definitions.js +11 -2
- package/dist/base/index.js +1 -0
- package/dist/base/parser.js +86 -0
- package/dist/base/story.js +14 -96
- package/package.json +4 -3
- package/types/base/chapter.d.ts +19 -13
- package/types/base/definitions.d.ts +71 -4
- package/types/base/index.d.ts +1 -0
- package/types/base/parser.d.ts +2 -0
- package/types/base/story.d.ts +3 -16
package/README.md
CHANGED
|
@@ -1,5 +1,295 @@
|
|
|
1
1
|
# MdStory
|
|
2
2
|
|
|
3
|
-
An interactive
|
|
3
|
+
An interactive fiction scripting format based on Markdown and Handlebars.
|
|
4
4
|
|
|
5
|
-
Online demo
|
|
5
|
+
Online demo: <https://mdstory.elvish.cc>
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- Seamless intergration of Markdown, Handlebars and JavaScript.
|
|
10
|
+
- Ease-to-use API, for both Web and command line applications.
|
|
11
|
+
|
|
12
|
+
## File Format
|
|
13
|
+
|
|
14
|
+
### Metadata
|
|
15
|
+
|
|
16
|
+
The story file header may include YAML-formatted [Metadata](#type-metadata). Metadata defines the basic information and global configuration of the story.
|
|
17
|
+
|
|
18
|
+
### Chapters
|
|
19
|
+
|
|
20
|
+
Story files are divided into chapters by level-one headings. The `id` attribute of the heading serves as the unique identifier (`id`) for the chapter. If omitted, the heading content is used as the chapter `id` instead.
|
|
21
|
+
|
|
22
|
+
Handlebars template language is supported in the chapter content. During rendering, properties in `globals` and `assets` are added to the context for direct access by the template.
|
|
23
|
+
|
|
24
|
+
### Helpers
|
|
25
|
+
|
|
26
|
+
MdStory includes built-in Handlebars helpers for creating interactive components or various functionalities:
|
|
27
|
+
|
|
28
|
+
#### `{{input type name=default}}`
|
|
29
|
+
|
|
30
|
+
Creates an input of type `type` and assigns the input value (by default `default`) to a global variable named `name`. Supported input types include: `string`, `number`, `boolean`, and `object` (represented in a JSON string).
|
|
31
|
+
|
|
32
|
+
In HTML rendering mode, it generates a corresponding `<input>` element.
|
|
33
|
+
|
|
34
|
+
#### `{{set name=value}}`
|
|
35
|
+
|
|
36
|
+
Assigns the value `value` to a global variable named `name`.
|
|
37
|
+
|
|
38
|
+
#### `{{#nav target}}`
|
|
39
|
+
|
|
40
|
+
Creates an entry to navigate to another chapter identified by `target`.
|
|
41
|
+
|
|
42
|
+
In HTML rendering mode, it generates a corresponding `<button type="submit">` element.
|
|
43
|
+
|
|
44
|
+
#### `{{linebreak [n]}}`
|
|
45
|
+
|
|
46
|
+
Inserts `n` blank lines, where `n` defaults to `1`.
|
|
47
|
+
|
|
48
|
+
#### `{{asset name}}`
|
|
49
|
+
|
|
50
|
+
Retrieves the URL of a resource file named `name`. Basically it acts the same way as `{{name}}` except that it supports resource names with special characters.
|
|
51
|
+
|
|
52
|
+
#### `{{mime name}}`
|
|
53
|
+
|
|
54
|
+
Retrieves the MIME type of a resource file named `name`.
|
|
55
|
+
|
|
56
|
+
### JavaScript Scripts
|
|
57
|
+
|
|
58
|
+
JavaScript may be included into the story file using the `<script>` tag. Scripts before any level-one headings are considered global scripts, while those within chapters are considered chapter scripts. Only one `<script>` tag is allowed at the beginning of the story and in each chapter.
|
|
59
|
+
|
|
60
|
+
Scripts are evaluated during runtime using the `Function()` constructor, therefore you may use top-level `return` statements to return objects of type [StoryHooks](#type-storyhooks) or [ChapterHooks](#type-chapterhooks).
|
|
61
|
+
|
|
62
|
+
### Stylesheets
|
|
63
|
+
|
|
64
|
+
CSS stylesheets may be included using the `<style>` tag, they will be extracted and gathered into the `stylesheet` property of [StoryBody](#type-storybody) during parsing.
|
|
65
|
+
|
|
66
|
+
## Examples
|
|
67
|
+
|
|
68
|
+
Here are some [examples](./examples/) of story files.
|
|
69
|
+
|
|
70
|
+
## API
|
|
71
|
+
|
|
72
|
+
### `type Value`
|
|
73
|
+
|
|
74
|
+
The type of variables in MdStory, basically all types allowed in JSON, including primitive values (`string`, `number`, `boolean`, `null`) and nested `array`s and `object`s. Functions and `undefined` are not supported.
|
|
75
|
+
|
|
76
|
+
### `type Scope`
|
|
77
|
+
|
|
78
|
+
An object of variable values by their names, used to store global variables or input fields.
|
|
79
|
+
|
|
80
|
+
### `type Asset`
|
|
81
|
+
|
|
82
|
+
A referenceable resource file.
|
|
83
|
+
|
|
84
|
+
#### Properties
|
|
85
|
+
|
|
86
|
+
- `url`: The URL of the resource.
|
|
87
|
+
- `mime (optional)`: The MIME type of the resource.
|
|
88
|
+
|
|
89
|
+
### `type Metadata`
|
|
90
|
+
|
|
91
|
+
The Metadata of the story.
|
|
92
|
+
|
|
93
|
+
#### Properties
|
|
94
|
+
|
|
95
|
+
- `title (optional)`: The story title.
|
|
96
|
+
- `author (optional)`: The author's name.
|
|
97
|
+
- `email (optional)`: The author's email address.
|
|
98
|
+
- `globals (optional)`: An object of type [Scope](#type-scope) containing initial values of global variables.
|
|
99
|
+
- `assets (optional)`: An object of resource names and [Asset](#type-asset) objects, containing all assets used in the story.
|
|
100
|
+
|
|
101
|
+
### `type ChapterBody`
|
|
102
|
+
|
|
103
|
+
The structured representation of chapter content.
|
|
104
|
+
|
|
105
|
+
#### Properties
|
|
106
|
+
|
|
107
|
+
- `title`: The chapter title.
|
|
108
|
+
- `template`: The Handlebars template for rendering.
|
|
109
|
+
- `script`: The JavaScript script for the chapter.
|
|
110
|
+
|
|
111
|
+
### `type StoryBody`
|
|
112
|
+
|
|
113
|
+
The structured representation of story content.
|
|
114
|
+
|
|
115
|
+
#### Properties
|
|
116
|
+
|
|
117
|
+
- `metadata`: The story [Metadata](#type-metadata).
|
|
118
|
+
- `chapters`: An object of [ChapterBody](#type-chapterbody) objects by their `id`s.
|
|
119
|
+
- `entry`: The `id` of the entry chapter of the story, which may be `null`.
|
|
120
|
+
- `script`: The global JavaScript script of the story.
|
|
121
|
+
- `stylesheet`: The global stylesheet of the story.
|
|
122
|
+
|
|
123
|
+
### `type StoryHooks`
|
|
124
|
+
|
|
125
|
+
Defines the global lifecycle hooks of the story.
|
|
126
|
+
|
|
127
|
+
#### Properties
|
|
128
|
+
|
|
129
|
+
- `onStart (optional)`: Called when the story starts.
|
|
130
|
+
- Parameters:
|
|
131
|
+
- `globals`: The initial values of global variables.
|
|
132
|
+
- Return value: Updated `globals` or `void`.
|
|
133
|
+
|
|
134
|
+
### `type ChapterHooks`
|
|
135
|
+
|
|
136
|
+
Defines the lifecycle hooks of a chapter.
|
|
137
|
+
|
|
138
|
+
#### Properties
|
|
139
|
+
|
|
140
|
+
- `onEnter (optional)`: Called when entering a chapter.
|
|
141
|
+
- Parameters:
|
|
142
|
+
- `globals`: Current global variables.
|
|
143
|
+
- Return value: Updated `globals` or `void`, effective only during the lifecycle of current chapter.
|
|
144
|
+
- `onLeave (optional)`: Called when leaving a chapter.
|
|
145
|
+
- Parameters:
|
|
146
|
+
- `globals`: Current global variables.
|
|
147
|
+
- `fields`: Input fields from current chapter.
|
|
148
|
+
- Return value: Updated `globals` or `void`.
|
|
149
|
+
- `onNavigate (optional)`: Called during chapter navigation.
|
|
150
|
+
- Parameters:
|
|
151
|
+
- `target` : `id` of target chapter.
|
|
152
|
+
- `globals`: Current global variables.
|
|
153
|
+
- `fields`: Input fields from current chapter.
|
|
154
|
+
- Return value: Updated `target` or `void`.
|
|
155
|
+
|
|
156
|
+
### `type Renderer`
|
|
157
|
+
|
|
158
|
+
Defines the renderer interface for generating outputs in different formats.
|
|
159
|
+
|
|
160
|
+
#### Methods
|
|
161
|
+
|
|
162
|
+
- `input({ name, type, value }) (optional)`: Generates the rendering result of an input field.
|
|
163
|
+
|
|
164
|
+
- Parameters:
|
|
165
|
+
- `name`: The name of the variable.
|
|
166
|
+
- `type`: The type of the variable.
|
|
167
|
+
- `value`: The default value of the variable.
|
|
168
|
+
- Return value: The rendered input field.
|
|
169
|
+
|
|
170
|
+
- `nav({ target, children }) (optional)`: Generates the rendering result of chapter navigation.
|
|
171
|
+
- Parameters:
|
|
172
|
+
- `target`: The `id` of the target chapter.
|
|
173
|
+
- `children`: The text content of the navigation button.
|
|
174
|
+
- Return value: The rendered navigation button.
|
|
175
|
+
|
|
176
|
+
### `type RenderOptions`
|
|
177
|
+
|
|
178
|
+
Defines rendering options.
|
|
179
|
+
|
|
180
|
+
#### Properties
|
|
181
|
+
|
|
182
|
+
- `format`: The rendering format, which may be `"markdown"`, `"html"`, or a custom [Renderer](#type-renderer).
|
|
183
|
+
- `html (optional)`: Whether to parse Markdown into HTML, defaults to `false`.
|
|
184
|
+
|
|
185
|
+
### `type RenderResult`
|
|
186
|
+
|
|
187
|
+
The rendering result, containing the rendered text and extracted fields.
|
|
188
|
+
|
|
189
|
+
#### Properties
|
|
190
|
+
|
|
191
|
+
- `text`: The rendered text content.
|
|
192
|
+
- `inputs`: An array of input fields, each containing:
|
|
193
|
+
- `name`: The name of the variable.
|
|
194
|
+
- `type`: The type of the variable.
|
|
195
|
+
- `value`: The default value of the variable.
|
|
196
|
+
- `sets`: An array of set fields, each containing:
|
|
197
|
+
- `name`: The name of the variable.
|
|
198
|
+
- `type`: The type of the variable.
|
|
199
|
+
- `value`: The value of the variable.
|
|
200
|
+
- `navs`: An array of navigation fields, each containing:
|
|
201
|
+
- `text`: The text content of the navigation button.
|
|
202
|
+
- `target`: The `id` of the target chapter.
|
|
203
|
+
|
|
204
|
+
### `type ChapterOptions`
|
|
205
|
+
|
|
206
|
+
Defines the initialization options of a chapter.
|
|
207
|
+
|
|
208
|
+
#### Properties
|
|
209
|
+
|
|
210
|
+
- `id`: The unique identifier of the chapter.
|
|
211
|
+
- `title`: The title of the chapter.
|
|
212
|
+
- `template`: The Handlebars template for rendering.
|
|
213
|
+
- `hooks`: An object of type [ChapterHooks](#type-chapterhooks).
|
|
214
|
+
|
|
215
|
+
### `class Chapter`
|
|
216
|
+
|
|
217
|
+
Defines a chapter.
|
|
218
|
+
|
|
219
|
+
#### Properties
|
|
220
|
+
|
|
221
|
+
- `id`: The unique identifier of the chapter.
|
|
222
|
+
- `title`: The title of the chapter.
|
|
223
|
+
- `template`: The Handlebars template for rendering.
|
|
224
|
+
- `hooks`: Chapter hooks of type [ChapterHooks](#type-chapterhooks).
|
|
225
|
+
|
|
226
|
+
#### Methods
|
|
227
|
+
|
|
228
|
+
- `constructor(options)`: Initializes the chapter instance.
|
|
229
|
+
- Parameters:
|
|
230
|
+
- `options`: The chapter options of type [ChapterOptions](#type-chapteroptions).
|
|
231
|
+
- `render(scope, assets, options)`: Renders the story content.
|
|
232
|
+
- Parameters:
|
|
233
|
+
- `scope`: The rendering context.
|
|
234
|
+
- `assets`: The story assets.
|
|
235
|
+
- `options`: The rendering options of type [RenderOptions](#type-renderoptions).
|
|
236
|
+
- Return value: The rendering result of type [RenderResult](#type-renderresult).
|
|
237
|
+
|
|
238
|
+
### `type StoryPrompt`
|
|
239
|
+
|
|
240
|
+
Defines the prompt function of the story, used to handle user input.
|
|
241
|
+
|
|
242
|
+
#### Parameters
|
|
243
|
+
|
|
244
|
+
- `props`: An object containing the current chapter and rendering result.
|
|
245
|
+
- `chapter`: Current chapter.
|
|
246
|
+
- `text`: The rendered chapter content.
|
|
247
|
+
- `inputs`, `sets`, `navs`: Fields from the rendering result.
|
|
248
|
+
|
|
249
|
+
#### Return value
|
|
250
|
+
|
|
251
|
+
- A `Promise` resolving to one of the following forms:
|
|
252
|
+
- `{ target, updates }`: The `id` of the target chapter and updated global variables.
|
|
253
|
+
- `FormData`: Contains the form data of user input.
|
|
254
|
+
|
|
255
|
+
### `class StoryBase`
|
|
256
|
+
|
|
257
|
+
Defines the base class of the story, containing the core logic of the story.
|
|
258
|
+
|
|
259
|
+
#### Properties
|
|
260
|
+
|
|
261
|
+
- `metadata`: Story [Metadata](#type-metadata).
|
|
262
|
+
- `globals`: Global variables.
|
|
263
|
+
- `chapters`: An object of chapters by their `id`s.
|
|
264
|
+
- `entry`: The entry chapter of the story.
|
|
265
|
+
- `hooks`: An object of type [StoryHooks](#type-storyhooks).
|
|
266
|
+
- `stylesheet`: The global stylesheet of the story.
|
|
267
|
+
- `assets`: An object of asset files by their alias names.
|
|
268
|
+
|
|
269
|
+
#### Methods
|
|
270
|
+
|
|
271
|
+
- `constructor({ metadata, chapters, entry, script, stylesheet })`: Initializes the story instance.
|
|
272
|
+
- `play(prompt, options)`: Starts playing the story.
|
|
273
|
+
- Parameters:
|
|
274
|
+
- `prompt`: A function of type [StoryPrompt](#type-storyprompt).
|
|
275
|
+
- `options`: An object of type [RenderOptions](#type-renderoptions).
|
|
276
|
+
|
|
277
|
+
### `function parseStoryContent`
|
|
278
|
+
|
|
279
|
+
Parses the story content in Markdown format.
|
|
280
|
+
|
|
281
|
+
#### Parameters
|
|
282
|
+
|
|
283
|
+
- `content`: The story content in Markdown format.
|
|
284
|
+
|
|
285
|
+
#### Return value
|
|
286
|
+
|
|
287
|
+
- An object of type [StoryBody](#type-storybody).
|
|
288
|
+
|
|
289
|
+
### `class Story`
|
|
290
|
+
|
|
291
|
+
Inherits from [StoryBase](#class-storybase), creating a story instance from the story content in Markdown format.
|
|
292
|
+
|
|
293
|
+
#### Methods
|
|
294
|
+
|
|
295
|
+
- `constructor(content: string)`: Initializes the story instance.
|
package/dist/base/chapter.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Handlebars from "handlebars";
|
|
2
2
|
import MarkdownIt from "markdown-it";
|
|
3
3
|
import pluginAttrs from "markdown-it-attrs";
|
|
4
|
+
const escapeHtml = (text) => text.replace(/[<>&'"]/g, (ch) => `&#${ch.charCodeAt(0)};`);
|
|
4
5
|
const valueType = (value) => {
|
|
5
6
|
if (typeof value === "string") {
|
|
6
7
|
return "string";
|
|
@@ -13,7 +14,6 @@ const valueType = (value) => {
|
|
|
13
14
|
}
|
|
14
15
|
return "object";
|
|
15
16
|
};
|
|
16
|
-
const escapeHtml = (text) => text.replace(/[<>&'"]/g, (ch) => `&#${ch.charCodeAt(0)};`);
|
|
17
17
|
const createElementHtml = (tag, attrs, children) => {
|
|
18
18
|
// prettier-ignore
|
|
19
19
|
const voidTags = [
|
|
@@ -21,88 +21,102 @@ const createElementHtml = (tag, attrs, children) => {
|
|
|
21
21
|
"link", "meta", "param", "source", "track", "wbr",
|
|
22
22
|
];
|
|
23
23
|
const attrText = Object.entries(attrs)
|
|
24
|
-
.filter(([, value]) => value !== undefined)
|
|
25
24
|
.map(([name, value]) => {
|
|
26
25
|
if (typeof value === "boolean") {
|
|
27
26
|
value = value ? "" : undefined;
|
|
28
27
|
}
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
if (value === undefined) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
if (value) {
|
|
32
|
+
const escapedValue = escapeHtml(value ?? "");
|
|
33
|
+
return `${name}="${escapedValue}"`;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
return name;
|
|
37
|
+
}
|
|
31
38
|
})
|
|
39
|
+
.filter((attr) => attr !== null)
|
|
32
40
|
.join(" ");
|
|
33
41
|
if (voidTags.includes(tag)) {
|
|
34
42
|
return `<${tag} ${attrText}>`;
|
|
35
43
|
}
|
|
36
44
|
return `<${tag} ${attrText}>${children ?? ""}</${tag}>`;
|
|
37
45
|
};
|
|
38
|
-
const createInputHtml = ({
|
|
39
|
-
const tag = tagMap["input"] ?? "input";
|
|
46
|
+
const createInputHtml = ({ name, type, value }) => {
|
|
40
47
|
const inputType = type === "boolean" ? "checkbox" : "text";
|
|
41
48
|
const inputAttrs = {
|
|
42
49
|
name,
|
|
43
50
|
type: inputType,
|
|
44
51
|
value: inputType !== "checkbox" ? (type === "object" ? JSON.stringify(value) : String(value)) : undefined,
|
|
45
52
|
checked: inputType === "checkbox" && value ? "" : undefined,
|
|
46
|
-
required,
|
|
47
|
-
readonly,
|
|
48
53
|
"aria-label": name,
|
|
49
54
|
};
|
|
50
|
-
return createElementHtml(
|
|
55
|
+
return createElementHtml("input", inputAttrs);
|
|
51
56
|
};
|
|
52
|
-
const createSubmitButtonHtml = ({
|
|
53
|
-
const tag = tagMap["button"] ?? "button";
|
|
57
|
+
const createSubmitButtonHtml = ({ target, children }) => {
|
|
54
58
|
const buttonAttrs = {
|
|
55
59
|
name: "@target",
|
|
56
60
|
type: "submit",
|
|
57
61
|
value: target,
|
|
58
62
|
};
|
|
59
|
-
return createElementHtml(
|
|
63
|
+
return createElementHtml("button", buttonAttrs, children);
|
|
60
64
|
};
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
const markdownRenderer = {
|
|
66
|
+
input({ name, type }) {
|
|
67
|
+
if (type === "boolean") {
|
|
68
|
+
return `[? _${name}_]`;
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
return `[> _${name}_]`;
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
nav({ children }) {
|
|
75
|
+
return `[@ __${children}__]`;
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
const htmlRenderer = {
|
|
79
|
+
input({ type, name, value }) {
|
|
80
|
+
return createInputHtml({ name, type, value });
|
|
81
|
+
},
|
|
82
|
+
nav({ target, children }) {
|
|
83
|
+
return createSubmitButtonHtml({ target: target ?? "", children });
|
|
84
|
+
},
|
|
66
85
|
};
|
|
67
|
-
const useHelper = ({ inputs, sets, navs },
|
|
86
|
+
const useHelper = ({ inputs, sets, navs }, assets, renderer) => {
|
|
68
87
|
return {
|
|
69
88
|
input(type, opt) {
|
|
70
|
-
let result = "";
|
|
71
89
|
for (const name in opt.hash) {
|
|
72
90
|
const value = opt.hash[name];
|
|
73
91
|
inputs.push({ name, type, value });
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
result = createInputMarkdown({ name, type });
|
|
79
|
-
}
|
|
80
|
-
break;
|
|
92
|
+
const result = renderer.input ? renderer.input({ name, type, value }) : "";
|
|
93
|
+
return new Handlebars.SafeString(result);
|
|
81
94
|
}
|
|
82
|
-
return
|
|
95
|
+
return "";
|
|
83
96
|
},
|
|
84
97
|
set(opt) {
|
|
85
|
-
const
|
|
86
|
-
.
|
|
98
|
+
for (const name in opt.hash) {
|
|
99
|
+
const value = opt.hash[name];
|
|
87
100
|
const type = valueType(value);
|
|
88
101
|
sets.push({ name, type, value });
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
return "";
|
|
93
|
-
})
|
|
94
|
-
.join("");
|
|
95
|
-
return new Handlebars.SafeString(result);
|
|
102
|
+
}
|
|
103
|
+
return "";
|
|
96
104
|
},
|
|
97
105
|
nav(target, opt) {
|
|
98
|
-
let result = "";
|
|
99
106
|
const text = opt.fn(this).trim();
|
|
100
107
|
navs.push({ text, target });
|
|
101
|
-
|
|
102
|
-
result = createSubmitButtonHtml({ target: target ?? "", children: text, ...options });
|
|
103
|
-
}
|
|
108
|
+
const result = renderer.nav ? renderer.nav({ target, children: text }) : "";
|
|
104
109
|
return new Handlebars.SafeString(result);
|
|
105
110
|
},
|
|
111
|
+
asset(name) {
|
|
112
|
+
return new Handlebars.SafeString(assets[name]?.url ?? "");
|
|
113
|
+
},
|
|
114
|
+
mime(name) {
|
|
115
|
+
return new Handlebars.SafeString(assets[name]?.mime ?? "");
|
|
116
|
+
},
|
|
117
|
+
linebreak(n) {
|
|
118
|
+
return new Handlebars.SafeString("<br>".repeat(n ?? 1));
|
|
119
|
+
},
|
|
106
120
|
};
|
|
107
121
|
};
|
|
108
122
|
export class Chapter {
|
|
@@ -112,19 +126,31 @@ export class Chapter {
|
|
|
112
126
|
this.template = template;
|
|
113
127
|
this.hooks = hooks;
|
|
114
128
|
}
|
|
115
|
-
render(scope,
|
|
116
|
-
|
|
129
|
+
render(scope, assets = {}, { format, html }) {
|
|
130
|
+
let renderer;
|
|
131
|
+
if (format === "markdown") {
|
|
132
|
+
renderer = markdownRenderer;
|
|
133
|
+
}
|
|
134
|
+
else if (format === "html") {
|
|
135
|
+
renderer = htmlRenderer;
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
renderer = format;
|
|
139
|
+
}
|
|
117
140
|
const fields = {
|
|
118
141
|
inputs: [],
|
|
119
142
|
sets: [],
|
|
120
143
|
navs: [],
|
|
121
144
|
};
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
145
|
+
const helpers = useHelper(fields, assets, renderer);
|
|
146
|
+
let text;
|
|
147
|
+
if (html) {
|
|
148
|
+
const md = new MarkdownIt({ html: true }).use(pluginAttrs);
|
|
149
|
+
text = Handlebars.compile(this.template)(scope, { helpers });
|
|
126
150
|
text = md.render(text);
|
|
127
|
-
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
text = Handlebars.compile(this.template, { noEscape: true })(scope, { helpers });
|
|
128
154
|
}
|
|
129
155
|
return { text, ...fields };
|
|
130
156
|
}
|
package/dist/base/definitions.js
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
export const ValueSchema = z.any().transform((v) => v);
|
|
3
3
|
export const ScopeSchema = z.record(ValueSchema);
|
|
4
|
+
const AssetObjectSchema = z.object({ url: z.string(), mime: z.string().optional() });
|
|
5
|
+
export const AssetSchema = z.union([
|
|
6
|
+
z.string().transform((url) => AssetObjectSchema.parse({ url, mime: undefined })),
|
|
7
|
+
AssetObjectSchema,
|
|
8
|
+
]);
|
|
9
|
+
export const AssetsSchema = z.record(AssetSchema);
|
|
4
10
|
export const MetadataSchema = z.object({
|
|
5
|
-
title: z.string().
|
|
6
|
-
|
|
11
|
+
title: z.string().optional(),
|
|
12
|
+
author: z.string().optional(),
|
|
13
|
+
email: z.string().optional(),
|
|
14
|
+
globals: ScopeSchema.optional(),
|
|
15
|
+
assets: AssetsSchema.optional(),
|
|
7
16
|
});
|
|
8
17
|
const TargetSchema = z.string().or(z.null());
|
|
9
18
|
export const StoryHooksSchema = z
|
package/dist/base/index.js
CHANGED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import yaml from "js-yaml";
|
|
2
|
+
import MarkdownIt from "markdown-it";
|
|
3
|
+
import pluginFrontMatter from "markdown-it-front-matter";
|
|
4
|
+
import pluginAttrs from "markdown-it-attrs";
|
|
5
|
+
import { MetadataSchema } from "./definitions.js";
|
|
6
|
+
import { DuplicateIdError, EmptyChapterIdError, InvalidMetadataError } from "./error.js";
|
|
7
|
+
export const parseStoryContent = (content) => {
|
|
8
|
+
const md = new MarkdownIt({ html: true }).use(pluginAttrs).use(pluginFrontMatter, () => { });
|
|
9
|
+
const tokens = md.parse(content, {});
|
|
10
|
+
let metadata = MetadataSchema.parse({});
|
|
11
|
+
let storyScript = "";
|
|
12
|
+
let stylesheet = "";
|
|
13
|
+
const ignoredRanges = [];
|
|
14
|
+
const divisions = [];
|
|
15
|
+
tokens.forEach((token, i) => {
|
|
16
|
+
if (token.type === "front_matter" && token.meta) {
|
|
17
|
+
try {
|
|
18
|
+
const frontMatter = MetadataSchema.parse(yaml.load(token.meta));
|
|
19
|
+
metadata = Object.assign(metadata, frontMatter);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
throw new InvalidMetadataError(token.meta);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
else if (token.type === "heading_open" && token.tag === "h1" && token.level === 0 && token.map) {
|
|
26
|
+
const lineno = token.map[0];
|
|
27
|
+
let id = token.attrs?.find(([key]) => key === "id")?.[1] ?? "";
|
|
28
|
+
let title = "";
|
|
29
|
+
const nextToken = tokens[i + 1];
|
|
30
|
+
if (nextToken && nextToken.type === "inline") {
|
|
31
|
+
const content = nextToken.content.trim();
|
|
32
|
+
id || (id = content);
|
|
33
|
+
title = content;
|
|
34
|
+
}
|
|
35
|
+
if (!id) {
|
|
36
|
+
throw new EmptyChapterIdError();
|
|
37
|
+
}
|
|
38
|
+
if (divisions.find(({ id: _id }) => id === _id)) {
|
|
39
|
+
throw new DuplicateIdError(id);
|
|
40
|
+
}
|
|
41
|
+
divisions.push({ id, title, lineno, script: "" });
|
|
42
|
+
}
|
|
43
|
+
else if (token.type === "html_block" && token.map) {
|
|
44
|
+
let regres;
|
|
45
|
+
if ((regres = /^[\s]*<script>(.*)<\/script>[\s]*$/s.exec(token.content))) {
|
|
46
|
+
const script = regres[1].trim();
|
|
47
|
+
if (script) {
|
|
48
|
+
if (divisions.length === 0) {
|
|
49
|
+
storyScript = script;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
divisions[divisions.length - 1].script = script;
|
|
53
|
+
}
|
|
54
|
+
ignoredRanges.push(token.map);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
else if ((regres = /^[\s]*<style>(.*)<\/style>[\s]*$/s.exec(token.content))) {
|
|
58
|
+
const style = regres[1].trim();
|
|
59
|
+
stylesheet += style;
|
|
60
|
+
ignoredRanges.push(token.map);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
const lines = content.split("\n").map((line, i) => {
|
|
65
|
+
if (ignoredRanges.find(([from, to]) => i >= from && i < to)) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
return line;
|
|
69
|
+
});
|
|
70
|
+
const chapterEntries = divisions.map(({ id, title, lineno, script }, i) => {
|
|
71
|
+
const template = lines
|
|
72
|
+
.slice(lineno, divisions[i + 1]?.lineno)
|
|
73
|
+
.filter((line) => line !== null)
|
|
74
|
+
.join("\n");
|
|
75
|
+
return [id, { title, template, script }];
|
|
76
|
+
});
|
|
77
|
+
const chapters = Object.fromEntries(chapterEntries);
|
|
78
|
+
const entry = chapterEntries[0]?.[0] || null;
|
|
79
|
+
return {
|
|
80
|
+
metadata,
|
|
81
|
+
chapters,
|
|
82
|
+
entry,
|
|
83
|
+
script: storyScript,
|
|
84
|
+
stylesheet,
|
|
85
|
+
};
|
|
86
|
+
};
|
package/dist/base/story.js
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import MarkdownIt from "markdown-it";
|
|
3
|
-
import pluginFrontMatter from "markdown-it-front-matter";
|
|
4
|
-
import pluginAttrs from "markdown-it-attrs";
|
|
5
|
-
import { MetadataSchema, StoryHooksSchema, ChapterHooksSchema, } from "./definitions.js";
|
|
1
|
+
import { ChapterHooksSchema, StoryHooksSchema, } from "./definitions.js";
|
|
6
2
|
import { Chapter } from "./chapter.js";
|
|
7
|
-
import { ChapterNotFoundError,
|
|
3
|
+
import { ChapterNotFoundError, InvalidInputError } from "./error.js";
|
|
8
4
|
const parstInput = (type, text) => {
|
|
9
5
|
if (type === "boolean") {
|
|
10
6
|
return text === "on";
|
|
@@ -30,114 +26,36 @@ const parseFormData = (formData, { inputs, sets }) => {
|
|
|
30
26
|
}));
|
|
31
27
|
return { target, updates };
|
|
32
28
|
};
|
|
33
|
-
export const parseStoryContent = (content) => {
|
|
34
|
-
const md = new MarkdownIt({ html: true }).use(pluginAttrs).use(pluginFrontMatter, () => { });
|
|
35
|
-
const tokens = md.parse(content, {});
|
|
36
|
-
let metadata = MetadataSchema.parse({});
|
|
37
|
-
let storyScript = "";
|
|
38
|
-
let stylesheet = "";
|
|
39
|
-
const ignoredRanges = [];
|
|
40
|
-
const divisions = [];
|
|
41
|
-
tokens.forEach((token, i) => {
|
|
42
|
-
if (token.type === "front_matter" && token.meta) {
|
|
43
|
-
try {
|
|
44
|
-
const frontMatter = MetadataSchema.parse(yaml.load(token.meta));
|
|
45
|
-
metadata = { ...metadata, ...frontMatter };
|
|
46
|
-
}
|
|
47
|
-
catch {
|
|
48
|
-
throw new InvalidMetadataError(token.meta);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
else if (token.type === "heading_open" && token.tag === "h1" && token.level === 0 && token.map) {
|
|
52
|
-
const lineno = token.map[0];
|
|
53
|
-
let id = token.attrs?.find(([key]) => key === "id")?.[1] ?? "";
|
|
54
|
-
let title = "";
|
|
55
|
-
const nextToken = tokens[i + 1];
|
|
56
|
-
if (nextToken && nextToken.type === "inline") {
|
|
57
|
-
const content = nextToken.content.trim();
|
|
58
|
-
id || (id = content);
|
|
59
|
-
title = content;
|
|
60
|
-
}
|
|
61
|
-
if (!id) {
|
|
62
|
-
throw new EmptyChapterIdError();
|
|
63
|
-
}
|
|
64
|
-
if (divisions.find(({ id: _id }) => id === _id)) {
|
|
65
|
-
throw new DuplicateIdError(id);
|
|
66
|
-
}
|
|
67
|
-
divisions.push({ id, title, lineno, script: "" });
|
|
68
|
-
}
|
|
69
|
-
else if (token.type === "html_block" && token.map) {
|
|
70
|
-
let regres;
|
|
71
|
-
if ((regres = /^[\s]*<script>(.*)<\/script>[\s]*$/s.exec(token.content))) {
|
|
72
|
-
const script = regres[1].trim();
|
|
73
|
-
if (script) {
|
|
74
|
-
if (divisions.length === 0) {
|
|
75
|
-
storyScript = script;
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
divisions[divisions.length - 1].script = script;
|
|
79
|
-
}
|
|
80
|
-
ignoredRanges.push(token.map);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
else if ((regres = /^[\s]*<style>(.*)<\/style>[\s]*$/s.exec(token.content))) {
|
|
84
|
-
const style = regres[1].trim();
|
|
85
|
-
stylesheet += style;
|
|
86
|
-
ignoredRanges.push(token.map);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
const lines = content.split("\n").map((line, i) => {
|
|
91
|
-
if (ignoredRanges.find(([from, to]) => i >= from && i < to)) {
|
|
92
|
-
return null;
|
|
93
|
-
}
|
|
94
|
-
return line;
|
|
95
|
-
});
|
|
96
|
-
const chapterEntries = divisions.map(({ id, title, lineno, script }, i) => {
|
|
97
|
-
const template = lines
|
|
98
|
-
.slice(lineno, divisions[i + 1]?.lineno)
|
|
99
|
-
.filter((line) => line !== null)
|
|
100
|
-
.join("\n");
|
|
101
|
-
const hooks = script ? ChapterHooksSchema.parse(new Function(script)()) : {};
|
|
102
|
-
return [id, { title, template, hooks }];
|
|
103
|
-
});
|
|
104
|
-
const chapters = Object.fromEntries(chapterEntries);
|
|
105
|
-
const entry = chapterEntries[0]?.[0] || null;
|
|
106
|
-
const hooks = storyScript ? StoryHooksSchema.parse(new Function(storyScript)()) : {};
|
|
107
|
-
return {
|
|
108
|
-
metadata,
|
|
109
|
-
chapters,
|
|
110
|
-
entry,
|
|
111
|
-
hooks,
|
|
112
|
-
stylesheet,
|
|
113
|
-
};
|
|
114
|
-
};
|
|
115
29
|
export class StoryBase {
|
|
116
|
-
constructor({ metadata, chapters, entry,
|
|
117
|
-
const realChapters = Object.fromEntries(Object.entries(chapters).map(([id,
|
|
118
|
-
|
|
30
|
+
constructor({ metadata, chapters, entry, script, stylesheet }) {
|
|
31
|
+
const realChapters = Object.fromEntries(Object.entries(chapters).map(([id, { title, template, script }]) => {
|
|
32
|
+
const hooks = (script && ChapterHooksSchema.parse(new Function(script)())) || {};
|
|
33
|
+
return [id, new Chapter({ id, title, template, hooks })];
|
|
119
34
|
}));
|
|
120
35
|
this.metadata = metadata;
|
|
121
|
-
this.globals = metadata.globals;
|
|
36
|
+
this.globals = metadata.globals ?? {};
|
|
122
37
|
this.chapters = realChapters;
|
|
123
38
|
this.entry = (entry && realChapters[entry]) || null;
|
|
124
|
-
this.hooks =
|
|
39
|
+
this.hooks = (script && StoryHooksSchema.parse(new Function(script)())) || {};
|
|
125
40
|
this.stylesheet = stylesheet;
|
|
41
|
+
this.assets = metadata.assets ?? {};
|
|
126
42
|
}
|
|
127
43
|
async play(prompt, options) {
|
|
128
44
|
if (this.hooks.onStart) {
|
|
129
45
|
this.hooks.onStart(this.globals);
|
|
130
46
|
}
|
|
47
|
+
const assetsUrl = Object.fromEntries(Object.entries(this.assets).map(([name, { url }]) => [name, url]));
|
|
131
48
|
let chapter = this.entry;
|
|
132
49
|
while (chapter) {
|
|
133
|
-
let
|
|
50
|
+
let scope = this.globals;
|
|
51
|
+
scope = Object.assign(scope, assetsUrl);
|
|
134
52
|
if (chapter.hooks.onEnter) {
|
|
135
53
|
const modified = chapter.hooks.onEnter(this.globals);
|
|
136
54
|
if (modified !== undefined) {
|
|
137
|
-
|
|
55
|
+
scope = Object.assign(scope, modified);
|
|
138
56
|
}
|
|
139
57
|
}
|
|
140
|
-
const renderResult = chapter.render(
|
|
58
|
+
const renderResult = chapter.render(scope, this.assets, options);
|
|
141
59
|
const promptResult = await prompt({ chapter, ...renderResult });
|
|
142
60
|
const { target, updates } = promptResult instanceof FormData ? parseFormData(promptResult, renderResult) : promptResult;
|
|
143
61
|
let modifiedTarget = target;
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elvishscout/mdstory",
|
|
3
|
-
"
|
|
4
|
-
"
|
|
3
|
+
"repository": "https://github.com/ElvishScout/mdstory.git",
|
|
4
|
+
"version": "0.1.3",
|
|
5
|
+
"description": "An interactive fiction scripting format based on Markdown and Handlebars.",
|
|
5
6
|
"main": "./dist/index.js",
|
|
6
7
|
"type": "module",
|
|
7
8
|
"files": [
|
|
@@ -37,4 +38,4 @@
|
|
|
37
38
|
],
|
|
38
39
|
"author": "Jiakai Jiang",
|
|
39
40
|
"license": "ISC"
|
|
40
|
-
}
|
|
41
|
+
}
|
package/types/base/chapter.d.ts
CHANGED
|
@@ -1,13 +1,22 @@
|
|
|
1
|
-
import { ValueType, Value, ChapterHooks, Scope } from "./definitions.js";
|
|
2
|
-
type
|
|
3
|
-
type
|
|
4
|
-
|
|
1
|
+
import { ValueType, Value, ChapterHooks, Scope, Asset } from "./definitions.js";
|
|
2
|
+
export type Renderer = {
|
|
3
|
+
input?: ({ name, type, value }: {
|
|
4
|
+
name: string;
|
|
5
|
+
type: ValueType;
|
|
6
|
+
value: string;
|
|
7
|
+
}) => string;
|
|
8
|
+
nav?: ({ target, children }: {
|
|
9
|
+
target: string | null;
|
|
10
|
+
children: string;
|
|
11
|
+
}) => string;
|
|
5
12
|
};
|
|
6
|
-
export type RenderOptions =
|
|
7
|
-
format: "markdown";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
13
|
+
export type RenderOptions = {
|
|
14
|
+
format: "markdown" | "html" | Renderer;
|
|
15
|
+
html?: boolean;
|
|
16
|
+
};
|
|
17
|
+
export type RenderResult = {
|
|
18
|
+
text: string;
|
|
19
|
+
} & Fields;
|
|
11
20
|
type Fields = {
|
|
12
21
|
inputs: {
|
|
13
22
|
name: string;
|
|
@@ -24,9 +33,6 @@ type Fields = {
|
|
|
24
33
|
target: string | null;
|
|
25
34
|
}[];
|
|
26
35
|
};
|
|
27
|
-
export type RenderResult = {
|
|
28
|
-
text: string;
|
|
29
|
-
} & Fields;
|
|
30
36
|
export type ChapterOptions = {
|
|
31
37
|
id: string;
|
|
32
38
|
title: string;
|
|
@@ -39,6 +45,6 @@ export declare class Chapter {
|
|
|
39
45
|
template: string;
|
|
40
46
|
hooks: ChapterHooks;
|
|
41
47
|
constructor({ id, title, template, hooks }: ChapterOptions);
|
|
42
|
-
render(scope: Scope,
|
|
48
|
+
render(scope: Scope, assets: Record<string, Asset> | undefined, { format, html }: RenderOptions): RenderResult;
|
|
43
49
|
}
|
|
44
50
|
export {};
|
|
@@ -7,15 +7,68 @@ type JsonObject = {
|
|
|
7
7
|
type JsonValue = JsonPrimitive | JsonArray | JsonObject;
|
|
8
8
|
export declare const ValueSchema: z.ZodEffects<z.ZodAny, string | number | boolean | JsonArray | JsonObject | null, any>;
|
|
9
9
|
export declare const ScopeSchema: z.ZodRecord<z.ZodString, z.ZodEffects<z.ZodAny, string | number | boolean | JsonArray | JsonObject | null, any>>;
|
|
10
|
+
export declare const AssetSchema: z.ZodUnion<[z.ZodEffects<z.ZodString, {
|
|
11
|
+
url: string;
|
|
12
|
+
mime?: string | undefined;
|
|
13
|
+
}, string>, z.ZodObject<{
|
|
14
|
+
url: z.ZodString;
|
|
15
|
+
mime: z.ZodOptional<z.ZodString>;
|
|
16
|
+
}, "strip", z.ZodTypeAny, {
|
|
17
|
+
url: string;
|
|
18
|
+
mime?: string | undefined;
|
|
19
|
+
}, {
|
|
20
|
+
url: string;
|
|
21
|
+
mime?: string | undefined;
|
|
22
|
+
}>]>;
|
|
23
|
+
export declare const AssetsSchema: z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodEffects<z.ZodString, {
|
|
24
|
+
url: string;
|
|
25
|
+
mime?: string | undefined;
|
|
26
|
+
}, string>, z.ZodObject<{
|
|
27
|
+
url: z.ZodString;
|
|
28
|
+
mime: z.ZodOptional<z.ZodString>;
|
|
29
|
+
}, "strip", z.ZodTypeAny, {
|
|
30
|
+
url: string;
|
|
31
|
+
mime?: string | undefined;
|
|
32
|
+
}, {
|
|
33
|
+
url: string;
|
|
34
|
+
mime?: string | undefined;
|
|
35
|
+
}>]>>;
|
|
10
36
|
export declare const MetadataSchema: z.ZodObject<{
|
|
11
|
-
title: z.
|
|
12
|
-
|
|
37
|
+
title: z.ZodOptional<z.ZodString>;
|
|
38
|
+
author: z.ZodOptional<z.ZodString>;
|
|
39
|
+
email: z.ZodOptional<z.ZodString>;
|
|
40
|
+
globals: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEffects<z.ZodAny, string | number | boolean | JsonArray | JsonObject | null, any>>>;
|
|
41
|
+
assets: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodEffects<z.ZodString, {
|
|
42
|
+
url: string;
|
|
43
|
+
mime?: string | undefined;
|
|
44
|
+
}, string>, z.ZodObject<{
|
|
45
|
+
url: z.ZodString;
|
|
46
|
+
mime: z.ZodOptional<z.ZodString>;
|
|
47
|
+
}, "strip", z.ZodTypeAny, {
|
|
48
|
+
url: string;
|
|
49
|
+
mime?: string | undefined;
|
|
50
|
+
}, {
|
|
51
|
+
url: string;
|
|
52
|
+
mime?: string | undefined;
|
|
53
|
+
}>]>>>;
|
|
13
54
|
}, "strip", z.ZodTypeAny, {
|
|
14
|
-
title
|
|
15
|
-
|
|
55
|
+
title?: string | undefined;
|
|
56
|
+
author?: string | undefined;
|
|
57
|
+
email?: string | undefined;
|
|
58
|
+
globals?: Record<string, string | number | boolean | JsonArray | JsonObject | null> | undefined;
|
|
59
|
+
assets?: Record<string, {
|
|
60
|
+
url: string;
|
|
61
|
+
mime?: string | undefined;
|
|
62
|
+
}> | undefined;
|
|
16
63
|
}, {
|
|
17
64
|
title?: string | undefined;
|
|
65
|
+
author?: string | undefined;
|
|
66
|
+
email?: string | undefined;
|
|
18
67
|
globals?: Record<string, any> | undefined;
|
|
68
|
+
assets?: Record<string, string | {
|
|
69
|
+
url: string;
|
|
70
|
+
mime?: string | undefined;
|
|
71
|
+
}> | undefined;
|
|
19
72
|
}>;
|
|
20
73
|
export declare const StoryHooksSchema: z.ZodObject<{
|
|
21
74
|
onStart: z.ZodOptional<z.ZodFunction<z.ZodTuple<[z.ZodRecord<z.ZodString, z.ZodEffects<z.ZodAny, string | number | boolean | JsonArray | JsonObject | null, any>>], z.ZodUnknown>, z.ZodUnion<[z.ZodRecord<z.ZodString, z.ZodEffects<z.ZodAny, string | number | boolean | JsonArray | JsonObject | null, any>>, z.ZodVoid]>>>;
|
|
@@ -39,8 +92,22 @@ export declare const ChapterHooksSchema: z.ZodObject<{
|
|
|
39
92
|
}>;
|
|
40
93
|
export type Value = z.infer<typeof ValueSchema>;
|
|
41
94
|
export type Scope = z.infer<typeof ScopeSchema>;
|
|
95
|
+
export type Asset = z.infer<typeof AssetSchema>;
|
|
42
96
|
export type Metadata = z.infer<typeof MetadataSchema>;
|
|
43
97
|
export type StoryHooks = z.infer<typeof StoryHooksSchema>;
|
|
44
98
|
export type ChapterHooks = z.infer<typeof ChapterHooksSchema>;
|
|
45
99
|
export type ValueType = "string" | "number" | "boolean" | "object";
|
|
100
|
+
export type ChapterBody = {
|
|
101
|
+
title: string;
|
|
102
|
+
template: string;
|
|
103
|
+
script: string;
|
|
104
|
+
};
|
|
105
|
+
export type StoryBody = {
|
|
106
|
+
metadata: Metadata;
|
|
107
|
+
chapters: Record<string, ChapterBody>;
|
|
108
|
+
entry: string | null;
|
|
109
|
+
script: string;
|
|
110
|
+
stylesheet: string;
|
|
111
|
+
};
|
|
112
|
+
export type StoryAssets = Record<string, string>;
|
|
46
113
|
export {};
|
package/types/base/index.d.ts
CHANGED
package/types/base/story.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { StoryHooks, Scope, Metadata,
|
|
1
|
+
import { StoryBody, StoryHooks, Scope, Metadata, Asset } from "./definitions.js";
|
|
2
2
|
import { Chapter, RenderOptions, RenderResult } from "./chapter.js";
|
|
3
3
|
export type StoryPrompt = (props: {
|
|
4
4
|
chapter: Chapter;
|
|
@@ -6,19 +6,6 @@ export type StoryPrompt = (props: {
|
|
|
6
6
|
target: string | null;
|
|
7
7
|
updates: Scope;
|
|
8
8
|
} | FormData>;
|
|
9
|
-
type ChapterBody = {
|
|
10
|
-
title: string;
|
|
11
|
-
template: string;
|
|
12
|
-
hooks: ChapterHooks;
|
|
13
|
-
};
|
|
14
|
-
type StoryBody = {
|
|
15
|
-
metadata: Metadata;
|
|
16
|
-
chapters: Record<string, ChapterBody>;
|
|
17
|
-
entry: string | null;
|
|
18
|
-
hooks: StoryHooks;
|
|
19
|
-
stylesheet: string;
|
|
20
|
-
};
|
|
21
|
-
export declare const parseStoryContent: (content: string) => StoryBody;
|
|
22
9
|
export declare class StoryBase {
|
|
23
10
|
metadata: Metadata;
|
|
24
11
|
globals: Scope;
|
|
@@ -26,7 +13,7 @@ export declare class StoryBase {
|
|
|
26
13
|
entry: Chapter | null;
|
|
27
14
|
hooks: StoryHooks;
|
|
28
15
|
stylesheet: string;
|
|
29
|
-
|
|
16
|
+
assets: Record<string, Asset>;
|
|
17
|
+
constructor({ metadata, chapters, entry, script, stylesheet }: StoryBody);
|
|
30
18
|
play(prompt: StoryPrompt, options: RenderOptions): Promise<void>;
|
|
31
19
|
}
|
|
32
|
-
export {};
|