@elvishscout/mdstory 0.1.3 → 0.1.4

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 CHANGED
@@ -6,7 +6,7 @@ Online demo: <https://mdstory.elvish.cc>
6
6
 
7
7
  ## Features
8
8
 
9
- - Seamless intergration of Markdown, Handlebars and JavaScript.
9
+ - Seamless integration of Markdown, Handlebars and JavaScript.
10
10
  - Ease-to-use API, for both Web and command line applications.
11
11
 
12
12
  ## File Format
@@ -27,7 +27,7 @@ MdStory includes built-in Handlebars helpers for creating interactive components
27
27
 
28
28
  #### `{{input type name=default}}`
29
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).
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 as a JSON string).
31
31
 
32
32
  In HTML rendering mode, it generates a corresponding `<input>` element.
33
33
 
@@ -47,21 +47,21 @@ Inserts `n` blank lines, where `n` defaults to `1`.
47
47
 
48
48
  #### `{{asset name}}`
49
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.
50
+ Retrieves the URL of a resource file named `name`. Basically it works the same as `{{name}}` except that it supports resource names with special characters.
51
51
 
52
52
  #### `{{mime name}}`
53
53
 
54
54
  Retrieves the MIME type of a resource file named `name`.
55
55
 
56
- ### JavaScript Scripts
56
+ ### JavaScript Integration
57
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.
58
+ JavaScript may be included into the story source 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
59
 
60
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
61
 
62
62
  ### Stylesheets
