extwee 2.0.5 → 2.2.0

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.
Files changed (215) hide show
  1. package/.eslintrc.json +25 -25
  2. package/.github/FUNDING.yml +3 -0
  3. package/.github/dependabot.yml +11 -0
  4. package/.github/workflows/nodejs.yml +25 -24
  5. package/.travis.yml +13 -13
  6. package/CODE_OF_CONDUCT.md +82 -82
  7. package/LICENSE +21 -21
  8. package/README.md +173 -36
  9. package/SECURITY.md +12 -12
  10. package/babel.config.json +18 -22
  11. package/build/extwee +0 -0
  12. package/build/extwee.exe +0 -0
  13. package/build/extwee.web.min.js +2 -0
  14. package/build/extwee.web.min.js.LICENSE.txt +1 -0
  15. package/docs/.nojekyll +0 -0
  16. package/docs/README.md +167 -0
  17. package/docs/_sidebar.md +19 -0
  18. package/docs/examples/dynamicPassages.md +28 -0
  19. package/docs/examples/jsonToTwee.md +23 -0
  20. package/docs/examples/twsToTwee.md +25 -0
  21. package/docs/formats/json.md +17 -0
  22. package/docs/formats/twee.md +13 -0
  23. package/docs/formats/twine1HTML.md +13 -0
  24. package/docs/formats/twine2ArchiveHTML.md +13 -0
  25. package/docs/formats/twine2HTML.md +13 -0
  26. package/docs/formats/tws.md +9 -0
  27. package/docs/index.html +26 -0
  28. package/docs/install/binaries.md +9 -0
  29. package/docs/install/npm.md +20 -0
  30. package/docs/install/npx.md +9 -0
  31. package/docs/objects/passage.md +47 -0
  32. package/docs/objects/story.md +70 -0
  33. package/docs/objects/storyformat.md +27 -0
  34. package/index.html +22 -0
  35. package/index.js +29 -31
  36. package/package.json +65 -58
  37. package/src/JSON/parse.js +128 -0
  38. package/src/Passage.js +298 -202
  39. package/src/Story.js +650 -489
  40. package/src/StoryFormat/parse.js +134 -0
  41. package/src/StoryFormat.js +259 -300
  42. package/src/TWS/parse.js +86 -0
  43. package/src/Twee/parse.js +157 -0
  44. package/src/Twine1HTML/compile.js +58 -0
  45. package/src/Twine1HTML/parse.js +134 -0
  46. package/src/Twine2ArchiveHTML/compile.js +36 -0
  47. package/src/Twine2ArchiveHTML/parse.js +49 -0
  48. package/src/Twine2HTML/compile.js +35 -0
  49. package/src/Twine2HTML/parse.js +348 -0
  50. package/src/extwee.js +206 -0
  51. package/test/CLI/CLI.test.js +49 -0
  52. package/test/CLI/files/example.json +1 -0
  53. package/test/CLI/files/example6.twee +22 -0
  54. package/test/{Roundtrip → CLI/files}/harlowe.js +2 -2
  55. package/test/CLI/{input.html → files/input.html} +47 -47
  56. package/test/CLI/files/output/test.twee +0 -0
  57. package/test/CLI/{tweeExample.twee → files/tweeExample.twee} +17 -17
  58. package/test/CLI/files/twine1/LICENSE.txt +32 -0
  59. package/test/CLI/files/twine1/code.js +5 -0
  60. package/test/CLI/files/twine1/engine.js +43 -0
  61. package/test/CLI/files/twine1/header.html +325 -0
  62. package/test/CLI/files/twine1Test.html +371 -0
  63. package/test/{HTMLParser → CLI/files}/twineExample.html +16 -15
  64. package/test/JSON/JSON.Parse.test.js +316 -0
  65. package/test/Passage.test.js +175 -104
  66. package/test/Roundtrip/{Example1.html → Files/Example1.html} +63 -63
  67. package/test/Roundtrip/Files/LICENSE +19 -0
  68. package/test/Roundtrip/Files/example1.twee +10 -0
  69. package/test/Roundtrip/{example2.twee → Files/example2.twee} +27 -18
  70. package/test/Roundtrip/Files/example4.twee +27 -0
  71. package/test/{StoryFormatParser → Roundtrip/Files}/harlowe.js +2 -2
  72. package/test/Roundtrip/{round.html → Files/round.html} +6 -7
  73. package/test/Roundtrip/Roundtrip.test.js +54 -0
  74. package/test/Story.test.js +624 -355
  75. package/test/StoryFormat/StoryFormat.Parse.test.js +91 -0
  76. package/test/{StoryFormatParser → StoryFormat/StoryFormatParser}/example.js +3 -3
  77. package/test/{StoryFormatParser → StoryFormat/StoryFormatParser}/example2.js +3 -3
  78. package/test/{CLI → StoryFormat/StoryFormatParser}/harlowe.js +2 -2
  79. package/test/StoryFormat.test.js +152 -152
  80. package/test/TWS/Parse.test.js +78 -0
  81. package/test/TWS/TWSParser/Example1.tws +150 -0
  82. package/test/TWS/TWSParser/Example5.tws +414 -0
  83. package/test/TWS/TWSParser/noscale.tws +0 -0
  84. package/test/TWS/TWSParser/nostory.tws +0 -0
  85. package/test/Twee/Twee.Parse.test.js +76 -0
  86. package/test/{TweeParser → Twee/TweeParser}/emptytags.twee +2 -2
  87. package/test/{TweeParser → Twee/TweeParser}/example.twee +32 -32
  88. package/test/{TweeParser → Twee/TweeParser}/missing.twee +19 -19
  89. package/test/{TweeParser → Twee/TweeParser}/multipleScriptPassages.twee +19 -19
  90. package/test/{TweeParser → Twee/TweeParser}/multipleStyleTag.twee +19 -19
  91. package/test/{TweeParser → Twee/TweeParser}/multipletags.twee +10 -10
  92. package/test/{TweeParser → Twee/TweeParser}/noTitle.twee +2 -2
  93. package/test/{TweeParser → Twee/TweeParser}/notes.twee +16 -16
  94. package/test/{TweeParser → Twee/TweeParser}/pasagemetadataerror.twee +2 -2
  95. package/test/{TweeParser → Twee/TweeParser}/scriptPassage.twee +16 -16
  96. package/test/{TweeParser → Twee/TweeParser}/singletag.twee +13 -13
  97. package/test/{TweeParser → Twee/TweeParser}/startMetadata.twee +14 -14
  98. package/test/{TweeParser → Twee/TweeParser}/storydataerror.twee +25 -25
  99. package/test/{TweeParser → Twee/TweeParser}/stylePassage.twee +16 -16
  100. package/test/{Story → Twee/TweeParser}/test.twee +25 -25
  101. package/test/Twine1HTML/Twine1HTML.Compile.test.js +180 -0
  102. package/test/Twine1HTML/Twine1HTML.Parse.test.js +183 -0
  103. package/test/Twine1HTML/Twine1HTMLCompiler/Twine1/LICENSE +674 -0
  104. package/test/Twine1HTML/Twine1HTMLCompiler/Twine1/engine.js +43 -0
  105. package/test/Twine1HTML/Twine1HTMLCompiler/Twine1/jquery.js +4 -0
  106. package/test/Twine1HTML/Twine1HTMLCompiler/Twine1/modernizr.js +4 -0
  107. package/test/Twine1HTML/Twine1HTMLCompiler/engineTest.html +1 -0
  108. package/test/Twine1HTML/Twine1HTMLCompiler/jonah-1.4.2/LICENSE +32 -0
  109. package/test/Twine1HTML/Twine1HTMLCompiler/jonah-1.4.2/code.js +4 -0
  110. package/test/Twine1HTML/Twine1HTMLCompiler/jonah-1.4.2/header.html +327 -0
  111. package/test/Twine1HTML/Twine1HTMLCompiler/test.html +0 -0
  112. package/test/Twine1HTML/Twine1HTMLCompiler/test1.html +6 -0
  113. package/test/Twine1HTML/Twine1HTMLCompiler/test2.html +6 -0
  114. package/test/Twine1HTML/Twine1HTMLCompiler/test3.html +43 -0
  115. package/test/Twine1HTML/Twine1HTMLCompiler/test4.html +372 -0
  116. package/test/Twine1HTML/Twine1HTMLCompiler/test5.html +372 -0
  117. package/test/Twine2ArchiveHTML/Twine2ArchiveHTML.Compile.test.js +35 -0
  118. package/test/Twine2ArchiveHTML/Twine2ArchiveHTML.Parse.test.js +25 -0
  119. package/test/Twine2ArchiveHTML/Twine2ArchiveHTMLCompiler/test1.html +6 -0
  120. package/test/Twine2ArchiveHTML/Twine2ArchiveHTMLParser/test1.html +3 -0
  121. package/test/Twine2HTML/Twine2HTML.Compile.test.js +224 -0
  122. package/test/Twine2HTML/Twine2HTML.Parse.test.js +172 -0
  123. package/test/{HTMLWriter → Twine2HTML/Twine2HTMLCompiler}/creator.html +4 -5
  124. package/test/{CLI → Twine2HTML/Twine2HTMLCompiler}/example6.twee +15 -15
  125. package/test/{HTMLWriter → Twine2HTML/Twine2HTMLCompiler}/missingStoryTitle.twee +29 -29
  126. package/test/{HTMLWriter → Twine2HTML/Twine2HTMLCompiler}/test11.html +1 -3
  127. package/test/{HTMLWriter → Twine2HTML/Twine2HTMLCompiler}/test2.html +10 -11
  128. package/test/{HTMLWriter → Twine2HTML/Twine2HTMLCompiler}/test3.html +1 -2
  129. package/test/{HTMLWriter → Twine2HTML/Twine2HTMLCompiler}/test4.html +4 -5
  130. package/test/{HTMLWriter → Twine2HTML/Twine2HTMLCompiler}/test6.html +1 -2
  131. package/test/{HTMLParser → Twine2HTML/Twine2HTMLParser}/Example1.html +52 -52
  132. package/test/{HTMLParser → Twine2HTML/Twine2HTMLParser}/Tags.html +15 -15
  133. package/test/{HTMLParser → Twine2HTML/Twine2HTMLParser}/lyingStartnode.html +15 -15
  134. package/test/{HTMLParser → Twine2HTML/Twine2HTMLParser}/lyingTagColors.html +48 -48
  135. package/test/{HTMLParser → Twine2HTML/Twine2HTMLParser}/missingCreator.html +11 -11
  136. package/test/{HTMLParser → Twine2HTML/Twine2HTMLParser}/missingCreatorVersion.html +11 -11
  137. package/test/{HTMLParser → Twine2HTML/Twine2HTMLParser}/missingFormat.html +11 -11
  138. package/test/{HTMLParser → Twine2HTML/Twine2HTMLParser}/missingFormatVersion.html +11 -11
  139. package/test/{HTMLParser → Twine2HTML/Twine2HTMLParser}/missingIFID.html +11 -11
  140. package/test/{HTMLParser → Twine2HTML/Twine2HTMLParser}/missingName.html +33 -33
  141. package/test/{HTMLParser → Twine2HTML/Twine2HTMLParser}/missingPID.html +15 -15
  142. package/test/{HTMLParser → Twine2HTML/Twine2HTMLParser}/missingPassageName.html +15 -15
  143. package/test/{HTMLParser → Twine2HTML/Twine2HTMLParser}/missingPassageTags.html +15 -15
  144. package/test/{HTMLParser → Twine2HTML/Twine2HTMLParser}/missingPosition.html +15 -15
  145. package/test/{HTMLParser → Twine2HTML/Twine2HTMLParser}/missingScript.html +14 -14
  146. package/test/{HTMLParser → Twine2HTML/Twine2HTMLParser}/missingSize.html +35 -35
  147. package/test/{HTMLParser → Twine2HTML/Twine2HTMLParser}/missingStartnode.html +11 -11
  148. package/test/{HTMLParser → Twine2HTML/Twine2HTMLParser}/missingStyle.html +14 -14
  149. package/test/{HTMLParser → Twine2HTML/Twine2HTMLParser}/missingZoom.html +11 -11
  150. package/test/Twine2HTML/Twine2HTMLParser/twineExample.html +23 -0
  151. package/test/{HTMLParser → Twine2HTML/Twine2HTMLParser}/twineExample2.html +15 -15
  152. package/test/{HTMLParser → Twine2HTML/Twine2HTMLParser}/twineExample3.html +15 -15
  153. package/web-index.js +29 -0
  154. package/webpack.config.js +12 -0
  155. package/bin/extwee.js +0 -47
  156. package/src/FileReader.js +0 -33
  157. package/src/HTMLParser.js +0 -343
  158. package/src/HTMLWriter.js +0 -231
  159. package/src/StoryFormatParser.js +0 -142
  160. package/src/TweeParser.js +0 -161
  161. package/src/TweeWriter.js +0 -98
  162. package/story-formats/chapbook-1.2.0/format.js +0 -1
  163. package/story-formats/chapbook-1.2.0/logo.svg +0 -1
  164. package/story-formats/harlowe-1.2.4/format.js +0 -1
  165. package/story-formats/harlowe-1.2.4/icon.svg +0 -78
  166. package/story-formats/harlowe-2.1.0/format.js +0 -2
  167. package/story-formats/harlowe-2.1.0/icon.svg +0 -78
  168. package/story-formats/harlowe-3.1.0/format.js +0 -3
  169. package/story-formats/harlowe-3.1.0/icon.svg +0 -78
  170. package/story-formats/paperthin-1.0.0/format.js +0 -1
  171. package/story-formats/paperthin-1.0.0/icon.svg +0 -5
  172. package/story-formats/snowman-1.4.0/format.js +0 -1
  173. package/story-formats/snowman-1.4.0/icon.svg +0 -436
  174. package/story-formats/snowman-2.0.2/format.js +0 -1
  175. package/story-formats/snowman-2.0.2/icon.svg +0 -436
  176. package/story-formats/sugarcube-1.0.35/LICENSE +0 -23
  177. package/story-formats/sugarcube-1.0.35/format.js +0 -1
  178. package/story-formats/sugarcube-1.0.35/icon.svg +0 -56
  179. package/story-formats/sugarcube-2.31.1/LICENSE +0 -22
  180. package/story-formats/sugarcube-2.31.1/format.js +0 -1
  181. package/story-formats/sugarcube-2.31.1/icon.svg +0 -56
  182. package/test/CLI/test2.html +0 -47
  183. package/test/CLI/twineExample.html +0 -15
  184. package/test/CLI.test.js +0 -30
  185. package/test/FileReader/t1.txt +0 -1
  186. package/test/FileReader.test.js +0 -14
  187. package/test/HTMLParser.test.js +0 -177
  188. package/test/HTMLWriter/example6.twee +0 -16
  189. package/test/HTMLWriter.test.js +0 -289
  190. package/test/Roundtrip/example1.twee +0 -21
  191. package/test/Roundtrip.test.js +0 -48
  192. package/test/Story/startmeta.twee +0 -29
  193. package/test/StoryFormatParser.test.js +0 -91
  194. package/test/TweeParser/test.twee +0 -25
  195. package/test/TweeParser.test.js +0 -79
  196. package/test/TweeWriter/test1.twee +0 -18
  197. package/test/TweeWriter/test3.twee +0 -12
  198. package/test/TweeWriter/test4.twee +0 -14
  199. package/test/TweeWriter/test5.twee +0 -20
  200. package/test/TweeWriter.test.js +0 -85
  201. /package/test/CLI/{test.twee → files/test.twee} +0 -0
  202. /package/test/{StoryFormatParser → StoryFormat/StoryFormatParser}/format.js +0 -0
  203. /package/test/{StoryFormatParser → StoryFormat/StoryFormatParser}/format_doublename.js +0 -0
  204. /package/test/{StoryFormatParser → StoryFormat/StoryFormatParser}/missingAuthor.js +0 -0
  205. /package/test/{StoryFormatParser → StoryFormat/StoryFormatParser}/missingDescription.js +0 -0
  206. /package/test/{StoryFormatParser → StoryFormat/StoryFormatParser}/missingImage.js +0 -0
  207. /package/test/{StoryFormatParser → StoryFormat/StoryFormatParser}/missingLicense.js +0 -0
  208. /package/test/{StoryFormatParser → StoryFormat/StoryFormatParser}/missingName.js +0 -0
  209. /package/test/{StoryFormatParser → StoryFormat/StoryFormatParser}/missingProofing.js +0 -0
  210. /package/test/{StoryFormatParser → StoryFormat/StoryFormatParser}/missingSource.js +0 -0
  211. /package/test/{StoryFormatParser → StoryFormat/StoryFormatParser}/missingURL.js +0 -0
  212. /package/test/{StoryFormatParser → StoryFormat/StoryFormatParser}/missingVersion.js +0 -0
  213. /package/test/{StoryFormatParser → StoryFormat/StoryFormatParser}/versionWrong.js +0 -0
  214. /package/test/{HTMLWriter → Twine2HTML/Twine2HTMLCompiler}/TestTags.html +0 -0
  215. /package/test/{HTMLParser → Twine2HTML/Twine2HTMLParser}/tagColors.html +0 -0
