extwee 1.6.0 → 2.0.2
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/.eslintrc.json +25 -0
- package/.github/workflows/nodejs.yml +24 -25
- package/.travis.yml +13 -13
- package/CODE_OF_CONDUCT.md +82 -0
- package/LICENSE +21 -21
- package/README.md +36 -205
- package/SECURITY.md +12 -0
- package/babel.config.json +22 -0
- package/bin/extwee.js +49 -0
- package/index.js +31 -26
- package/package.json +59 -37
- package/src/FileReader.js +33 -36
- package/src/HTMLParser.js +343 -206
- package/src/HTMLWriter.js +227 -177
- package/src/Passage.js +202 -20
- package/src/Story.js +461 -148
- package/src/StoryFormat.js +300 -41
- package/src/StoryFormatParser.js +142 -65
- package/src/TweeParser.js +161 -255
- package/src/TweeWriter.js +98 -111
- package/story-formats/chapbook-1.2.0/format.js +1 -0
- package/story-formats/chapbook-1.2.0/logo.svg +1 -0
- package/story-formats/harlowe-1.2.4/format.js +1 -0
- package/story-formats/harlowe-1.2.4/icon.svg +78 -0
- package/story-formats/harlowe-2.1.0/format.js +2 -0
- package/story-formats/harlowe-2.1.0/icon.svg +78 -0
- package/story-formats/harlowe-3.1.0/format.js +3 -0
- package/story-formats/harlowe-3.1.0/icon.svg +78 -0
- package/story-formats/paperthin-1.0.0/format.js +1 -0
- package/story-formats/paperthin-1.0.0/icon.svg +5 -0
- package/story-formats/snowman-1.4.0/format.js +1 -0
- package/story-formats/snowman-1.4.0/icon.svg +436 -0
- package/story-formats/snowman-2.0.2/format.js +1 -0
- package/story-formats/snowman-2.0.2/icon.svg +436 -0
- package/story-formats/sugarcube-1.0.35/LICENSE +23 -0
- package/story-formats/sugarcube-1.0.35/format.js +1 -0
- package/story-formats/sugarcube-1.0.35/icon.svg +56 -0
- package/story-formats/sugarcube-2.31.1/LICENSE +22 -0
- package/story-formats/sugarcube-2.31.1/format.js +1 -0
- package/story-formats/sugarcube-2.31.1/icon.svg +56 -0
- package/test/{HTMLWriter/example7.twee → CLI/example6.twee} +16 -16
- package/test/CLI/harlowe.js +3 -0
- package/test/CLI/input.html +47 -0
- package/test/CLI/test.twee +18 -0
- package/test/CLI/test2.html +47 -0
- package/test/CLI/tweeExample.twee +17 -0
- package/test/CLI/twineExample.html +15 -0
- package/test/CLI.test.js +30 -0
- package/test/FileReader.test.js +14 -0
- package/test/HTMLParser/Example1.html +53 -0
- package/test/HTMLParser/Tags.html +15 -0
- package/test/HTMLParser/lyingStartnode.html +15 -0
- package/test/HTMLParser/lyingTagColors.html +48 -0
- package/test/HTMLParser/missingCreator.html +11 -0
- package/test/HTMLParser/missingCreatorVersion.html +11 -0
- package/test/HTMLParser/missingFormat.html +11 -0
- package/test/HTMLParser/missingFormatVersion.html +11 -0
- package/test/HTMLParser/missingIFID.html +11 -0
- package/test/HTMLParser/missingName.html +33 -0
- package/test/HTMLParser/missingPID.html +15 -0
- package/test/HTMLParser/missingPassageName.html +15 -0
- package/test/HTMLParser/missingPassageTags.html +15 -0
- package/test/HTMLParser/missingPosition.html +15 -0
- package/test/HTMLParser/missingScript.html +14 -0
- package/test/HTMLParser/missingSize.html +35 -0
- package/test/HTMLParser/missingStartnode.html +11 -0
- package/test/HTMLParser/missingStyle.html +14 -0
- package/test/HTMLParser/missingZoom.html +11 -0
- package/test/HTMLParser/tagColors.html +31 -0
- package/test/HTMLParser/twineExample.html +15 -46
- package/test/HTMLParser/twineExample2.html +15 -0
- package/test/HTMLParser/twineExample3.html +15 -0
- package/test/HTMLParser.test.js +177 -0
- package/test/HTMLWriter/TestTags.html +42 -0
- package/test/HTMLWriter/{test10.html → creator.html} +8 -5
- package/test/HTMLWriter/example6.twee +16 -16
- package/test/HTMLWriter/{example.twee → missingStoryTitle.twee} +29 -29
- package/test/HTMLWriter/test11.html +123 -0
- package/test/HTMLWriter/test2.html +15 -12
- package/test/HTMLWriter/test3.html +7 -13
- package/test/HTMLWriter/test4.html +8 -5
- package/test/HTMLWriter/test6.html +7 -5
- package/test/HTMLWriter.test.js +289 -0
- package/test/Passage.test.js +104 -0
- package/test/Roundtrip/Example1.html +64 -0
- package/test/Roundtrip/example1.twee +21 -0
- package/test/Roundtrip/example2.twee +18 -0
- package/test/Roundtrip/harlowe.js +3 -0
- package/test/Roundtrip/round.html +50 -0
- package/test/Roundtrip.test.js +48 -0
- package/test/Story/startmeta.twee +29 -29
- package/test/Story/test.twee +25 -25
- package/test/Story.test.js +282 -0
- package/test/StoryFormat.test.js +152 -0
- package/test/StoryFormatParser/example.js +3 -0
- package/test/StoryFormatParser/{test2.js → example2.js} +3 -3
- package/test/StoryFormatParser/format_doublename.js +1 -0
- package/test/StoryFormatParser/harlowe.js +2 -2
- package/test/StoryFormatParser/missingAuthor.js +1 -0
- package/test/StoryFormatParser/missingDescription.js +1 -0
- package/test/StoryFormatParser/missingImage.js +1 -0
- package/test/StoryFormatParser/missingLicense.js +1 -0
- package/test/StoryFormatParser/missingName.js +1 -0
- package/test/StoryFormatParser/missingProofing.js +1 -0
- package/test/StoryFormatParser/missingSource.js +1 -0
- package/test/StoryFormatParser/missingURL.js +1 -0
- package/test/StoryFormatParser/missingVersion.js +1 -0
- package/test/StoryFormatParser/versionWrong.js +1 -0
- package/test/StoryFormatParser.test.js +91 -0
- package/test/TweeParser/emptytags.twee +2 -2
- package/test/TweeParser/example.twee +32 -29
- package/test/TweeParser/missing.twee +19 -0
- package/test/{HTMLWriter/example5.twee → TweeParser/multipleScriptPassages.twee} +19 -13
- package/test/{HTMLWriter/example4.twee → TweeParser/multipleStyleTag.twee} +19 -13
- package/test/TweeParser/multipletags.twee +10 -2
- package/test/TweeParser/noTitle.twee +2 -0
- package/test/TweeParser/notes.twee +16 -0
- package/test/TweeParser/pasagemetadataerror.twee +2 -2
- package/test/{HTMLWriter/example2.twee → TweeParser/scriptPassage.twee} +16 -13
- package/test/TweeParser/singletag.twee +13 -2
- package/test/TweeParser/startMetadata.twee +14 -0
- package/test/TweeParser/storydataerror.twee +25 -25
- package/test/{HTMLWriter/example3.twee → TweeParser/stylePassage.twee} +16 -13
- package/test/TweeParser/test.twee +25 -25
- package/test/TweeParser.test.js +79 -0
- package/test/TweeWriter/test1.twee +14 -9
- package/test/TweeWriter/test3.twee +7 -10
- package/test/TweeWriter/test4.twee +14 -0
- package/test/TweeWriter/test5.twee +20 -0
- package/test/TweeWriter.test.js +85 -0
- package/main.js +0 -106
- package/src/DirectoryReader.js +0 -107
- package/src/DirectoryWatcher.js +0 -92
- package/test/DirectoryReader/css/test.css +0 -3
- package/test/DirectoryReader1/js/Site.js +0 -1
- package/test/DirectoryReader2/error.js +0 -1
- package/test/DirectoryReader2/example.css +0 -3
- package/test/DirectoryReader2/index.twee +0 -6
- package/test/DirectoryReader3/twee/index.twee +0 -6
- package/test/DirectoryWatcher/example.txt +0 -0
- package/test/DirectoryWatcher/test.txt +0 -0
- package/test/DirectoryWatcher/test1.txt +0 -0
- package/test/HTMLWriter/test5.html +0 -48
- package/test/HTMLWriter/test7.html +0 -48
- package/test/HTMLWriter/test8.html +0 -48
- package/test/HTMLWriter/test9.html +0 -48
- package/test/StoryFormatParser/test.js +0 -2
- package/test/TweeParser/test.twee3 +0 -11
- package/test/TweeWriter/metatest.twee +0 -12
- package/test/TweeWriter/test2.twee +0 -15
- package/test/test.js +0 -722
package/src/StoryFormat.js
CHANGED
|
@@ -1,41 +1,300 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @class StoryFormat
|
|
3
|
-
* @module StoryFormat
|
|
4
|
-
*/
|
|
5
|
-
class StoryFormat {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @class StoryFormat
|
|
3
|
+
* @module StoryFormat
|
|
4
|
+
*/
|
|
5
|
+
export default class StoryFormat {
|
|
6
|
+
/**
|
|
7
|
+
* Internal name
|
|
8
|
+
*
|
|
9
|
+
* @private
|
|
10
|
+
*/
|
|
11
|
+
#_name = '';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Internal version
|
|
15
|
+
*
|
|
16
|
+
* @private
|
|
17
|
+
*/
|
|
18
|
+
#_version = '';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Internal description
|
|
22
|
+
*
|
|
23
|
+
* @private
|
|
24
|
+
*/
|
|
25
|
+
#_description = '';
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Internal author
|
|
29
|
+
*
|
|
30
|
+
* @private
|
|
31
|
+
*/
|
|
32
|
+
#_author = '';
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Internal image
|
|
36
|
+
*
|
|
37
|
+
* @private
|
|
38
|
+
*/
|
|
39
|
+
#_image = '';
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Internal URL
|
|
43
|
+
*
|
|
44
|
+
* @private
|
|
45
|
+
*/
|
|
46
|
+
#_url = '';
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Internal license
|
|
50
|
+
*
|
|
51
|
+
* @private
|
|
52
|
+
*/
|
|
53
|
+
#_license = '';
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Internal proofing
|
|
57
|
+
*
|
|
58
|
+
* @private
|
|
59
|
+
*/
|
|
60
|
+
#_proofing = '';
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Internal source
|
|
64
|
+
*
|
|
65
|
+
* @private
|
|
66
|
+
*/
|
|
67
|
+
#_source = '';
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @class
|
|
71
|
+
* @function StoryFormat
|
|
72
|
+
* @param {string} name - Name
|
|
73
|
+
* @param {string} version - Version
|
|
74
|
+
* @param {string} description - Description
|
|
75
|
+
* @param {string} author - Author
|
|
76
|
+
* @param {string} image - Image
|
|
77
|
+
* @param {string} url - URL
|
|
78
|
+
* @param {string} license - License
|
|
79
|
+
* @param {boolean} proofing - If proofing or not
|
|
80
|
+
* @param {string} source - Source
|
|
81
|
+
*/
|
|
82
|
+
constructor (
|
|
83
|
+
name = '',
|
|
84
|
+
version = '',
|
|
85
|
+
description = '',
|
|
86
|
+
author = '',
|
|
87
|
+
image = '',
|
|
88
|
+
url = '',
|
|
89
|
+
license = '',
|
|
90
|
+
proofing = false,
|
|
91
|
+
source = ''
|
|
92
|
+
) {
|
|
93
|
+
// Set name
|
|
94
|
+
this.name = name;
|
|
95
|
+
|
|
96
|
+
// Set version
|
|
97
|
+
this.version = version;
|
|
98
|
+
|
|
99
|
+
// Set description
|
|
100
|
+
this.description = description;
|
|
101
|
+
|
|
102
|
+
// Set author
|
|
103
|
+
this.author = author;
|
|
104
|
+
|
|
105
|
+
// Set image
|
|
106
|
+
this.image = image;
|
|
107
|
+
|
|
108
|
+
// Set URL
|
|
109
|
+
this.url = url;
|
|
110
|
+
|
|
111
|
+
// Set license
|
|
112
|
+
this.license = license;
|
|
113
|
+
|
|
114
|
+
// Set proofing
|
|
115
|
+
this.proofing = proofing;
|
|
116
|
+
|
|
117
|
+
// Set source
|
|
118
|
+
this.source = source;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Name
|
|
123
|
+
*
|
|
124
|
+
* @public
|
|
125
|
+
* @memberof StoryFormat
|
|
126
|
+
* @returns {string} Name
|
|
127
|
+
*/
|
|
128
|
+
get name () { return this.#_name; }
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* @param {string} n - Replacement name
|
|
132
|
+
*/
|
|
133
|
+
set name (n) {
|
|
134
|
+
if (typeof n === 'string') {
|
|
135
|
+
this.#_name = n;
|
|
136
|
+
} else {
|
|
137
|
+
throw new Error('Name must be a string!');
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Version
|
|
143
|
+
*
|
|
144
|
+
* @public
|
|
145
|
+
* @memberof StoryFormat
|
|
146
|
+
* @returns {string} Version
|
|
147
|
+
*/
|
|
148
|
+
get version () { return this.#_version; }
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* @param {string} n - Replacement version
|
|
152
|
+
*/
|
|
153
|
+
set version (n) {
|
|
154
|
+
if (typeof n === 'string') {
|
|
155
|
+
this.#_version = n;
|
|
156
|
+
} else {
|
|
157
|
+
throw new Error('Version must be a string!');
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Description
|
|
163
|
+
*
|
|
164
|
+
* @public
|
|
165
|
+
* @memberof StoryFormat
|
|
166
|
+
* @returns {string} Description
|
|
167
|
+
*/
|
|
168
|
+
get description () { return this.#_description; }
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* @param {string} d - Replacement description
|
|
172
|
+
*/
|
|
173
|
+
set description (d) {
|
|
174
|
+
if (typeof d === 'string') {
|
|
175
|
+
this.#_description = d;
|
|
176
|
+
} else {
|
|
177
|
+
throw new Error('Description must be a string!');
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Author
|
|
183
|
+
*
|
|
184
|
+
* @public
|
|
185
|
+
* @memberof StoryFormat
|
|
186
|
+
* @returns {string} Author
|
|
187
|
+
*/
|
|
188
|
+
get author () { return this.#_author; }
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* @param {string} a - Replacement author
|
|
192
|
+
*/
|
|
193
|
+
set author (a) {
|
|
194
|
+
if (typeof a === 'string') {
|
|
195
|
+
this.#_author = a;
|
|
196
|
+
} else {
|
|
197
|
+
throw new Error('Author must be a string!');
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Image
|
|
203
|
+
*
|
|
204
|
+
* @public
|
|
205
|
+
* @memberof StoryFormat
|
|
206
|
+
* @returns {string} Image
|
|
207
|
+
*/
|
|
208
|
+
get image () { return this.#_image; }
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* @param {string} i - Replacement image
|
|
212
|
+
*/
|
|
213
|
+
set image (i) {
|
|
214
|
+
if (typeof i === 'string') {
|
|
215
|
+
this.#_image = i;
|
|
216
|
+
} else {
|
|
217
|
+
throw new Error('Image must be a string!');
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* URL
|
|
223
|
+
*
|
|
224
|
+
* @public
|
|
225
|
+
* @memberof StoryFormat
|
|
226
|
+
* @returns {string} URL
|
|
227
|
+
*/
|
|
228
|
+
get url () { return this.#_url; }
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* @param {string} u - Replacement URL
|
|
232
|
+
*/
|
|
233
|
+
set url (u) {
|
|
234
|
+
if (typeof u === 'string') {
|
|
235
|
+
this.#_url = u;
|
|
236
|
+
} else {
|
|
237
|
+
throw new Error('URL must be a string!');
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* License
|
|
243
|
+
*
|
|
244
|
+
* @public
|
|
245
|
+
* @memberof StoryFormat
|
|
246
|
+
* @returns {string} License
|
|
247
|
+
*/
|
|
248
|
+
get license () { return this.#_license; }
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* @param {string} l - Replacement license
|
|
252
|
+
*/
|
|
253
|
+
set license (l) {
|
|
254
|
+
if (typeof l === 'string') {
|
|
255
|
+
this.#_license = l;
|
|
256
|
+
} else {
|
|
257
|
+
throw new Error('License must be a string!');
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Proofing
|
|
263
|
+
*
|
|
264
|
+
* @public
|
|
265
|
+
* @memberof StoryFormat
|
|
266
|
+
* @returns {boolean} Proofing
|
|
267
|
+
*/
|
|
268
|
+
get proofing () { return this.#_proofing; }
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* @param {boolean} p - Replacement proofing
|
|
272
|
+
*/
|
|
273
|
+
set proofing (p) {
|
|
274
|
+
if (typeof p === 'boolean') {
|
|
275
|
+
this.#_proofing = p;
|
|
276
|
+
} else {
|
|
277
|
+
throw new Error('Proofing must be a Boolean!');
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Source
|
|
283
|
+
*
|
|
284
|
+
* @public
|
|
285
|
+
* @memberof StoryFormat
|
|
286
|
+
* @returns {string} Source
|
|
287
|
+
*/
|
|
288
|
+
get source () { return this.#_source; }
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* @param {string} s - Replacement source
|
|
292
|
+
*/
|
|
293
|
+
set source (s) {
|
|
294
|
+
if (typeof s === 'string') {
|
|
295
|
+
this.#_source = s;
|
|
296
|
+
} else {
|
|
297
|
+
throw new Error('Source must be a String!');
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
package/src/StoryFormatParser.js
CHANGED
|
@@ -1,65 +1,142 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @class StoryFormatParser
|
|
5
|
-
* @module StoryFormatParser
|
|
6
|
-
*/
|
|
7
|
-
class StoryFormatParser {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
1
|
+
import StoryFormat from './StoryFormat.js';
|
|
2
|
+
import semver from 'semver';
|
|
3
|
+
/**
|
|
4
|
+
* @class StoryFormatParser
|
|
5
|
+
* @module StoryFormatParser
|
|
6
|
+
*/
|
|
7
|
+
export default class StoryFormatParser {
|
|
8
|
+
/**
|
|
9
|
+
* Parse a Story Format file
|
|
10
|
+
*
|
|
11
|
+
* @public
|
|
12
|
+
* @static
|
|
13
|
+
* @memberof StoryFormatParser
|
|
14
|
+
* @function parse
|
|
15
|
+
* @param {string} contents - Content
|
|
16
|
+
* @returns {StoryFormat} StoryFormat object
|
|
17
|
+
*/
|
|
18
|
+
static parse (contents) {
|
|
19
|
+
// Harlowe has malformed JSON, so we have to test for it
|
|
20
|
+
const harlowePosition = contents.indexOf('harlowe');
|
|
21
|
+
|
|
22
|
+
if (harlowePosition !== -1) {
|
|
23
|
+
// The 'setup' property is malformed
|
|
24
|
+
const setupPosition = contents.lastIndexOf(',"setup": function');
|
|
25
|
+
contents = contents.slice(0, setupPosition) + '}';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Find the start of story format or -1, if not found
|
|
29
|
+
const openingCurlyBracketPosition = contents.indexOf('{');
|
|
30
|
+
// Find the end of story format or -1, if not found
|
|
31
|
+
const closingCurlyBracketPosition = contents.lastIndexOf('}');
|
|
32
|
+
|
|
33
|
+
// Look for JSON among the story format
|
|
34
|
+
// If either is -1, this is not valid JSON
|
|
35
|
+
if (openingCurlyBracketPosition === -1 || closingCurlyBracketPosition === -1) {
|
|
36
|
+
// Either start or end curly brackets were now found!
|
|
37
|
+
throw new Error('Unable to find Twine2 JSON chunk!');
|
|
38
|
+
} else {
|
|
39
|
+
// Slice out the JSON based on curly brackets
|
|
40
|
+
contents = contents.slice(openingCurlyBracketPosition, closingCurlyBracketPosition + 1);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Create an object literal
|
|
44
|
+
let jsonContent = {};
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
jsonContent = JSON.parse(contents);
|
|
48
|
+
} catch (event) {
|
|
49
|
+
throw new Error('Unable to parse Twine2 JSON chunk!');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The following keys are found in most or all story formats:
|
|
54
|
+
* - name: (string) Optional. Name of the story format.
|
|
55
|
+
* (Omitting the name will lead to an Untitled Story Format.)
|
|
56
|
+
* - version: (string) Required, and semantic version-style formatting
|
|
57
|
+
* (x.y.z, e.g., 1.2.1) of the version is also required.
|
|
58
|
+
* - author: (string) Optional.
|
|
59
|
+
* - description: (string) Optional.
|
|
60
|
+
* - image: (string) Optional. The filename of an image (ideally SVG)
|
|
61
|
+
* served from the same directory as the format.js file.
|
|
62
|
+
* - url: (string) Optional. The URL of the directory containing the format.js file.
|
|
63
|
+
* - license: (string) Optional.
|
|
64
|
+
* - proofing: (boolean) Optional (defaults to false). True if the story format
|
|
65
|
+
* is a "proofing" format. The distinction is relevant only in the Twine 2 UI.
|
|
66
|
+
* - source: (string) Required. Full HTML output of the story format.
|
|
67
|
+
* (See: https://github.com/iftechfoundation/twine-specs/blob/master/twine-2-storyformats-spec.md)
|
|
68
|
+
*/
|
|
69
|
+
|
|
70
|
+
// Name is optional, so we have to test for it
|
|
71
|
+
if (!Object.prototype.hasOwnProperty.call(jsonContent, 'name')) {
|
|
72
|
+
// Use the default name
|
|
73
|
+
jsonContent.name = 'Untitled Story Format';
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Author is optional, so we have to test for it
|
|
77
|
+
if (!Object.prototype.hasOwnProperty.call(jsonContent, 'author')) {
|
|
78
|
+
// Use the default author
|
|
79
|
+
jsonContent.author = '';
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Description is optional, so we have to test for it
|
|
83
|
+
if (!Object.prototype.hasOwnProperty.call(jsonContent, 'description')) {
|
|
84
|
+
// Use the default description
|
|
85
|
+
jsonContent.description = '';
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Image is optional, so we have to test for it
|
|
89
|
+
if (!Object.prototype.hasOwnProperty.call(jsonContent, 'image')) {
|
|
90
|
+
// Use the default image
|
|
91
|
+
jsonContent.image = '';
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// URL is optional, so we have to test for it
|
|
95
|
+
if (!Object.prototype.hasOwnProperty.call(jsonContent, 'url')) {
|
|
96
|
+
// Use the default url
|
|
97
|
+
jsonContent.url = '';
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// License is optional, so we have to test for it
|
|
101
|
+
if (!Object.prototype.hasOwnProperty.call(jsonContent, 'license')) {
|
|
102
|
+
// Use the default license
|
|
103
|
+
jsonContent.license = '';
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Proofing is optional, so we have to test for it
|
|
107
|
+
if (!Object.prototype.hasOwnProperty.call(jsonContent, 'proofing')) {
|
|
108
|
+
// Use the default proofing
|
|
109
|
+
jsonContent.proofing = false;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Version is required, so we have to test for it
|
|
113
|
+
if (!Object.prototype.hasOwnProperty.call(jsonContent, 'version')) {
|
|
114
|
+
// Throw error
|
|
115
|
+
throw new Error('Processed story format does not have required version property!');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Test if version is semantic-style, which is required
|
|
119
|
+
if (semver.valid(jsonContent.version) === null) {
|
|
120
|
+
throw new Error('Processed story format\'s version is not a valid semantic value!');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Source is required, so we have to test for it
|
|
124
|
+
if (!Object.prototype.hasOwnProperty.call(jsonContent, 'source')) {
|
|
125
|
+
// Throw error
|
|
126
|
+
throw new Error('Processed story format does not have required source property!');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Pass all values to the constructor and return the result
|
|
130
|
+
return new StoryFormat(
|
|
131
|
+
jsonContent.name,
|
|
132
|
+
jsonContent.version,
|
|
133
|
+
jsonContent.description,
|
|
134
|
+
jsonContent.author,
|
|
135
|
+
jsonContent.image,
|
|
136
|
+
jsonContent.url,
|
|
137
|
+
jsonContent.license,
|
|
138
|
+
jsonContent.proofing,
|
|
139
|
+
jsonContent.source
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
}
|