63
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.
64
+ CSS stylesheets may be included using the `<style>` tag, which are extracted and gathered into the `stylesheet` property of [StoryBody](#type-storybody) during parsing.
65
65
 
66
66
  ## Examples
67
67
 
@@ -71,14 +71,38 @@ Here are some [examples](./examples/) of story files.
71
71
 
72
72
  ### `type Value`
73
73
 
74
+ ```typescript
75
+ type JsonPrimitive = number | string | boolean | null;
76
+ type JsonArray = JsonValue[];
77
+ type JsonObject = { [key: string]: JsonValue };
78
+ type JsonValue = JsonPrimitive | JsonArray | JsonObject;
79
+ type Value = JsonValue;
80
+ ```
81
+
74
82
  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
83
 
84
+ ### `type ValueType`
85
+
86
+ ```typescript
87
+ type ValueType = "string" | "number" | "boolean" | "object";
88
+ ```
89
+
90
+ The type indicator for input fields.
91
+
76
92
  ### `type Scope`
77
93
 
94
+ ```typescript
95
+ type Scope = JsonObject;
96
+ ```
97
+
78
98
  An object of variable values by their names, used to store global variables or input fields.
79
99
 
80
100
  ### `type Asset`
81
101
 
102
+ ```typescript
103
+ type Asset = { url: string; mime?: string };
104
+ ```
105
+
82
106
  A referenceable resource file.
83
107
 
84
108
  #### Properties
@@ -88,6 +112,15 @@ A referenceable resource file.
88
112
 
89
113
  ### `type Metadata`
90
114
 
115
+ ```typescript
116
+ type Metadata = {
117
+ title?: string;
118
+ author?: string;
119
+ email?: string;
120
+ assets?: Record<string, Asset>;
121
+ };
122
+ ```
123
+
91
124
  The Metadata of the story.
92
125
 
93
126
  #### Properties
@@ -95,11 +128,19 @@ The Metadata of the story.
95
128
  - `title (optional)`: The story title.
96
129
  - `author (optional)`: The author's name.
97
130
  - `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.
131
+ - `globals (optional)`: A [Scope](#type-scope) containing initial values of global variables.
132
+ - `assets (optional)`: An object of all [Asset](#type-asset) objects used in the story by their names.
100
133
 
101
134
  ### `type ChapterBody`
102
135
 
136
+ ```typescript
137
+ type ChapterBody = {
138
+ title: string;
139
+ template: string;
140
+ script: string;
141
+ };
142
+ ```
143
+
103
144
  The structured representation of chapter content.
104
145
 
105
146
  #### Properties
@@ -110,6 +151,16 @@ The structured representation of chapter content.
110
151
 
111
152
  ### `type StoryBody`
112
153
 
154
+ ```typescript
155
+ type StoryBody = {
156
+ metadata: Metadata;
157
+ chapters: Record<string, ChapterBody>;
158
+ entry: string | null;
159
+ script: string;
160
+ stylesheet: string;
161
+ };
162
+ ```
163
+
113
164
  The structured representation of story content.
114
165
 
115
166
  #### Properties
@@ -122,59 +173,92 @@ The structured representation of story content.
122
173
 
123
174
  ### `type StoryHooks`
124
175
 
176
+ ```typescript
177
+ type StoryHooks = {
178
+ onStart?: (globals: Scope) => Scope | void;
179
+ };
180
+ ```
181
+
125
182
  Defines the global lifecycle hooks of the story.
126
183
 
127
- #### Properties
184
+ #### Methods
128
185
 
129
186
  - `onStart (optional)`: Called when the story starts.
130
187
  - Parameters:
131
- - `globals`: The initial values of global variables.
132
- - Return value: Updated `globals` or `void`.
188
+ - `globals`: A [Scope](#type-scope) of initial global variables.
189
+ - Return value:
190
+ - Updated [Scope](#type-scope) of global variables or `void`.
133
191
 
134
192
  ### `type ChapterHooks`
135
193
 
194
+ ```typescript
195
+ type ChapterHooks = {
196
+ onEnter?: (globals: Scope) => Scope | void;
197
+ onLeave?: (globals: Scope, fields: Scope) => Scope | void;
198
+ onNavigate?: (target: string | null, globals: Scope, fields: Scope) => string | null;
199
+ };
200
+ ```
201
+
136
202
  Defines the lifecycle hooks of a chapter.
137
203
 
138
- #### Properties
204
+ #### Methods
139
205
 
140
206
  - `onEnter (optional)`: Called when entering a chapter.
141
207
  - Parameters:
142
- - `globals`: Current global variables.
143
- - Return value: Updated `globals` or `void`, effective only during the lifecycle of current chapter.
208
+ - `globals`: A [Scope](#type-scope) of current global variables.
209
+ - Return value:
210
+ - Updated [Scope](#type-scope) of global variables or `void`. Such update only applies to the current lifecycle of the chapter.
144
211
  - `onLeave (optional)`: Called when leaving a chapter.
145
212
  - Parameters:
146
- - `globals`: Current global variables.
147
- - `fields`: Input fields from current chapter.
148
- - Return value: Updated `globals` or `void`.
213
+ - `globals`: A [Scope](#type-scope) of current global variables.
214
+ - `fields`: A [Scope](#type-scope) of input fields from current chapter.
215
+ - Return value:
216
+ - Updated [Scope](#type-scope) of global variables or `void`.
149
217
  - `onNavigate (optional)`: Called during chapter navigation.
150
218
  - 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`.
219
+ - `target` : `id` of the target chapter.
220
+ - `globals`: A [Scope](#type-scope) of current global variables.
221
+ - `fields`: A [Scope](#type-scope) of input fields from current chapter.
222
+ - Return value:
223
+ - Updated `target` or `void`.
155
224
 
156
225
  ### `type Renderer`
157
226
 
227
+ ```typescript
228
+ type Renderer = {
229
+ input?: (options: { name: string; type: ValueType; value: Value }) => string;
230
+ nav?: (options: { target: string; children: string }) => string;
231
+ };
232
+ ```
233
+
158
234
  Defines the renderer interface for generating outputs in different formats.
159
235
 
160
236
  #### Methods
161
237
 
162
- - `input({ name, type, value }) (optional)`: Generates the rendering result of an input field.
163
-
238
+ - `input (optional)`: Generates the rendering result of an input field.
164
239
  - Parameters:
165
240
  - `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.
241
+ - `type`: The [ValueType](#type-valuetype) of the variable.
242
+ - `value`: The default [Value](#type-value) of the variable.
243
+ - Return value:
244
+ - The rendered input field.
169
245
 
170
- - `nav({ target, children }) (optional)`: Generates the rendering result of chapter navigation.
246
+ - `nav (optional)`: Generates the rendering result of chapter navigation.
171
247
  - Parameters:
172
248
  - `target`: The `id` of the target chapter.
173
249
  - `children`: The text content of the navigation button.
174
- - Return value: The rendered navigation button.
250
+ - Return value:
251
+ - The rendered navigation button.
175
252
 
176
253
  ### `type RenderOptions`
177
254
 
255
+ ```typescript
256
+ type RenderOptions = {
257
+ format: "markdown" | "html" | Renderer;
258
+ html?: boolean;
259
+ };
260
+ ```
261
+
178
262
  Defines rendering options.
179
263
 
180
264
  #### Properties
@@ -184,6 +268,14 @@ Defines rendering options.
184
268
 
185
269
  ### `type RenderResult`
186
270
 
271
+ ```typescript
272
+ type RenderResult = {
273
+ text: string;
274
+ inputs: { name: string; type: ValueType; value: Value }[];
275
+ navs: { text: string; target: string | null }[];
276
+ };
277
+ ```
278
+
187
279
  The rendering result, containing the rendered text and extracted fields.
188
280
 
189
281
  #### Properties
@@ -191,18 +283,23 @@ The rendering result, containing the rendered text and extracted fields.
191
283
  - `text`: The rendered text content.
192
284
  - `inputs`: An array of input fields, each containing:
193
285
  - `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.
286
+ - `type`: The [ValueType](#type-valuetype) of the variable.
287
+ - `value`: The default [Value](#type-value) of the variable.
200
288
  - `navs`: An array of navigation fields, each containing:
201
289
  - `text`: The text content of the navigation button.
202
290
  - `target`: The `id` of the target chapter.
203
291
 
204
292
  ### `type ChapterOptions`
205
293
 
294
+ ```typescript
295
+ type ChapterOptions = {
296
+ id: string;
297
+ title: string;
298
+ template: string;
299
+ hooks: ChapterHooks;
300
+ };
301
+ ```
302
+
206
303
  Defines the initialization options of a chapter.
207
304
 
208
305
  #### Properties
@@ -214,6 +311,18 @@ Defines the initialization options of a chapter.
214
311
 
215
312
  ### `class Chapter`
216
313
 
314
+ ```typescript
315
+ class Chapter {
316
+ id: string;
317
+ title: string;
318
+ template: string;
319
+ hooks: ChapterHooks;
320
+
321
+ constructor(options: ChapterOptions);
322
+ render(scope: Scope, assets: Record<string, Asset>, options: RenderOptions): string;
323
+ }
324
+ ```
325
+
217
326
  Defines a chapter.
218
327
 
219
328
  #### Properties
@@ -225,62 +334,88 @@ Defines a chapter.
225
334
 
226
335
  #### Methods
227
336
 
228
- - `constructor(options)`: Initializes the chapter instance.
337
+ - `constructor`: Initializes the chapter instance.
229
338
  - Parameters:
230
- - `options`: The chapter options of type [ChapterOptions](#type-chapteroptions).
231
- - `render(scope, assets, options)`: Renders the story content.
339
+ - `options`: An object of type [ChapterOptions](#type-chapteroptions).
340
+ - `render`: Renders the chapter content.
232
341
  - 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).
342
+ - `scope`: An object of type [Scope](#type-scope) for template rendering.
343
+ - `assets`: An object of [Asset](#type-asset) objects by their names.
344
+ - `options`: An object of type [RenderOptions](#type-renderoptions).
345
+ - Return value:
346
+ - An object of type [RenderResult](#type-renderresult).
237
347
 
238
348
  ### `type StoryPrompt`
239
349
 
350
+ ```typescript
351
+ type StoryPrompt = (props: { chapter: Chapter } & RenderResult) => Promise<{ target: string | null; updates: Scope } | FormData>;
352
+ ```
353
+
240
354
  Defines the prompt function of the story, used to handle user input.
241
355
 
242
356
  #### Parameters
243
357
 
244
358
  - `props`: An object containing the current chapter and rendering result.
245
- - `chapter`: Current chapter.
359
+ - `chapter`: Current [Chapter](#class-chapter).
246
360
  - `text`: The rendered chapter content.
247
- - `inputs`, `sets`, `navs`: Fields from the rendering result.
361
+ - `inputs`, `navs`: Fields from [RenderResult](#type-renderresult).
248
362
 
249
363
  #### Return value
250
364
 
251
365
  - 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.
366
+ - `{ target, updates }`: The `id` of the target chapter and updated [Scope](#type-scope) of global variables.
367
+ - `FormData`: Contains the form data of user input, typically from a Web app.
254
368
 
255
369
  ### `class StoryBase`
256
370
 
371
+ ```typescript
372
+ class StoryBase {
373
+ metadata: Metadata;
374
+ globals: Scope;
375
+ chapters: Record<string, Chapter>;
376
+ entry: Chapter | null;
377
+ hooks: StoryHooks;
378
+ stylesheet: string;
379
+ assets: Record<string, Asset>;
380
+
381
+ constructor(storyBody: StoryBody);
382
+ play(prompt: StoryPrompt, options: RenderOptions): Promise<void>;
383
+ }
384
+ ```
385
+
257
386
  Defines the base class of the story, containing the core logic of the story.
258
387
 
259
388
  #### Properties
260
389
 
261
390
  - `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.
391
+ - `globals`: A [Scope](#type-scope) of global variables.
392
+ - `chapters`: An object of [Chapter](#class-chapter) objects by their `id`s.
393
+ - `entry`: The entry [Chapter](#class-chapter) of the story.
265
394
  - `hooks`: An object of type [StoryHooks](#type-storyhooks).
266
395
  - `stylesheet`: The global stylesheet of the story.
267
- - `assets`: An object of asset files by their alias names.
396
+ - `assets`: An object of [Asset](#type-asset) objects by their names.
268
397
 
269
398
  #### Methods
270
399
 
271
- - `constructor({ metadata, chapters, entry, script, stylesheet })`: Initializes the story instance.
272
- - `play(prompt, options)`: Starts playing the story.
400
+ - `constructor`: Initializes the story instance.
401
+ - `play`: Starts playing the story.
273
402
  - Parameters:
274
403
  - `prompt`: A function of type [StoryPrompt](#type-storyprompt).
275
404
  - `options`: An object of type [RenderOptions](#type-renderoptions).
405
+ - Return value:
406
+ - A `Promise` resolving to `void`.
276
407
 
277
- ### `function parseStoryContent`
408
+ ### `function parseStorySource`
278
409
 
279
- Parses the story content in Markdown format.
410
+ ```typescript
411
+ function parseStorySource(source: string): StoryBody;
412
+ ```
413
+
414
+ Parses the story source in Markdown format.
280
415
 
281
416
  #### Parameters
282
417
 
283
- - `content`: The story content in Markdown format.
418
+ - `source`: The story source in Markdown format.
284
419
 
285
420
  #### Return value
286
421
 
@@ -288,8 +423,16 @@ Parses the story content in Markdown format.
288
423
 
289
424
  ### `class Story`
290
425
 
291
- Inherits from [StoryBase](#class-storybase), creating a story instance from the story content in Markdown format.
426
+ ```typescript
427
+ class Story extends StoryBase {
428
+ constructor(source: string);
429
+ }
430
+ ```
431
+
432
+ Inherits from [StoryBase](#class-storybase), creating a story instance from the story source in Markdown format.
292
433
 
293
434
  #### Methods
294
435
 
295
- - `constructor(content: string)`: Initializes the story instance.
436
+ - `constructor`: Initializes the story instance.
437
+ - Parameters:
438
+ - `source`: The story source in Markdown format.
@@ -4,9 +4,9 @@ import pluginFrontMatter from "markdown-it-front-matter";
4
4
  import pluginAttrs from "markdown-it-attrs";
5
5
  import { MetadataSchema } from "./definitions.js";
6
6
  import { DuplicateIdError, EmptyChapterIdError, InvalidMetadataError } from "./error.js";
7
- export const parseStoryContent = (content) => {
7
+ export const parseStorySource = (source) => {
8
8
  const md = new MarkdownIt({ html: true }).use(pluginAttrs).use(pluginFrontMatter, () => { });
9
- const tokens = md.parse(content, {});
9
+ const tokens = md.parse(source, {});
10
10
  let metadata = MetadataSchema.parse({});
11
11
  let storyScript = "";
12
12
  let stylesheet = "";
@@ -61,7 +61,7 @@ export const parseStoryContent = (content) => {
61
61
  }
62
62
  }
63
63
  });
64
- const lines = content.split("\n").map((line, i) => {
64
+ const lines = source.split("\n").map((line, i) => {
65
65
  if (ignoredRanges.find(([from, to]) => i >= from && i < to)) {
66
66
  return null;
67
67
  }
@@ -13,9 +13,9 @@ const parstInput = (type, text) => {
13
13
  }
14
14
  return text;
15
15
  };
16
- const parseFormData = (formData, { inputs, sets }) => {
16
+ const parseFormData = (formData, { inputs }) => {
17
17
  const target = formData.get("@target") || null;
18
- const updates = Object.fromEntries([...inputs, ...sets].map(({ name, type }) => {
18
+ const updates = Object.fromEntries(inputs.map(({ name, type }) => {
19
19
  const value = formData.get(name);
20
20
  try {
21
21
  return [name, parstInput(type, value)];
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  export * from "./base/index.js";
2
- import { StoryBase, parseStoryContent } from "./base/index.js";
2
+ import { StoryBase, parseStorySource } from "./base/index.js";
3
3
  export class Story extends StoryBase {
4
- constructor(content) {
5
- super(parseStoryContent(content));
4
+ constructor(source) {
5
+ super(parseStorySource(source));
6
6
  }
7
7
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@elvishscout/mdstory",
3
3
  "repository": "https://github.com/ElvishScout/mdstory.git",
4
- "version": "0.1.3",
4
+ "version": "0.1.4",
5
5
  "description": "An interactive fiction scripting format based on Markdown and Handlebars.",
6
6
  "main": "./dist/index.js",
7
7
  "type": "module",
@@ -16,7 +16,7 @@ export type RenderOptions = {
16
16
  };
17
17
  export type RenderResult = {
18
18
  text: string;
19
- } & Fields;
19
+ } & Omit<Fields, "sets">;
20
20
  type Fields = {
21
21
  inputs: {
22
22
  name: string;
@@ -1,2 +1,2 @@
1
1
  import { StoryBody } from "./definitions.js";
2
- export declare const parseStoryContent: (content: string) => StoryBody;
2
+ export declare const parseStorySource: (source: string) => StoryBody;
package/types/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export * from "./base/index.js";
2
2
  import { StoryBase } from "./base/index.js";
3
3
  export declare class Story extends StoryBase {
4
- constructor(content: string);
4
+ constructor(source: string);
5
5
  }