@@ -0,0 +1,224 @@
1
+ import { parse as parseStoryFormat } from '../../src/StoryFormat/parse.js';
2
+ import { parse as parseTwine2HTML } from '../../src/Twine2HTML/parse.js';
3
+ import { compile as compileTwine2HTML } from '../../src/Twine2HTML/compile.js';
4
+ import Story from '../../src/Story.js';
5
+ import Passage from '../../src/Passage.js';
6
+ import { readFileSync } from 'node:fs';
7
+
8
+ describe('Twine2HTMLCompiler', () => {
9
+ describe('compile()', () => {
10
+ it('story should be instanceof Story', () => {
11
+ expect(() => { compileTwine2HTML({}); }).toThrow();
12
+ });
13
+
14
+ it('storyFormat should be instanceof StoryFormat', () => {
15
+ const s = new Story();
16
+ expect(() => { compileTwine2HTML(s, {}); }).toThrow();
17
+ });
18
+
19
+ it('Read, write, and read HTML', () => {
20
+ // Read HTML.
21
+ const fr = readFileSync('test/Twine2HTML/Twine2HTMLParser/twineExample3.html', 'utf-8');
22
+
23
+ // Parse HTML.
24
+ const story = parseTwine2HTML(fr);
25
+
26
+ // Read StoryFormat.
27
+ const fr2 = readFileSync('test/StoryFormat/StoryFormatParser/format.js', 'utf-8');
28
+
29
+ // Parse StoryFormat.
30
+ const storyFormat = parseStoryFormat(fr2);
31
+
32
+ // Write HTML.
33
+ const fr3 = compileTwine2HTML(story, storyFormat);
34
+
35
+ // Parse HTML.
36
+ const story2 = parseTwine2HTML(fr3);
37
+
38
+ // Test both names to be the same.
39
+ expect(story.name).toBe(story2.name);
40
+ });
41
+
42
+ it('Should write one and two-tag passages', () => {
43
+ // Read HTML.
44
+ const fr = readFileSync('test/Twine2HTML/Twine2HTMLCompiler/TestTags.html', 'utf-8');
45
+
46
+ // Parse HTML.
47
+ const story = parseTwine2HTML(fr);
48
+
49
+ // Read StoryFormat.
50
+ const fr2 = readFileSync('test/StoryFormat/StoryFormatParser/format.js', 'utf-8');
51
+
52
+ // Parse StoryFormat.
53
+ const storyFormat = parseStoryFormat(fr2);
54
+
55
+ // Write HTML.
56
+ const fr3 = compileTwine2HTML(story, storyFormat);
57
+
58
+ // Parse HTML.
59
+ const story2 = parseTwine2HTML(fr3);
60
+
61
+ let tags = '';
62
+ let tags2 = '';
63
+
64
+ // Combine contents of tags.
65
+ story.forEachPassage((p) => {
66
+ tags += p.tags.join('');
67
+ });
68
+
69
+ // Combine contents of tags.
70
+ story2.forEachPassage((p) => {
71
+ tags2 += p.tags.join('');
72
+ });
73
+
74
+ // Test combination tags.
75
+ // They should be the same.
76
+ expect(tags).toBe(tags2);
77
+ });
78
+
79
+ it('Should not add optional position to passages', () => {
80
+ // Create Story.
81
+ const story = new Story();
82
+ // Add passage.
83
+ story.addPassage(new Passage('A'));
84
+ // Add passage.
85
+ story.addPassage(new Passage('B'));
86
+ // Add StoryTitle
87
+ story.addPassage(new Passage('StoryTitle', 'Title'));
88
+ // Add Start
89
+ story.addPassage(new Passage('Start', 'Content'));
90
+
91
+ // Read StoryFormat.
92
+ const fr2 = readFileSync('test/StoryFormat/StoryFormatParser/format.js', 'utf-8');
93
+
94
+ // Parse StoryFormat.
95
+ const storyFormat = parseStoryFormat(fr2);
96
+
97
+ // Set start
98
+ story.start = 'Start';
99
+
100
+ // Write out HTML with story and storyFormat.
101
+ // (Will add position to passages without them.)
102
+ const fr3 = compileTwine2HTML(story, storyFormat);
103
+
104
+ // Parse new HTML file.
105
+ const story2 = parseTwine2HTML(fr3);
106
+
107
+ // Verify none of the directly created passages have position.
108
+ story.forEachPassage((passage) => {
109
+ expect(Object.prototype.hasOwnProperty.call(passage.metadata, 'position')).toBe(false);
110
+ });
111
+
112
+ // Verify none parsed passages have position.
113
+ story2.forEachPassage((passage) => {
114
+ expect(Object.prototype.hasOwnProperty.call(passage.metadata, 'position')).toBe(false);
115
+ });
116
+ });
117
+
118
+ it("Don't write creator if missing originally", () => {
119
+ // Create a new story.
120
+ const story = new Story();
121
+
122
+ // Create a passage.
123
+ story.addPassage(new Passage('A'));
124
+
125
+ // Create another passage.
126
+ story.addPassage(new Passage('B'));
127
+
128
+ // Create another passage.
129
+ story.addPassage(new Passage('StoryTitle', 'Title'));
130
+
131
+ // Add Start
132
+ story.addPassage(new Passage('Start', 'Content'));
133
+
134
+ // Set start
135
+ story.start = 'Start';
136
+
137
+ // Read StoryFormat.
138
+ const fr2 = readFileSync('test/StoryFormat/StoryFormatParser/format.js', 'utf-8');
139
+
140
+ // Parse StoryFormat.
141
+ const storyFormat = parseStoryFormat(fr2);
142
+
143
+ // Write the HTML.
144
+ const fr3 = compileTwine2HTML(story, storyFormat);
145
+
146
+ // Parse HTML.
147
+ const story2 = parseTwine2HTML(fr3);
148
+
149
+ // Test creator (should be default)
150
+ expect(story.creator).toBe('extwee');
151
+
152
+ // Test parsed creator (should be default)
153
+ expect(story2.creator).toBe('extwee');
154
+
155
+ // Creator should be the same
156
+ expect(story.creator).toBe(story2.creator);
157
+ });
158
+
159
+ it('Throw error if StoryTitle does not exist', () => {
160
+ // Create a new story.
161
+ const story = new Story();
162
+
163
+ // Create a passage.
164
+ story.addPassage(new Passage('A'));
165
+
166
+ // Read StoryFormat.
167
+ const fr2 = readFileSync('test/StoryFormat/StoryFormatParser/format.js', 'utf-8');
168
+
169
+ // Parse StoryFormat.
170
+ const storyFormat = parseStoryFormat(fr2);
171
+
172
+ expect(() => {
173
+ compileTwine2HTML(story, storyFormat);
174
+ }).toThrow();
175
+ });
176
+
177
+ it('Throw error if no start or Start exists', () => {
178
+ // Create a new story.
179
+ const story = new Story();
180
+
181
+ // Create a passage.
182
+ story.addPassage(new Passage('A'));
183
+
184
+ // Create StoryTitle
185
+ story.addPassage(new Passage('StoryTitle', 'Name'));
186
+
187
+ // Read StoryFormat.
188
+ const fr2 = readFileSync('test/StoryFormat/StoryFormatParser/format.js', 'utf-8');
189
+
190
+ // Parse StoryFormat.
191
+ const storyFormat = parseStoryFormat(fr2);
192
+
193
+ // Throws error.
194
+ expect(() => {
195
+ compileTwine2HTML(story, storyFormat);
196
+ }).toThrow();
197
+ });
198
+
199
+ it('Throw error if starting passage property does not exist', () => {
200
+ // Create a new story.
201
+ const story = new Story();
202
+
203
+ // Create a passage.
204
+ story.addPassage(new Passage('A'));
205
+
206
+ // Create StoryTitle
207
+ story.addPassage(new Passage('StoryTitle', 'Name'));
208
+
209
+ // Set a passage that doesn't exist
210
+ story.start = 'Nope';
211
+
212
+ // Read StoryFormat.
213
+ const fr2 = readFileSync('test/StoryFormat/StoryFormatParser/format.js', 'utf-8');
214
+
215
+ // Parse StoryFormat.
216
+ const storyFormat = parseStoryFormat(fr2);
217
+
218
+ // Throws error.
219
+ expect(() => {
220
+ compileTwine2HTML(story, storyFormat);
221
+ }).toThrow();
222
+ });
223
+ });
224
+ });
@@ -0,0 +1,172 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { parse as parseTwine2HTML, escapeMetacharacters } from '../../src/Twine2HTML/parse.js';
3
+
4
+ // Pull the name and version of this project from package.json.
5
+ // These are used as the 'creator' and 'creator-version'.
6
+ const { version } = JSON.parse(readFileSync('package.json', 'utf-8'));
7
+
8
+ describe('Twine2HTMLParser', () => {
9
+ describe('#parse()', () => {
10
+ it('Should throw error if content is not a string', () => {
11
+ expect(() => { parseTwine2HTML({}); }).toThrow();
12
+ });
13
+
14
+ it('Should throw error if content is not Twine-2 style HTML', () => {
15
+ expect(() => { parseTwine2HTML(''); }).toThrow();
16
+ });
17
+
18
+ it('Should be able to parse Twine 2 HTML for story name', () => {
19
+ const fr = readFileSync('test/Twine2HTML/Twine2HTMLParser/twineExample.html', 'utf-8');
20
+ const story = parseTwine2HTML(fr);
21
+ expect(story.name).toBe('twineExample');
22
+ });
23
+
24
+ it('Should be able to parse Twine 2 HTML for correct number of passages', () => {
25
+ const fr = readFileSync('test/Twine2HTML/Twine2HTMLParser/twineExample.html', 'utf-8');
26
+ const tp = parseTwine2HTML(fr);
27
+ expect(tp.size()).toBe(5);
28
+ });
29
+
30
+ it('Should be able to correctly parse passage tags', () => {
31
+ const fr = readFileSync('test/Twine2HTML/Twine2HTMLParser/Tags.html', 'utf-8');
32
+ const story = parseTwine2HTML(fr);
33
+ const p = story.getPassageByName('Untitled Passage');
34
+ expect(p.tags).toHaveLength(2);
35
+ });
36
+
37
+ it('Should have default name', () => {
38
+ const fr = readFileSync('test/Twine2HTML/Twine2HTMLParser/missingName.html', 'utf-8');
39
+ const story = parseTwine2HTML(fr);
40
+ expect(story.name).toBe('');
41
+ });
42
+
43
+ it('Should set a missing IFID to an empty string', () => {
44
+ const fr = readFileSync('test/Twine2HTML/Twine2HTMLParser/missingIFID.html', 'utf-8');
45
+ const tp = parseTwine2HTML(fr);
46
+ expect(tp.IFID).toBe('');
47
+ });
48
+
49
+ it('Should have Extwee for creator when missing', () => {
50
+ const fr = readFileSync('test/Twine2HTML/Twine2HTMLParser/missingCreator.html', 'utf-8');
51
+ const tp = parseTwine2HTML(fr);
52
+ expect(tp.creator).toBe('extwee');
53
+ });
54
+
55
+ it('Should have correct for creatorVersion when missing', () => {
56
+ const fr = readFileSync('test/Twine2HTML/Twine2HTMLParser/missingCreatorVersion.html', 'utf-8');
57
+ const tp = parseTwine2HTML(fr);
58
+ expect(tp.creatorVersion).toBe(version);
59
+ });
60
+
61
+ it('Should have empty string as format when missing', () => {
62
+ const fr = readFileSync('test/Twine2HTML/Twine2HTMLParser/missingFormat.html', 'utf-8');
63
+ const tp = parseTwine2HTML(fr);
64
+ expect(tp.format).toBe('');
65
+ });
66
+
67
+ it('Should have empty string as formatVersion when missing', () => {
68
+ const fr = readFileSync('test/Twine2HTML/Twine2HTMLParser/missingFormatVersion.html', 'utf-8');
69
+ const tp = parseTwine2HTML(fr);
70
+ expect(tp.formatVersion).toBe('');
71
+ });
72
+
73
+ it('Should have empty string as zoom when missing', () => {
74
+ const fr = readFileSync('test/Twine2HTML/Twine2HTMLParser/missingZoom.html', 'utf-8');
75
+ const tp = parseTwine2HTML(fr);
76
+ expect(tp.zoom).toBe(0);
77
+ });
78
+
79
+ it('Should not have position if passage does not', () => {
80
+ const fr = readFileSync('test/Twine2HTML/Twine2HTMLParser/missingPosition.html', 'utf-8');
81
+ const story = parseTwine2HTML(fr);
82
+ const p = story.getPassageByName('Untitled Passage');
83
+ expect(Object.prototype.hasOwnProperty.call(p.metadata, 'position')).toBe(false);
84
+ });
85
+
86
+ it('Should not have size if passage does not', () => {
87
+ const fr = readFileSync('test/Twine2HTML/Twine2HTMLParser/missingSize.html', 'utf-8');
88
+ const story = parseTwine2HTML(fr);
89
+ const p = story.getPassageByName('Untitled Passage');
90
+ expect(Object.prototype.hasOwnProperty.call(p.metadata, 'size')).toBe(false);
91
+ });
92
+
93
+ it('Should have empty array as tags if tags is missing', () => {
94
+ const fr = readFileSync('test/Twine2HTML/Twine2HTMLParser/missingPassageTags.html', 'utf-8');
95
+ const story = parseTwine2HTML(fr);
96
+ const p = story.getPassageByName('Untitled Passage');
97
+ expect(p.tags).toHaveLength(0);
98
+ });
99
+
100
+ it('Should not have stylesheet tag if no passages exist with it', () => {
101
+ const fr = readFileSync('test/Twine2HTML/Twine2HTMLParser/missingStyle.html', 'utf-8');
102
+ const story = parseTwine2HTML(fr);
103
+ const passages = story.getPassagesByTag('stylesheet');
104
+ expect(passages.length).toBe(0);
105
+ });
106
+
107
+ it('Should not have script tag if no passages exist with it', () => {
108
+ const fr = readFileSync('test/Twine2HTML/Twine2HTMLParser/missingScript.html', 'utf-8');
109
+ const story = parseTwine2HTML(fr);
110
+ const passages = story.getPassagesByTag('script');
111
+ expect(passages.length).toBe(0);
112
+ });
113
+
114
+ it('Should have script and style tags normally', () => {
115
+ const fr = readFileSync('test/Twine2HTML/Twine2HTMLParser/Example1.html', 'utf-8');
116
+ const story = parseTwine2HTML(fr);
117
+ const scriptPassages = story.getPassagesByTag('script');
118
+ const stylesheetPassages = story.getPassagesByTag('stylesheet');
119
+ expect(scriptPassages.length).toBe(1);
120
+ expect(stylesheetPassages.length).toBe(1);
121
+ });
122
+
123
+ it('Should throw error if startNode is missing', () => {
124
+ const fr = readFileSync('test/Twine2HTML/Twine2HTMLParser/missingStartnode.html', 'utf-8');
125
+ expect(() => { parseTwine2HTML(fr); }).toThrow();
126
+ });
127
+
128
+ it('Should throw error if passage name is missing', () => {
129
+ const fr = readFileSync('test/Twine2HTML/Twine2HTMLParser/missingPassageName.html', 'utf-8');
130
+ expect(() => { parseTwine2HTML(fr); }).toThrow();
131
+ });
132
+
133
+ it('Should throw error without PID', () => {
134
+ const fr = readFileSync('test/Twine2HTML/Twine2HTMLParser/missingPID.html', 'utf-8');
135
+ expect(() => { parseTwine2HTML(fr); }).toThrow();
136
+ });
137
+
138
+ it('Should parse tag colors', () => {
139
+ const fr = readFileSync('test/Twine2HTML/Twine2HTMLParser/tagColors.html', 'utf-8');
140
+ const story = parseTwine2HTML(fr);
141
+ // Test for tag colors
142
+ const tagColors = story.tagColors;
143
+ expect(tagColors.a).toBe('red');
144
+ });
145
+
146
+ it('Should throw error if startnode is missing', () => {
147
+ const fr = readFileSync('test/Twine2HTML/Twine2HTMLParser/missingStartnode.html', 'utf-8');
148
+ expect(() => { parseTwine2HTML(fr); }).toThrow();
149
+ });
150
+
151
+ it('Should throw error when startnode has PID that does not exist', () => {
152
+ const fr = readFileSync('test/Twine2HTML/Twine2HTMLParser/lyingStartnode.html', 'utf-8');
153
+ expect(() => {
154
+ parseTwine2HTML(fr);
155
+ }).toThrow();
156
+ });
157
+
158
+ it('Do not update name and color if those attributes do not exist', () => {
159
+ const fr = readFileSync('test/Twine2HTML/Twine2HTMLParser/lyingTagColors.html', 'utf-8');
160
+ const story = parseTwine2HTML(fr);
161
+ const tagColorProperties = Object.keys(story.tagColors).length;
162
+ expect(tagColorProperties).toBe(0);
163
+ });
164
+ });
165
+
166
+ describe('#escapeMetacharacters()', () => {
167
+ it('Should escape metacharacters', () => {
168
+ /* eslint no-useless-escape: "off" */
169
+ expect(escapeMetacharacters('\\\{\\\}\\\[\\\]\\\\')).toBe('\\\\{\\\\}\\\\[\\\\]\\\\');
170
+ });
171
+ });
172
+ });
@@ -9,13 +9,12 @@
9
9
  </head>
