extwee 2.3.11 → 2.3.12

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 (179) hide show
  1. package/CHANGELOG.md +219 -0
  2. package/CONTRIBUTING.md +305 -0
  3. package/README.md +16 -0
  4. package/build/extwee.core.min.js +1 -1
  5. package/build/extwee.twine1html.min.js +1 -1
  6. package/build/extwee.twine2archive.min.js +1 -1
  7. package/build/extwee.tws.min.js +1 -1
  8. package/package.json +8 -5
  9. package/src/Story.js +2 -2
  10. package/types/src/Story.d.ts +1 -1
  11. package/.github/FUNDING.yml +0 -3
  12. package/.github/codeql-analysis.yml +0 -51
  13. package/.github/dependabot.yml +0 -11
  14. package/.github/workflows/dependabot-automerge.yml +0 -23
  15. package/.github/workflows/nodejs.yml +0 -28
  16. package/.travis.yml +0 -13
  17. package/babel.config.json +0 -18
  18. package/docs/.nojekyll +0 -0
  19. package/docs/README.md +0 -224
  20. package/docs/_sidebar.md +0 -19
  21. package/docs/build/extwee.core.min.js +0 -1
  22. package/docs/build/extwee.twine1html.min.js +0 -1
  23. package/docs/build/extwee.twine2archive.min.js +0 -1
  24. package/docs/build/extwee.tws.min.js +0 -1
  25. package/docs/demos/compiler/extwee.core.min.js +0 -1
  26. package/docs/demos/compiler/index.css +0 -105
  27. package/docs/demos/compiler/index.html +0 -359
  28. package/docs/demos/decompile/extwee.core.min.js +0 -1
  29. package/docs/demos/decompile/index.css +0 -584
  30. package/docs/demos/decompile/index.html +0 -468
  31. package/docs/examples/dynamicPassages.md +0 -28
  32. package/docs/examples/jsonToTwee.md +0 -23
  33. package/docs/examples/twsToTwee.md +0 -25
  34. package/docs/formats/json.md +0 -17
  35. package/docs/formats/twee.md +0 -13
  36. package/docs/formats/twine1HTML.md +0 -13
  37. package/docs/formats/twine2ArchiveHTML.md +0 -13
  38. package/docs/formats/twine2HTML.md +0 -13
  39. package/docs/formats/tws.md +0 -9
  40. package/docs/index.html +0 -26
  41. package/docs/install/npm.md +0 -16
  42. package/docs/install/npx.md +0 -79
  43. package/docs/objects/passage.md +0 -47
  44. package/docs/objects/story.md +0 -69
  45. package/docs/objects/storyformat.md +0 -27
  46. package/eslint.config.js +0 -28
  47. package/extwee.config.json +0 -6
  48. package/extwee.config.md +0 -67
  49. package/jest.config.json +0 -5
  50. package/test/CLI/CLI.test.js +0 -49
  51. package/test/CLI/files/example.json +0 -1
  52. package/test/CLI/files/example6.twee +0 -22
  53. package/test/CLI/files/harlowe.js +0 -3
  54. package/test/CLI/files/input.html +0 -47
  55. package/test/CLI/files/output/test.twee +0 -0
  56. package/test/CLI/files/test.twee +0 -18
  57. package/test/CLI/files/tweeExample.twee +0 -17
  58. package/test/CLI/files/twine1/LICENSE.txt +0 -32
  59. package/test/CLI/files/twine1/code.js +0 -5
  60. package/test/CLI/files/twine1/engine.js +0 -43
  61. package/test/CLI/files/twine1/header.html +0 -325
  62. package/test/CLI/files/twine1Test.html +0 -371
  63. package/test/CLI/files/twineExample.html +0 -16
  64. package/test/Config/Config.test.js +0 -76
  65. package/test/Config/files/empty.json +0 -3
  66. package/test/Config/files/full.json +0 -8
  67. package/test/Config/files/invalid.json +0 -1
  68. package/test/Config/files/valid.json +0 -6
  69. package/test/Config/isDirectory.test.js +0 -50
  70. package/test/Config/isFile.test.js +0 -53
  71. package/test/Config/loadStoryFormat.test.js +0 -117
  72. package/test/Config/readDirectories.test.js +0 -78
  73. package/test/IFID/IFID.Generate.test.js +0 -10
  74. package/test/JSON/JSON.Parse.test.js +0 -316
  75. package/test/Objects/Passage.test.js +0 -274
  76. package/test/Objects/SnowmanCompatibility.test.js +0 -111
  77. package/test/Objects/Story.test.js +0 -1075
  78. package/test/Objects/StoryFormat.test.js +0 -219
  79. package/test/Roundtrip/Files/Example1.html +0 -64
  80. package/test/Roundtrip/Files/LICENSE +0 -19
  81. package/test/Roundtrip/Files/example1.twee +0 -10
  82. package/test/Roundtrip/Files/example2.twee +0 -27
  83. package/test/Roundtrip/Files/example4.twee +0 -27
  84. package/test/Roundtrip/Files/harlowe.js +0 -3
  85. package/test/Roundtrip/Files/round.html +0 -49
  86. package/test/Roundtrip/Roundtrip.test.js +0 -54
  87. package/test/StoryFormat/StoryFormat.Parse.test.js +0 -479
  88. package/test/TWS/Parse.test.js +0 -56
  89. package/test/TWS/TWSParser/Example5.tws +0 -414
  90. package/test/TWS/TWSParser/noscale.tws +0 -0
  91. package/test/TWS/TWSParser/nostory.tws +0 -0
  92. package/test/Twee/Twee.Escaping.test.js +0 -200
  93. package/test/Twee/Twee.Parse.test.js +0 -108
  94. package/test/Twee/TweeParser/cursed.twee +0 -16
  95. package/test/Twee/TweeParser/cycling.twee +0 -75
  96. package/test/Twee/TweeParser/emptytags.twee +0 -2
  97. package/test/Twee/TweeParser/example.twee +0 -32
  98. package/test/Twee/TweeParser/malformed.twee +0 -2
  99. package/test/Twee/TweeParser/missing.twee +0 -19
  100. package/test/Twee/TweeParser/multipleScriptPassages.twee +0 -19
  101. package/test/Twee/TweeParser/multipleStyleTag.twee +0 -19
  102. package/test/Twee/TweeParser/multipletags.twee +0 -10
  103. package/test/Twee/TweeParser/noTitle.twee +0 -2
  104. package/test/Twee/TweeParser/notes.twee +0 -16
  105. package/test/Twee/TweeParser/pasagemetadataerror.twee +0 -2
  106. package/test/Twee/TweeParser/scriptPassage.twee +0 -16
  107. package/test/Twee/TweeParser/singletag.twee +0 -13
  108. package/test/Twee/TweeParser/start.twee +0 -2
  109. package/test/Twee/TweeParser/startMetadata.twee +0 -14
  110. package/test/Twee/TweeParser/storydataerror.twee +0 -25
  111. package/test/Twee/TweeParser/style.twee +0 -16
  112. package/test/Twee/TweeParser/stylePassage.twee +0 -16
  113. package/test/Twee/TweeParser/test.twee +0 -25
  114. package/test/Twine1HTML/Twine1HTML.Compile.test.js +0 -180
  115. package/test/Twine1HTML/Twine1HTML.Parse.Web.test.js +0 -484
  116. package/test/Twine1HTML/Twine1HTML.Parse.test.js +0 -183
  117. package/test/Twine1HTML/Twine1HTMLCompiler/Twine1/LICENSE +0 -674
  118. package/test/Twine1HTML/Twine1HTMLCompiler/Twine1/engine.js +0 -43
  119. package/test/Twine1HTML/Twine1HTMLCompiler/Twine1/jquery.js +0 -4
  120. package/test/Twine1HTML/Twine1HTMLCompiler/Twine1/modernizr.js +0 -4
  121. package/test/Twine1HTML/Twine1HTMLCompiler/engineTest.html +0 -1
  122. package/test/Twine1HTML/Twine1HTMLCompiler/jonah-1.4.2/LICENSE +0 -32
  123. package/test/Twine1HTML/Twine1HTMLCompiler/jonah-1.4.2/code.js +0 -4
  124. package/test/Twine1HTML/Twine1HTMLCompiler/jonah-1.4.2/header.html +0 -327
  125. package/test/Twine1HTML/Twine1HTMLCompiler/test.html +0 -0
  126. package/test/Twine1HTML/Twine1HTMLCompiler/test1.html +0 -6
  127. package/test/Twine1HTML/Twine1HTMLCompiler/test2.html +0 -6
  128. package/test/Twine1HTML/Twine1HTMLCompiler/test3.html +0 -43
  129. package/test/Twine1HTML/Twine1HTMLCompiler/test4.html +0 -372
  130. package/test/Twine1HTML/Twine1HTMLCompiler/test5.html +0 -372
  131. package/test/Twine2ArchiveHTML/Twine2ArchiveHTML.Compile.test.js +0 -35
  132. package/test/Twine2ArchiveHTML/Twine2ArchiveHTML.Parse.Web.test.js +0 -293
  133. package/test/Twine2ArchiveHTML/Twine2ArchiveHTML.Parse.test.js +0 -42
  134. package/test/Twine2ArchiveHTML/Twine2ArchiveHTMLCompiler/test1.html +0 -6
  135. package/test/Twine2ArchiveHTML/Twine2ArchiveHTMLParser/test1.html +0 -3
  136. package/test/Twine2HTML/Twine2HTML.Compile.test.js +0 -139
  137. package/test/Twine2HTML/Twine2HTML.Parse.Web.test.js +0 -329
  138. package/test/Twine2HTML/Twine2HTML.Parse.test.js +0 -192
  139. package/test/Twine2HTML/Twine2HTMLCompiler/TestTags.html +0 -42
  140. package/test/Twine2HTML/Twine2HTMLCompiler/creator.html +0 -50
  141. package/test/Twine2HTML/Twine2HTMLCompiler/example6.twee +0 -16
  142. package/test/Twine2HTML/Twine2HTMLCompiler/format.js +0 -9
  143. package/test/Twine2HTML/Twine2HTMLCompiler/missingStoryTitle.twee +0 -29
  144. package/test/Twine2HTML/Twine2HTMLCompiler/test11.html +0 -121
  145. package/test/Twine2HTML/Twine2HTMLCompiler/test2.html +0 -58
  146. package/test/Twine2HTML/Twine2HTMLCompiler/test3.html +0 -49
  147. package/test/Twine2HTML/Twine2HTMLCompiler/test4.html +0 -50
  148. package/test/Twine2HTML/Twine2HTMLCompiler/test6.html +0 -49
  149. package/test/Twine2HTML/Twine2HTMLParser/Example1.html +0 -53
  150. package/test/Twine2HTML/Twine2HTMLParser/Tags.html +0 -15
  151. package/test/Twine2HTML/Twine2HTMLParser/lyingStartnode.html +0 -15
  152. package/test/Twine2HTML/Twine2HTMLParser/lyingTagColors.html +0 -48
  153. package/test/Twine2HTML/Twine2HTMLParser/missingCreator.html +0 -11
  154. package/test/Twine2HTML/Twine2HTMLParser/missingCreatorVersion.html +0 -11
  155. package/test/Twine2HTML/Twine2HTMLParser/missingFormat.html +0 -11
  156. package/test/Twine2HTML/Twine2HTMLParser/missingFormatVersion.html +0 -11
  157. package/test/Twine2HTML/Twine2HTMLParser/missingIFID.html +0 -11
  158. package/test/Twine2HTML/Twine2HTMLParser/missingPassageTags.html +0 -15
  159. package/test/Twine2HTML/Twine2HTMLParser/missingPosition.html +0 -15
  160. package/test/Twine2HTML/Twine2HTMLParser/missingScript.html +0 -14
  161. package/test/Twine2HTML/Twine2HTMLParser/missingSize.html +0 -35
  162. package/test/Twine2HTML/Twine2HTMLParser/missingStartnode.html +0 -11
  163. package/test/Twine2HTML/Twine2HTMLParser/missingStyle.html +0 -14
  164. package/test/Twine2HTML/Twine2HTMLParser/missingZoom.html +0 -11
  165. package/test/Twine2HTML/Twine2HTMLParser/tagColors.html +0 -31
  166. package/test/Twine2HTML/Twine2HTMLParser/twineExample.html +0 -23
  167. package/test/Twine2HTML/Twine2HTMLParser/twineExample2.html +0 -15
  168. package/test/Twine2HTML/Twine2HTMLParser/twineExample3.html +0 -15
  169. package/test/Twine2HTML/Twine2HTMLParser/unescaping.html +0 -33
  170. package/test/Web/web-core-coverage.test.js +0 -175
  171. package/test/Web/web-core-global.test.js +0 -93
  172. package/test/Web/web-core.test.js +0 -156
  173. package/test/Web/web-exports.test.js +0 -136
  174. package/test/Web/web-twine1html.test.js +0 -105
  175. package/test/Web/web-twine2archive.test.js +0 -96
  176. package/test/Web/web-tws.test.js +0 -77
  177. package/test/Web/window.Extwee.test.js +0 -97
  178. package/tsconfig.json +0 -21
  179. package/webpack.config.js +0 -47