10
10
  <body>
11
11
  <tw-story tags></tw-story>
12
- <tw-storydata name="Title" startnode="4" creator="extwee" creator-version="2.0.5" ifid="827B82ED-3279-4429-BCB6-3800F7AD3D2C" zoom="0" format="Snowman" format-version="2.0.0" options hidden>
12
+ <tw-storydata name="Title" startnode="3" creator="extwee" creator-version="2.2.0" ifid="50B062BA-5D60-4238-853E-3C2E50A4414F" zoom="0" format="" format-version="" options hidden>
13
13
  <style role="stylesheet" id="twine-user-stylesheet" type="text/twine-css"></style>
14
14
  <script role="script" id="twine-user-script" type="text/twine-javascript"></script>
15
- <tw-passagedata pid="1" name="A"></tw-passagedata>
16
- <tw-passagedata pid="2" name="B"></tw-passagedata>
17
- <tw-passagedata pid="3" name="StoryTitle">Title</tw-passagedata>
18
- <tw-passagedata pid="4" name="Start">Content</tw-passagedata>
15
+ <tw-passagedata pid="1" name="A" tags="" ></tw-passagedata>
16
+ <tw-passagedata pid="2" name="B" tags="" ></tw-passagedata>
17
+ <tw-passagedata pid="3" name="Start" tags="" >Content</tw-passagedata>
19
18
  </tw-storydata>
20
19
  <script>
21
20
  (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
@@ -1,16 +1,16 @@
1
- :: StoryTitle
2
- twineExample
3
-
4
- :: Start [tag tags] {"position": "200,200", "size": "100,100"}
5
- Content
6
-
7
- :: Style1 [stylesheet]
8
- body {background-color: green;}
9
-
10
- :: StoryData
11
- {
12
- "ifid": "2B68ECD6-348F-4CF5-96F8-549A512A8128",
13
- "format": "Harlowe",
14
- "formatVersion": "2.1.0",
15
- "zoom": "1"
1
+ :: StoryTitle
2
+ twineExample
3
+
4
+ :: Start [tag tags] {"position": "200,200", "size": "100,100"}
5
+ Content
6
+
7
+ :: Style1 [stylesheet]
8
+ body {background-color: green;}
9
+
10
+ :: StoryData
11
+ {
12
+ "ifid": "2B68ECD6-348F-4CF5-96F8-549A512A8128",
13
+ "format": "Harlowe",
14
+ "formatVersion": "2.1.0",
15
+ "zoom": "1"
16
16
  }
@@ -1,29 +1,29 @@
1
- :: StoryTitle
2
- twineExample
3
-
4
- :: Start {"position":"102,104","size":"100,100"}
5
- [[Another passage]]
6
-
7
- [[A third passage]]
8
-
9
- :: Another passage {"position":"353,60","size":"100,100"}
10
- [[A fourth passage]]
11
-
12
- [[A third passage]]
13
-
14
- :: A third passage {"position":"350,288","size":"100,100"}
15
- [[Start]]
16
-
17
- :: A fourth passage {"position":"587,197","size":"100,100"}
18
- [[A fifth passage]]
19
-
20
- :: A fifth passage {"position":"800,306","size":"100,100"}
21
- Double-click this passage to edit it.
22
-
23
- :: StoryData
24
- {
25
- "ifid": "2B68ECD6-348F-4CF5-96F8-549A512A8128",
26
- "format": "Harlowe",
27
- "formatVersion": "2.1.0",
28
- "zoom": "1"
29
- }
1
+ :: StoryTitle
2
+ twineExample
3
+
4
+ :: Start {"position":"102,104","size":"100,100"}
5
+ [[Another passage]]
6
+
7
+ [[A third passage]]
8
+
9
+ :: Another passage {"position":"353,60","size":"100,100"}
10
+ [[A fourth passage]]
11
+
12
+ [[A third passage]]
13
+
14
+ :: A third passage {"position":"350,288","size":"100,100"}
15
+ [[Start]]
16
+
17
+ :: A fourth passage {"position":"587,197","size":"100,100"}
18
+ [[A fifth passage]]
19
+
20
+ :: A fifth passage {"position":"800,306","size":"100,100"}
21
+ Double-click this passage to edit it.
22
+
23
+ :: StoryData
24
+ {
25
+ "ifid": "2B68ECD6-348F-4CF5-96F8-549A512A8128",
26
+ "format": "Harlowe",
27
+ "formatVersion": "2.1.0",
28
+ "zoom": "1"
29
+ }
@@ -100,12 +100,10 @@ var saveAs=saveAs||navigator.msSaveBlob&&navigator.msSaveBlob.bind(navigator)||f
100
100
  <div id="init-lacking">Your browser lacks required capabilities. Please upgrade it or switch to another to continue.</div>
101
101
  <div id="init-loading"><div>Loading&hellip;</div></div>
102
102
  </div>
103
- <tw-storydata name="twineExample" startnode="2" creator="extwee" creator-version="2.0.5" ifid="2B68ECD6-348F-4CF5-96F8-549A512A8128" zoom="0" format="SugarCube" format-version="2.31.1" options hidden>
103
+ <tw-storydata name="twineExample" startnode="2" creator="extwee" creator-version="2.0.6" ifid="2B68ECD6-348F-4CF5-96F8-549A512A8128" zoom="0" format="SugarCube" format-version="2.31.1" options hidden>
104
104
  <style role="stylesheet" id="twine-user-stylesheet" type="text/twine-css">body {background-color: green;}</style>
105
105
  <script role="script" id="twine-user-script" type="text/twine-javascript"></script>
106
- <tw-passagedata pid="1" name="StoryTitle">twineExample</tw-passagedata>
107
106
  <tw-passagedata pid="2" name="Start" tags="tag tags" position="200,200" size="100,100" >Content</tw-passagedata>
108
- <tw-passagedata pid="3" name="Style1" tags="stylesheet" >body {background-color: green;}</tw-passagedata>
109
107
  </tw-storydata>
110
108
  <script id="script-sugarcube" type="text/javascript">
111
109
  /*! SugarCube JS */
@@ -9,21 +9,20 @@
9
9
  </head>
10
10
  <body>
11
11
  <tw-story tags></tw-story>
12
- <tw-storydata name="twineExample" startnode="1" creator="Twine" creator-version="2.2.1" ifid="2B68ECD6-348F-4CF5-96F8-549A512A8128" zoom="1" format="Snowman" format-version="2.0.0" options hidden>
12
+ <tw-storydata name="twineExample" startnode="1" creator="Twine" creator-version="2.2.1" ifid="2B68ECD6-348F-4CF5-96F8-549A512A8128" zoom="1" format="Harlowe" format-version="2.1.0" options hidden>
13
13
  <style role="stylesheet" id="twine-user-stylesheet" type="text/twine-css">html{font-size: 1.2em;}</style>
14
14
  <script role="script" id="twine-user-script" type="text/twine-javascript">window.test = {};</script>
15
- <tw-passagedata pid="1" name="StoryTitle">twineExample</tw-passagedata>
16
- <tw-passagedata pid="1" name="Start" position="102,104" size="100,100" >[[Another passage]]
17
-
15
+ <tw-passagedata pid="1" name="Start" tags="" position="102,104" size="100,100" >[[Another passage]]
16
+
18
17
  [[A third passage]]</tw-passagedata>
19
- <tw-passagedata pid="2" name="Another passage" position="353,60" size="100,100" >[[A fourth passage]]
20
-
18
+ <tw-passagedata pid="2" name="Another passage" tags="" position="353,60" size="100,100" >[[A fourth passage]]
19
+
21
20
  [[A third passage]] </tw-passagedata>
22
- <tw-passagedata pid="3" name="A third passage" position="350,288" size="100,100" >[[Start]]</tw-passagedata>
23
- <tw-passagedata pid="4" name="A fourth passage" position="587,197" size="100,100" >[[A fifth passage]]</tw-passagedata>
24
- <tw-passagedata pid="5" name="A fifth passage" position="800,306" size="100,100" >Double-click this passage to edit it.</tw-passagedata>
25
- <tw-passagedata pid="2" name="UserStylesheet" tags="stylesheet" >html{font-size: 1.2em;}</tw-passagedata>
26
- <tw-passagedata pid="3" name="UserScript" tags="script" >window.test = {};</tw-passagedata>
21
+ <tw-passagedata pid="3" name="A third passage" tags="" position="350,288" size="100,100" >[[Start]]</tw-passagedata>
22
+ <tw-passagedata pid="4" name="A fourth passage" tags="" position="587,197" size="100,100" >[[A fifth passage]]</tw-passagedata>
23
+ <tw-passagedata pid="5" name="A fifth passage" tags="" position="800,306" size="100,100" >Double-click this passage to edit it.</tw-passagedata>
24
+ <tw-passagedata pid="6" name="UserStylesheet" tags="stylesheet" >html{font-size: 1.2em;}</tw-passagedata>
25
+ <tw-passagedata pid="7" name="UserScript" tags="script" >window.test = {};</tw-passagedata>
27
26
  </tw-storydata>
28
27
  <script>
29
28
  (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
@@ -9,10 +9,9 @@
9
9
  </head>
10
10
  <body>
11
11
  <tw-story tags></tw-story>
12
- <tw-storydata name="TestTags" startnode="1" creator="Twine" creator-version="2.3.9" ifid="5B4E374F-E8B0-4FBB-A78E-A4150401BF24" zoom="1" format="Snowman" format-version="2.0.0" options hidden>
12
+ <tw-storydata name="TestTags" startnode="1" creator="Twine" creator-version="2.3.9" ifid="5B4E374F-E8B0-4FBB-A78E-A4150401BF24" zoom="1" format="Harlowe" format-version="3.1.0" options hidden>
13
13
  <style role="stylesheet" id="twine-user-stylesheet" type="text/twine-css"></style>
14
14
  <script role="script" id="twine-user-script" type="text/twine-javascript"></script>
15
- <tw-passagedata pid="1" name="StoryTitle">TestTags</tw-passagedata>
16
15
  <tw-passagedata pid="1" name="Untitled Passage" tags="one" position="199,100" size="100,100" >[[Another]]</tw-passagedata>
17
16
  <tw-passagedata pid="2" name="Another" tags="two three" position="399,99" size="100,100" >Double-click this passage to edit it.</tw-passagedata>
18
17
  </tw-storydata>
@@ -9,13 +9,12 @@
9
9
  </head>
10
10
  <body>
11
11
  <tw-story tags></tw-story>
12
- <tw-storydata name="Title" startnode="4" creator="extwee" creator-version="2.0.5" ifid="A1B257B5-F799-4618-9683-07B9F6BB6CE2" zoom="0" format="Snowman" format-version="2.0.0" options hidden>
12
+ <tw-storydata name="Title" startnode="3" creator="extwee" creator-version="2.2.0" ifid="83C3B47C-E799-48BA-ACBA-E103534DF477" zoom="0" format="" format-version="" options hidden>
13
13
  <style role="stylesheet" id="twine-user-stylesheet" type="text/twine-css"></style>
14
14
  <script role="script" id="twine-user-script" type="text/twine-javascript"></script>
15
- <tw-passagedata pid="1" name="A"></tw-passagedata>
16
- <tw-passagedata pid="2" name="B"></tw-passagedata>
17
- <tw-passagedata pid="3" name="StoryTitle">Title</tw-passagedata>
18
- <tw-passagedata pid="4" name="Start">Content</tw-passagedata>
15
+ <tw-passagedata pid="1" name="A" tags="" ></tw-passagedata>
16
+ <tw-passagedata pid="2" name="B" tags="" ></tw-passagedata>
17
+ <tw-passagedata pid="3" name="Start" tags="" >Content</tw-passagedata>
19
18
  </tw-storydata>
20
19
  <script>
21
20
  (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
@@ -9,11 +9,10 @@
9
9
  </head>
10
10
  <body>
11
11
  <tw-story tags></tw-story>
12
- <tw-storydata name="Name" startnode="3" creator="extwee" creator-version="2.0.5" ifid="64851070-16F0-410B-8C27-F90668C994BC" zoom="0" format="Snowman" format-version="2.0.0" options hidden>
12
+ <tw-storydata name="Name" startnode="3" creator="extwee" creator-version="2.0.6" ifid="AD1FF443-CFE8-4651-99AD-FD9E1DCB0304" zoom="0" format="Snowman" format-version="2.0.0" options hidden>
13
13
  <style role="stylesheet" id="twine-user-stylesheet" type="text/twine-css"></style>
14
14
  <script role="script" id="twine-user-script" type="text/twine-javascript"></script>
15
15
  <tw-passagedata pid="1" name="A"></tw-passagedata>
16
- <tw-passagedata pid="2" name="StoryTitle">Name</tw-passagedata>
17
16
  <tw-passagedata pid="3" name="Start">Content</tw-passagedata>
18
17
  </tw-storydata>
19
18
  <script>