@@ -1,414 +0,0 @@
1
- (dp0
2
- S'buildDestination'
3
- p1
4
- V\u005c\u005cMac\u005cDropbox\u005cTwineBuild.html
5
- p2
6
- sS'saveDestination'
7
- p3
8
- V\u005c\u005cMac\u005cDropbox\u005cExample5.tws
9
- p4
10
- sS'metadata'
11
- p5
12
- (dp6
13
- S'description'
14
- p7
15
- Vtest1
16
- p8
17
- sS'identity'
18
- p9
19
- Vtest1
20
- p10
21
- ssS'target'
22
- p11
23
- S'sugarcane'
24
- p12
25
- sS'storyPanel'
26
- p13
27
- (dp14
28
- S'widgets'
29
- p15
30
- (lp16
31
- (dp17
32
- S'selected'
33
- p18
34
- I00
35
- sS'pos'
36
- p19
37
- (lp20
38
- I10
39
- aI10
40
- asS'passage'
41
- p21
42
- (itiddlywiki
43
- Tiddler
44
- p22
45
- (dp24
46
- S'text'
47
- p25
48
- S'Your story will display this passage first. Edit it by double clicking it.'
49
- p26
50
- sS'title'
51
- p27
52
- S'Start'
53
- p28
54
- sS'modified'
55
- p29
56
- ctime
57
- struct_time
58
- p30
59
- ((I2023
60
- I9
61
- I3
62
- I14
63
- I38
64
- I52
65
- I6
66
- I246
67
- I1
68
- tp31
69
- (dp32
70
- tp33
71
- Rp34
72
- sS'tags'
73
- p35
74
- (lp36
75
- sS'created'
76
- p37
77
- g34
78
- sbsa(dp38
79
- g18
80
- I00
81
- sg19
82
- (lp39
83
- I10
84
- aI150
85
- asg21
86
- (itiddlywiki
87
- Tiddler
88
- p40
89
- (dp41
90
- g25
91
- S'Untitled Story'
92
- p42
93
- sg27
94
- S'StoryTitle'
95
- p43
96
- sg29
97
- g30
98
- ((I2023
99
- I9
100
- I3
101
- I14
102
- I38
103
- I52
104
- I6
105
- I246
106
- I1
107
- tp44
108
- (dp45
109
- tp46
110
- Rp47
111
- sg35
112
- (lp48
113
- sg37
114
- g47
115
- sbsa(dp49
116
- g18
117
- I00
118
- sg19
119
- (lp50
120
- I10
121
- aI290
122
- asg21
123
- (itiddlywiki
124
- Tiddler
125
- p51
126
- (dp52
127
- g25
128
- S'Anonymous'
129
- p53
130
- sg27
131
- S'StoryAuthor'
132
- p54
133
- sg29
134
- g30
135
- ((I2023
136
- I9
137
- I3
138
- I14
139
- I38
140
- I52
141
- I6
142
- I246
143
- I1
144
- tp55
145
- (dp56
146
- tp57
147
- Rp58
148
- sg35
149
- (lp59
150
- sg37
151
- g58
152
- sbsa(dp60
153
- g18
154
- I01
155
- sg19
156
- (lp61
157
- F262.0
158
- aF10.0
159
- asg21
160
- (itiddlywiki
161
- Tiddler
162
- p62
163
- (dp63
164
- g25
165
- V[[Untitled Passage 2]]
166
- p64
167
- sg27
168
- VUntitled Passage 1
169
- p65
170
- sg29
171
- g30
172
- ((I2023
173
- I9
174
- I3
175
- I15
176
- I47
177
- I59
178
- I6
179
- I246
180
- I1
181
- tp66
182
- (dp67
183
- tp68
184
- Rp69
185
- sg35
186
- (lp70
187
- Vtag1
188
- p71
189
- aVtag2
190
- p72
191
- aVtag3
192
- p73
193
- asg37
194
- g30
195
- ((I2023
196
- I9
197
- I3
198
- I14
199
- I39
200
- I28
201
- I6
202
- I246
203
- I1
204
- tp74
205
- (dp75
206
- tp76
207
- Rp77
208
- sbsa(dp78
209
- g18
210
- I00
211
- sg19
212
- (lp79
213
- F261.0
214
- aF150.0
215
- asg21
216
- (itiddlywiki
217
- Tiddler
218
- p80
219
- (dp81
220
- g25
221
- Vdd
222
- p82
223
- sg27
224
- VUntitled Passage 2
225
- p83
226
- sg29
227
- g30
228
- ((I2023
229
- I9
230
- I3
231
- I15
232
- I42
233
- I58
234
- I6
235
- I246
236
- I1
237
- tp84
238
- (dp85
239
- tp86
240
- Rp87
241
- sg35
242
- (lp88
243
- sg37
244
- g30
245
- ((I2023
246
- I9
247
- I3
248
- I14
249
- I39
250
- I30
251
- I6
252
- I246
253
- I1
254
- tp89
255
- (dp90
256
- tp91
257
- Rp92
258
- sbsa(dp93
259
- g18
260
- I00
261
- sg19
262
- (lp94
263
- F262.0
264
- aF290.0
265
- asg21
266
- (itiddlywiki
267
- Tiddler
268
- p95
269
- (dp96
270
- g25
271
- Vdd
272
- p97
273
- sg27
274
- VUntitled Passage 3
275
- p98
276
- sg29
277
- g30
278
- ((I2023
279
- I9
280
- I3
281
- I15
282
- I44
283
- I49
284
- I6
285
- I246
286
- I1
287
- tp99
288
- (dp100
289
- tp101
290
- Rp102
291
- sg35
292
- (lp103
293
- sg37
294
- g30
295
- ((I2023
296
- I9
297
- I3
298
- I14
299
- I39
300
- I31
301
- I6
302
- I246
303
- I1
304
- tp104
305
- (dp105
306
- tp106
307
- Rp107
308
- sbsa(dp108
309
- g18
310
- I00
311
- sg19
312
- (lp109
313
- F401.0
314
- aF10.0
315
- asg21
316
- (itiddlywiki
317
- Tiddler
318
- p110
319
- (dp111
320
- g25
321
- Vdd
322
- p112
323
- sg27
324
- VUntitled Passage 4
325
- p113
326
- sg29
327
- g30
328
- ((I2023
329
- I9
330
- I3
331
- I15
332
- I43
333
- I10
334
- I6
335
- I246
336
- I1
337
- tp114
338
- (dp115
339
- tp116
340
- Rp117
341
- sg35
342
- (lp118
343
- sg37
344
- g30
345
- ((I2023
346
- I9
347
- I3
348
- I14
349
- I39
350
- I31
351
- I6
352
- I246
353
- I1
354
- tp119
355
- (dp120
356
- tp121
357
- Rp122
358
- sbsa(dp123
359
- g18
360
- I00
361
- sg19
362
- (lp124
363
- F402.0
364
- aF150.0
365
- asg21
366
- (itiddlywiki
367
- Tiddler
368
- p125
369
- (dp126
370
- g25
371
- S'jquery:off\nhash:off\nbookmark:on\nmodernizr:off\nundo:on\nobfuscate:off\nexitprompt:off\nblankcss:off\n'
372
- p127
373
- sg27
374
- VStorySettings
375
- p128
376
- sg29
377
- g30
378
- ((I2023
379
- I9
380
- I3
381
- I15
382
- I20
383
- I35
384
- I6
385
- I246
386
- I1
387
- tp129
388
- (dp130
389
- tp131
390
- Rp132
391
- sg35
392
- (lp133
393
- sg37
394
- g30
395
- ((I2023
396
- I9
397
- I3
398
- I15
399
- I20
400
- I35
401
- I6
402
- I246
403
- I1
404
- tp134
405
- (dp135
406
- tp136
407
- Rp137
408
- sbsasS'scale'
409
- p138
410
- F6.200000000000003
411
- sS'snapping'
412
- p139
413
- I00
414
- ss.
Binary file
Binary file
@@ -1,200 +0,0 @@
1
- import { parse as parseTwee, escapeTweeMetacharacters, unescapeTweeMetacharacters } from '../../src/Twee/parse.js';
2
- import Passage from '../../src/Passage.js';
3
-
4
- describe('Twee Escaping', () => {
5
- describe('unescapeTweeMetacharacters()', () => {
6
- it('Should unescape square brackets', () => {
7
- expect(unescapeTweeMetacharacters('Test\\[Name\\]')).toBe('Test[Name]');
8
- });
9
-
10
- it('Should unescape curly braces', () => {
11
- expect(unescapeTweeMetacharacters('Test\\{Name\\}')).toBe('Test{Name}');
12
- });
13
-
14
- it('Should unescape backslashes', () => {
15
- expect(unescapeTweeMetacharacters('Test\\\\Name')).toBe('Test\\Name');
16
- });
17
-
18
- it('Should unescape any character after backslash (robust decoding)', () => {
19
- expect(unescapeTweeMetacharacters('\\q')).toBe('q');
20
- expect(unescapeTweeMetacharacters('\\x')).toBe('x');
21
- expect(unescapeTweeMetacharacters('\\5')).toBe('5');
22
- });
23
-
24
- it('Should handle complex combinations', () => {
25
- expect(unescapeTweeMetacharacters('\\[Hello\\] \\{world\\} \\\\\\\\')).toBe('[Hello] {world} \\\\');
26
- });
27
-
28
- it('Should handle non-string input gracefully', () => {
29
- expect(unescapeTweeMetacharacters(null)).toBe(null);
30
- expect(unescapeTweeMetacharacters(undefined)).toBe(undefined);
31
- expect(unescapeTweeMetacharacters(123)).toBe(123);
32
- });
33
-
34
- it('Should handle empty strings', () => {
35
- expect(unescapeTweeMetacharacters('')).toBe('');
36
- });
37
-
38
- it('Should handle strings without escape sequences', () => {
39
- expect(unescapeTweeMetacharacters('Normal Text')).toBe('Normal Text');
40
- });
41
- });
42
-
43
- describe('escapeTweeMetacharacters()', () => {
44
- it('Should escape square brackets', () => {
45
- expect(escapeTweeMetacharacters('Test[Name]')).toBe('Test\\[Name\\]');
46
- });
47
-
48
- it('Should escape curly braces', () => {
49
- expect(escapeTweeMetacharacters('Test{Name}')).toBe('Test\\{Name\\}');
50
- });
51
-
52
- it('Should escape backslashes', () => {
53
- expect(escapeTweeMetacharacters('Test\\Name')).toBe('Test\\\\Name');
54
- });
55
-
56
- it('Should escape complex combinations', () => {
57
- expect(escapeTweeMetacharacters('[Hello] {world} \\\\')).toBe('\\[Hello\\] \\{world\\} \\\\\\\\');
58
- });
59
-
60
- it('Should handle non-string input gracefully', () => {
61
- expect(escapeTweeMetacharacters(null)).toBe(null);
62
- expect(escapeTweeMetacharacters(undefined)).toBe(undefined);
63
- expect(escapeTweeMetacharacters(123)).toBe(123);
64
- });
65
-
66
- it('Should handle empty strings', () => {
67
- expect(escapeTweeMetacharacters('')).toBe('');
68
- });
69
-
70
- it('Should handle strings without metacharacters', () => {
71
- expect(escapeTweeMetacharacters('Normal Text')).toBe('Normal Text');
72
- });
73
- });
74
-
75
- describe('Round-trip escaping', () => {
76
- it('Should preserve text through escape -> unescape cycle', () => {
77
- const original = 'Test[Name]{Value}\\Path';
78
- const escaped = escapeTweeMetacharacters(original);
79
- const unescaped = unescapeTweeMetacharacters(escaped);
80
- expect(unescaped).toBe(original);
81
- });
82
-
83
- it('Should handle complex nested scenarios', () => {
84
- const original = '[{\\}]{[\\]}';
85
- const escaped = escapeTweeMetacharacters(original);
86
- const unescaped = unescapeTweeMetacharacters(escaped);
87
- expect(unescaped).toBe(original);
88
- });
89
- });
90
-
91
- describe('Twee parsing with escaping', () => {
92
- it('Should correctly parse escaped passage names', () => {
93
- const content = ':: Test\\[Name\\] \\{with\\} \\\\brackets\nContent here';
94
- const story = parseTwee(content);
95
- expect(story.passages[0].name).toBe('Test[Name] {with} \\brackets');
96
- });
97
-
98
- it('Should correctly parse escaped tags', () => {
99
- const content = ':: TestPassage [tag\\[1\\] tag\\{2\\}]\nContent here';
100
- const story = parseTwee(content);
101
- expect(story.passages[0].tags).toEqual(['tag[1]', 'tag{2}']);
102
- });
103
-
104
- it('Should handle mixed escaped and non-escaped content', () => {
105
- const content = ':: Test\\[Passage [normal escaped\\]tag]\nContent here';
106
- const story = parseTwee(content);
107
- expect(story.passages[0].name).toBe('Test[Passage');
108
- expect(story.passages[0].tags).toEqual(['normal', 'escaped]tag']);
109
- });
110
-
111
- it('Should handle the cursed.twee test case correctly', () => {
112
- const content = `:: StoryData
113
- {
114
- "ifid": "22F25A58-7062-4927-95B6-F424DDB2EC65",
115
- "format": "Harlowe",
116
- "format-version": "3.3.8",
117
- "start": "[Hello] {world} \\\\\\\\",
118
- "zoom": 1
119
- }
120
-
121
- :: \\[Hello\\] \\{world\\} \\\\\\\\
122
- Content here`;
123
-
124
- const story = parseTwee(content);
125
- expect(story.start).toBe('[Hello] {world} \\\\');
126
-
127
- // Find the passage by the unescaped name
128
- const passage = story.getPassageByName('[Hello] {world} \\\\');
129
- expect(passage).not.toBeNull();
130
- expect(passage.name).toBe('[Hello] {world} \\\\');
131
- });
132
-
133
- it('Should handle complex metadata with escaped keys (if supported)', () => {
134
- const content = ':: TestPassage {"position": "100,200", "size": "150,100"}\nContent here';
135
- const story = parseTwee(content);
136
- expect(story.passages[0].metadata.position).toBe('100,200');
137
- expect(story.passages[0].metadata.size).toBe('150,100');
138
- });
139
- });
140
-
141
- describe('Twee generation with escaping', () => {
142
- it('Should escape passage names when generating Twee', () => {
143
- const passage = new Passage('Test[Name]', 'Content', [], {});
144
- const tweeOutput = passage.toTwee();
145
- expect(tweeOutput).toContain(':: Test\\[Name\\]');
146
- });
147
-
148
- it('Should escape tag names when generating Twee', () => {
149
- const passage = new Passage('TestPassage', 'Content', ['tag[1]', 'tag{2}'], {});
150
- const tweeOutput = passage.toTwee();
151
- expect(tweeOutput).toContain('[tag\\[1\\] tag\\{2\\}]');
152
- });
153
-
154
- it('Should handle complex escaping scenarios', () => {
155
- const passage = new Passage('Test[Name]{Value}\\Path', 'Content', ['complex[tag]'], {});
156
- const tweeOutput = passage.toTwee();
157
- expect(tweeOutput).toContain(':: Test\\[Name\\]\\{Value\\}\\\\Path');
158
- expect(tweeOutput).toContain('[complex\\[tag\\]]');
159
- });
160
-
161
- it('Should preserve normal names and tags without escaping', () => {
162
- const passage = new Passage('NormalName', 'Content', ['normaltag'], {});
163
- const tweeOutput = passage.toTwee();
164
- expect(tweeOutput).toContain(':: NormalName');
165
- expect(tweeOutput).toContain('[normaltag]');
166
- });
167
- });
168
-
169
- describe('Edge cases', () => {
170
- it('Should handle empty passage names gracefully', () => {
171
- const content = ':: \nContent here';
172
- expect(() => parseTwee(content)).toThrow('Malformed passage header!');
173
- });
174
-
175
- it('Should handle passages with only escaped characters as names', () => {
176
- const content = ':: \\[\\]\nContent here';
177
- const story = parseTwee(content);
178
- expect(story.passages[0].name).toBe('[]');
179
- });
180
-
181
- it('Should handle multiple consecutive escapes', () => {
182
- const content = ':: Test\\\\\\\\Name\nContent here';
183
- const story = parseTwee(content);
184
- expect(story.passages[0].name).toBe('Test\\\\Name');
185
- });
186
-
187
- it('Should handle tags with only metacharacters', () => {
188
- const content = ':: TestPassage [\\[\\] \\{\\}]\nContent here';
189
- const story = parseTwee(content);
190
- expect(story.passages[0].tags).toEqual(['[]', '{}']);
191
- });
192
-
193
- it('Should handle mixed whitespace and escaping', () => {
194
- const content = ':: Test\\[Name\\] [ tag\\[1\\] tag2 ]\nContent here';
195
- const story = parseTwee(content);
196
- expect(story.passages[0].name).toBe('Test[Name]');
197
- expect(story.passages[0].tags).toEqual(['tag[1]', 'tag2']);
198
- });
199
- });
200
- });
@@ -1,108 +0,0 @@
1
- import { readFileSync } from 'node:fs';
2
- import { parse as parseTwee } from '../../src/Twee/parse.js';
3
-
4
- describe('Twee', () => {
5
- describe('parse()', () => {
6
- it('Should throw error if non-string is used', () => {
7
- expect(() => { parseTwee(1); }).toThrow();
8
- });
9
-
10
- it('Should throw error if empty string is used', () => {
11
- expect(() => { parseTwee(); }).toThrow();
12
- });
13
-
14
- it('Should throw error if no passages are present', () => {
15
- expect(() => { parseTwee('()()'); }).toThrow();
16
- });
17
-
18
- it('Should ignore malformed passage metadata and create empty object', () => {
19
- const fr = readFileSync('test/Twee/TweeParser/malformed.twee', 'utf-8');
20
- const story = parseTwee(fr);
21
- const metadata = story.getPassageByName('Start').metadata;
22
- const numberOfMetadataProperties = Object.keys(metadata).length;
23
- expect(numberOfMetadataProperties).toBe(0);
24
- });
25
-
26
- it('Should throw error if it detects malformed passage headers', () => {
27
- expect(() => { parseTwee('::{}[]\nNo name'); }).toThrow();
28
- });
29
-
30
- it('Should cut notes before passages', () => {
31
- const fr = readFileSync('test/Twee/TweeParser/notes.twee', 'utf-8');
32
- const story = parseTwee(fr);
33
- expect(story.name).toBe('twineExample');
34
- });
35
-
36
- it('Should be able to parse Twee file for Story Name', () => {
37
- const fr = readFileSync('test/Twee/TweeParser/example.twee', 'utf-8');
38
- const story = parseTwee(fr);
39
- expect(story.name).toBe('twineExample');
40
- });
41
-
42
- it('Should parse single tag on Start passage', () => {
43
- const fr = readFileSync('test/Twee/TweeParser/singletag.twee', 'utf-8');
44
- const story = parseTwee(fr);
45
- const start = story.getPassageByName('Start');
46
- expect(start.tags).toHaveLength(1);
47
- });
48
-
49
- it('Should parse multiple tag', () => {
50
- const fr = readFileSync('test/Twee/TweeParser/multipletags.twee', 'utf-8');
51
- const story = parseTwee(fr);
52
- const start = story.getPassageByName('Start');
53
- expect(start.tags).toHaveLength(2);
54
- });
55
-
56
- it('Should parse single script passage', () => {
57
- const fr = readFileSync('test/Twee/TweeParser/scriptPassage.twee', 'utf-8');
58
- const story = parseTwee(fr);
59
- const p = story.getPassageByName('UserScript');
60
- expect(p).toBe(null);
61
- expect(story.storyJavaScript.length).toBeGreaterThan(0);
62
- });
63
-
64
- it('Should parse single stylesheet passage', () => {
65
- const fr = readFileSync('test/Twee/TweeParser/stylePassage.twee', 'utf-8');
66
- const story = parseTwee(fr);
67
- const p = story.getPassageByName('UserStylesheet');
68
- expect(p).toBe(null);
69
- expect(story.storyStylesheet.length).toBeGreaterThan(0);
70
- });
71
-
72
- it('Should parse StoryTitle', () => {
73
- const fr = readFileSync('test/Twee/TweeParser/test.twee', 'utf-8');
74
- const story = parseTwee(fr);
75
- expect(story.name).not.toBe(null);
76
- });
77
-
78
- it('Should parse StoryAuthor', () => {
79
- const fr = readFileSync('test/Twee/TweeParser/example.twee', 'utf-8');
80
- const story = parseTwee(fr);
81
- const p = story.getPassageByName('StoryAuthor');
82
- expect(p).not.toBe(null);
83
- });
84
-
85
- it('Should parse single and only passage Start', () => {
86
- const fr = readFileSync('test/Twee/TweeParser/start.twee', 'utf-8');
87
- const story = parseTwee(fr);
88
- const p = story.getPassageByName('Start');
89
- const startingPassage = story.start;
90
- expect(p).not.toBe(null);
91
- expect(startingPassage).toBe('Start');
92
- });
93
-
94
- it('Should correctly parse "script" tagged passages as story javascript AND remove passages from story', () => {
95
- const fr = readFileSync('test/Twee/TweeParser/cycling.twee', 'utf-8');
96
- const story = parseTwee(fr);
97
- expect(story.storyJavaScript.length).toBeGreaterThan(0);
98
- expect(story.passages.length).toBe(2);
99
- });
100
-
101
- it('Should correctly parse "stylesheet" tagged passages as story stylesheet AND remove passages from story', () => {
102
- const fr = readFileSync('test/Twee/TweeParser/style.twee', 'utf-8');
103
- const story = parseTwee(fr);
104
- expect(story.storyStylesheet.length).toBeGreaterThan(0);
105
- expect(story.passages.length).toBe(1);
106
- });
107
- });
108
- });