extwee 1.5.3 → 2.0.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 (144) hide show
  1. package/.eslintrc.json +25 -0
  2. package/.github/workflows/nodejs.yml +24 -0
  3. package/.travis.yml +13 -0
  4. package/CODE_OF_CONDUCT.md +82 -0
  5. package/LICENSE +21 -21
  6. package/README.md +36 -203
  7. package/SECURITY.md +12 -0
  8. package/babel.config.json +22 -0
  9. package/bin/extwee.js +49 -0
  10. package/index.js +31 -26
  11. package/package.json +60 -39
  12. package/src/FileReader.js +33 -0
  13. package/src/HTMLParser.js +343 -0
  14. package/src/HTMLWriter.js +196 -0
  15. package/src/Passage.js +202 -0
  16. package/src/Story.js +461 -0
  17. package/src/StoryFormat.js +300 -0
  18. package/src/StoryFormatParser.js +142 -0
  19. package/src/TweeParser.js +166 -0
  20. package/src/TweeWriter.js +98 -0
  21. package/story-formats/chapbook-1.2.0/format.js +1 -0
  22. package/story-formats/chapbook-1.2.0/logo.svg +1 -0
  23. package/story-formats/harlowe-1.2.4/format.js +1 -0
  24. package/story-formats/harlowe-1.2.4/icon.svg +78 -0
  25. package/story-formats/harlowe-2.1.0/format.js +2 -0
  26. package/story-formats/harlowe-2.1.0/icon.svg +78 -0
  27. package/story-formats/harlowe-3.1.0/format.js +3 -0
  28. package/story-formats/harlowe-3.1.0/icon.svg +78 -0
  29. package/story-formats/paperthin-1.0.0/format.js +1 -0
  30. package/story-formats/paperthin-1.0.0/icon.svg +5 -0
  31. package/story-formats/snowman-1.4.0/format.js +1 -0
  32. package/story-formats/snowman-1.4.0/icon.svg +436 -0
  33. package/story-formats/snowman-2.0.2/format.js +1 -0
  34. package/story-formats/snowman-2.0.2/icon.svg +436 -0
  35. package/story-formats/sugarcube-1.0.35/LICENSE +23 -0
  36. package/story-formats/sugarcube-1.0.35/format.js +1 -0
  37. package/story-formats/sugarcube-1.0.35/icon.svg +56 -0
  38. package/story-formats/sugarcube-2.31.1/LICENSE +22 -0
  39. package/story-formats/sugarcube-2.31.1/format.js +1 -0
  40. package/story-formats/sugarcube-2.31.1/icon.svg +56 -0
  41. package/test/CLI/example6.twee +16 -0
  42. package/test/CLI/harlowe.js +3 -0
  43. package/test/CLI/input.html +47 -0
  44. package/test/CLI/test.twee +18 -0
  45. package/test/CLI/test2.html +47 -0
  46. package/test/CLI/tweeExample.twee +17 -0
  47. package/test/CLI/twineExample.html +15 -0
  48. package/test/CLI.test.js +30 -0
  49. package/test/FileReader/t1.txt +1 -0
  50. package/test/FileReader.test.js +14 -0
  51. package/test/HTMLParser/Example1.html +53 -0
  52. package/test/HTMLParser/Tags.html +15 -0
  53. package/test/HTMLParser/lyingStartnode.html +15 -0
  54. package/test/HTMLParser/lyingTagColors.html +48 -0
  55. package/test/HTMLParser/missingCreator.html +11 -0
  56. package/test/HTMLParser/missingCreatorVersion.html +11 -0
  57. package/test/HTMLParser/missingFormat.html +11 -0
  58. package/test/HTMLParser/missingFormatVersion.html +11 -0
  59. package/test/HTMLParser/missingIFID.html +11 -0
  60. package/test/HTMLParser/missingName.html +33 -0
  61. package/test/HTMLParser/missingPID.html +15 -0
  62. package/test/HTMLParser/missingPassageName.html +15 -0
  63. package/test/HTMLParser/missingPassageTags.html +15 -0
  64. package/test/HTMLParser/missingPosition.html +15 -0
  65. package/test/HTMLParser/missingScript.html +14 -0
  66. package/test/HTMLParser/missingSize.html +35 -0
  67. package/test/HTMLParser/missingStartnode.html +11 -0
  68. package/test/HTMLParser/missingStyle.html +14 -0
  69. package/test/HTMLParser/missingZoom.html +11 -0
  70. package/test/HTMLParser/tagColors.html +31 -0
  71. package/test/HTMLParser/twineExample.html +15 -0
  72. package/test/HTMLParser/twineExample2.html +15 -0
  73. package/test/HTMLParser/twineExample3.html +15 -0
  74. package/test/HTMLParser.test.js +177 -0
  75. package/test/HTMLWriter/TestTags.html +42 -0
  76. package/test/HTMLWriter/creator.html +51 -0
  77. package/test/HTMLWriter/example6.twee +16 -0
  78. package/test/HTMLWriter/missingStoryTitle.twee +29 -0
  79. package/test/HTMLWriter/test11.html +123 -0
  80. package/test/HTMLWriter/test2.html +59 -0
  81. package/test/HTMLWriter/test3.html +50 -0
  82. package/test/HTMLWriter/test4.html +51 -0
  83. package/test/HTMLWriter/test6.html +50 -0
  84. package/test/HTMLWriter.test.js +279 -0
  85. package/test/Passage.test.js +104 -0
  86. package/test/Roundtrip/Example1.html +64 -0
  87. package/test/Roundtrip/example1.twee +21 -0
  88. package/test/Roundtrip/example2.twee +18 -0
  89. package/test/Roundtrip/harlowe.js +3 -0
  90. package/test/Roundtrip/round.html +50 -0
  91. package/test/Roundtrip.test.js +48 -0
  92. package/test/Story/startmeta.twee +29 -0
  93. package/test/Story/test.twee +25 -0
  94. package/test/Story.test.js +282 -0
  95. package/test/StoryFormat.test.js +152 -0
  96. package/test/StoryFormatParser/example.js +3 -0
  97. package/test/StoryFormatParser/example2.js +3 -0
  98. package/test/StoryFormatParser/format.js +1 -0
  99. package/test/StoryFormatParser/format_doublename.js +1 -0
  100. package/test/StoryFormatParser/harlowe.js +3 -0
  101. package/test/StoryFormatParser/missingAuthor.js +1 -0
  102. package/test/StoryFormatParser/missingDescription.js +1 -0
  103. package/test/StoryFormatParser/missingImage.js +1 -0
  104. package/test/StoryFormatParser/missingLicense.js +1 -0
  105. package/test/StoryFormatParser/missingName.js +1 -0
  106. package/test/StoryFormatParser/missingProofing.js +1 -0
  107. package/test/StoryFormatParser/missingSource.js +1 -0
  108. package/test/StoryFormatParser/missingURL.js +1 -0
  109. package/test/StoryFormatParser/missingVersion.js +1 -0
  110. package/test/StoryFormatParser/versionWrong.js +1 -0
  111. package/test/StoryFormatParser.test.js +91 -0
  112. package/test/TweeParser/emptytags.twee +2 -0
  113. package/test/TweeParser/example.twee +32 -0
  114. package/test/TweeParser/missing.twee +19 -0
  115. package/test/TweeParser/multipleScriptPassages.twee +19 -0
  116. package/test/TweeParser/multipleStyleTag.twee +19 -0
  117. package/test/TweeParser/multipletags.twee +10 -0
  118. package/test/TweeParser/noTitle.twee +2 -0
  119. package/test/TweeParser/notes.twee +16 -0
  120. package/test/TweeParser/pasagemetadataerror.twee +2 -0
  121. package/test/TweeParser/scriptPassage.twee +16 -0
  122. package/test/TweeParser/singletag.twee +13 -0
  123. package/test/TweeParser/startMetadata.twee +14 -0
  124. package/test/TweeParser/storydataerror.twee +25 -0
  125. package/test/TweeParser/stylePassage.twee +16 -0
  126. package/test/TweeParser/test.twee +25 -0
  127. package/test/TweeParser.test.js +79 -0
  128. package/test/TweeWriter/test1.twee +18 -0
  129. package/test/TweeWriter/test3.twee +12 -0
  130. package/test/TweeWriter/test4.twee +14 -0
  131. package/test/TweeWriter/test5.twee +20 -0
  132. package/test/TweeWriter.test.js +82 -0
  133. package/DirectoryReader.js +0 -128
  134. package/DirectoryWatcher.js +0 -63
  135. package/FileReader.js +0 -36
  136. package/HTMLParser.js +0 -206
  137. package/HTMLWriter.js +0 -177
  138. package/Passage.js +0 -20
  139. package/Story.js +0 -148
  140. package/StoryFormat.js +0 -41
  141. package/StoryFormatParser.js +0 -65
  142. package/TweeParser.js +0 -255
  143. package/TweeWriter.js +0 -111
  144. package/main.js +0 -103
package/HTMLParser.js DELETED
@@ -1,206 +0,0 @@
1
- const { parse } = require('node-html-parser');
2
- const htmlparser = parse;
3
- const Story = require('./Story.js');
4
- const Passage = require('./Passage.js');
5
- /**
6
- * @class HTMLParser
7
- * @module HTMLParser
8
- */
9
- class HTMLParser {
10
- /**
11
- * @method HTMLParser
12
- * @constructor
13
- */
14
- constructor (content) {
15
-
16
- this.story = null;
17
-
18
- this.parse(content);
19
- }
20
-
21
- parse(content) {
22
-
23
- // Send to node-html-parser
24
- // Enable getting the content of 'script', 'style', and 'pre' elements
25
- // Get back a DOM
26
- let dom = new htmlparser(
27
- content,
28
- {
29
- lowerCaseTagName: false,
30
- script: true,
31
- style: true,
32
- pre: true
33
- });
34
-
35
- // Pull out the tw-storydata element
36
- let storyData = dom.querySelector('tw-storydata');
37
-
38
- if(storyData != null) {
39
-
40
- this.story = new Story();
41
- this.story.name = storyData.attributes["name"];
42
- this.story.creator = storyData.attributes["creator"];
43
- this.story.creatorVersion = storyData.attributes["creator-version"];
44
-
45
- this.story.metadata = {};
46
- this.story.metadata.ifid = storyData.attributes["ifid"];
47
- this.story.metadata.format = storyData.attributes["format"];
48
- this.story.metadata.formatVersion = storyData.attributes["format-version"];
49
- this.story.metadata.zoom = storyData.attributes["zoom"];
50
- this.story.metadata.start = storyData.attributes["startnode"];
51
-
52
- } else {
53
-
54
- throw new Error("Error: Not a Twine 2-style file!");
55
-
56
- }
57
-
58
- // Pull out the tw-passagedata elements
59
- let storyPassages = dom.querySelectorAll("tw-passagedata");
60
-
61
- // Create an empty array
62
- this.story.passages = new Array();
63
-
64
- // Set default pid
65
- let pid = 1;
66
-
67
- // Add StoryTitle
68
- this.story.passages.push(
69
- new Passage(
70
- "StoryTitle",
71
- [],
72
- {},
73
- this.story.name,
74
- pid
75
- )
76
- );
77
-
78
- // Increase PID by one before parsing any other passages
79
- pid++;
80
-
81
- // Move through the passages
82
- for(let passage in storyPassages) {
83
-
84
- // Get the passage attributes
85
- let attr = storyPassages[passage].attributes;
86
- // Get the passage text
87
- let text = storyPassages[passage].rawText;
88
-
89
- // Save position
90
- let position = attr.position;
91
-
92
- // Save size
93
- let size = attr.size;
94
-
95
- // Escape the name
96
- let name = this._escapeMetacharacters(attr.name);
97
-
98
- // Create empty tags
99
- let tags = "";
100
-
101
- // Escape any tags
102
- // (Attributes can, themselves, be emtpy strings.)
103
- if(attr.tags.length > 0 && attr.tags != '""') {
104
-
105
- tags = this._escapeMetacharacters(attr.tags);
106
-
107
- }
108
-
109
- // Split by spaces
110
- tags = tags.split(" ");
111
-
112
- // Remove any empty strings
113
- tags = tags.filter(tag => tag != "");
114
-
115
- // Add a new Passage into an array
116
- this.story.passages.push(
117
- new Passage(
118
- name,
119
- tags,
120
- {
121
- "position": position,
122
- "size": size
123
-
124
- },
125
- text,
126
- pid
127
- )
128
- );
129
-
130
- pid++;
131
-
132
- }
133
-
134
- // Look for the style element
135
- let styleElement = dom.querySelector('#twine-user-stylesheet');
136
-
137
- // Check if there is any content.
138
- // If not, we won't add empty passages
139
- if(styleElement.rawText.length > 0) {
140
-
141
- // Add UserStylesheet
142
- this.story.passages.push(
143
- new Passage(
144
- "UserStylesheet",
145
- ["stylesheet"],
146
- {},
147
- styleElement.rawText
148
- )
149
- );
150
- }
151
-
152
- // Look for the script element
153
- let scriptElement = dom.querySelector('#twine-user-script');
154
-
155
- // Check if there is any content.
156
- // If not, we won't add empty passages
157
- if(scriptElement.rawText.length > 0) {
158
-
159
- // Add UserScript
160
- this.story.passages.push(
161
- new Passage(
162
- "UserScript",
163
- ["script"],
164
- {},
165
- scriptElement.rawText
166
- )
167
- );
168
-
169
- }
170
-
171
- // Now that all passages have been handled,
172
- // change the start name
173
- this.story.metadata.start = this.story.getStartingPassage();
174
-
175
- // Add StoryData
176
- this.story.passages.push(
177
- new Passage(
178
- "StoryData",
179
- [],
180
- {},
181
- JSON.stringify(this.story.metadata, null, 4)
182
- )
183
- );
184
-
185
- }
186
-
187
- _escapeMetacharacters(result) {
188
-
189
- // Replace any single backslash with two of them
190
- result = result.replace(/\\/g, "\\");
191
- // Double-escape escaped {
192
- result = result.replace(/\\\{/g, "\\\\{");
193
- // Double-escape escaped }
194
- result = result.replace(/\\\}/g, "\\\\}");
195
- // Double-escape escaped [
196
- result = result.replace(/\\\[/g, "\\\\[");
197
- // Double-escape escaped ]
198
- result = result.replace(/\\\]/g, "\\\\]");
199
-
200
- return result;
201
-
202
- }
203
-
204
- }
205
-
206
- module.exports = HTMLParser;
package/HTMLWriter.js DELETED
@@ -1,177 +0,0 @@
1
- const fs = require("fs");
2
- const Story = require('./Story.js');
3
- const StoryFormat = require('./StoryFormat.js');
4
- /**
5
- * @class HTMLWriter
6
- * @module HTMLWriter
7
- */
8
- class HTMLWriter {
9
- /**
10
- * @method HTMLWriter
11
- * @constructor
12
- */
13
- constructor (file, story, storyFormat, css, js) {
14
-
15
- if( !(story instanceof Story) ) {
16
- throw new Error("Error: story must be a Story object!");
17
- }
18
-
19
- if( !(storyFormat instanceof StoryFormat)) {
20
-
21
- throw new Error("storyFormat must be a StoryFormat object!");
22
-
23
- }
24
-
25
- let cssContent = css || null;
26
- let jsContent = js || null;
27
-
28
- this.writeFile(file, story, storyFormat, cssContent, jsContent);
29
- }
30
-
31
- writeFile(file, story, storyFormat, cssContent, jsContent) {
32
-
33
- let outputContents = "";
34
-
35
- // Build <tw-storydata>
36
- let storyData =
37
- '<tw-storydata name="' + story.name + '" ' +
38
- 'startnode="' + story.getStartingPassage() + '" ' +
39
- 'creator="' + story.creator + '" ' +
40
- 'creator-version="' + story.creatorVersion + '" ' +
41
- 'ifid="' + story.metadata.ifid + '" ' +
42
- 'zoom="' + story.metadata.zoom + '" ' +
43
- 'format="' + storyFormat.name + '" ' +
44
- 'format-version="' + storyFormat.version + '" ' +
45
- 'options hidden>\n';
46
-
47
- // Build the STYLE
48
- storyData += '<style role="stylesheet" id="twine-user-stylesheet" type="text/twine-css">';
49
-
50
- // Get any passages tagged with 'stylesheet'
51
- let stylePassages = story.getStylePassages();
52
-
53
- // CSS passed through from DirectoryReader
54
- if(cssContent != null) {
55
- storyData += cssContent;
56
- }
57
-
58
- // Iterate through the collection and add to storyData
59
- for(let content of stylePassages) {
60
- storyData += content.text;
61
- }
62
-
63
- storyData += '</style>\n';
64
-
65
- // Build the SCRIPT
66
- storyData += '<script role="script" id="twine-user-script" type="text/twine-javascript">';
67
-
68
- // Get any passages tagged with 'script'
69
- let scriptPassages = story.getScriptPassages();
70
-
71
- // JS passed through from DirectoryReader
72
- if(jsContent != null) {
73
- storyData += jsContent;
74
- }
75
-
76
- // Iterate through the collection and add to storyData
77
- for(let content of scriptPassages) {
78
- storyData += content.text;
79
- }
80
-
81
- storyData += '</script>\n';
82
-
83
- // All the script data has been written.
84
- // Delete all 'script'-tagged passages
85
- story.deleteAllByTag("script");
86
-
87
- // All the style data has been written.
88
- // Delete all 'style'-tagged passages
89
- story.deleteAllByTag("stylesheet");
90
-
91
- // Build the passages
92
- for(let passage of story.passages) {
93
-
94
- storyData += '<tw-passagedata pid="' + passage.pid + '" name="' + passage.name + '"';
95
-
96
- // Write out any tags
97
- if(passage.tags.length > 1) {
98
-
99
- storyData += ' tags="';
100
-
101
- for(let t of passage.tags) {
102
-
103
- storyData += t + ', ';
104
-
105
- }
106
-
107
- storyData += '" ';
108
-
109
- } else if(passage.tags.length == 1) {
110
-
111
- storyData += ' tags="' + passage.tags[0] + '" ';
112
-
113
- } else {
114
-
115
- storyData += ' tags ';
116
-
117
- }
118
-
119
- // Write out position
120
- if(passage.metadata.hasOwnProperty("position")) {
121
-
122
- storyData += 'position="' +
123
- passage.metadata.position + '" ';
124
-
125
- } else {
126
-
127
- // Didn't have a position.
128
- // Make one up.
129
- storyData += 'position="100,100" ';
130
-
131
- }
132
-
133
- // Write out size
134
- if(passage.metadata.hasOwnProperty("size") ) {
135
-
136
- storyData += 'size="' +
137
- passage.metadata.size + '" ';
138
-
139
- } else {
140
-
141
- // Didn't have a size.
142
- // Make one up.
143
- storyData += 'size="100,100" ';
144
-
145
- }
146
-
147
- storyData += '>' + passage.text + '</tw-passagedata>\n';
148
-
149
- }
150
-
151
- storyData += '</tw-storydata>';
152
-
153
- // Replace the story name in the source file
154
- storyFormat.source = storyFormat.source.replace("{{STORY_NAME}}", story.name);
155
-
156
- // Replace the story data
157
- storyFormat.source = storyFormat.source.replace("{{STORY_DATA}}", storyData);
158
-
159
- outputContents += storyFormat.source
160
-
161
- try {
162
-
163
- // Try to write
164
- fs.writeFileSync(file, outputContents);
165
-
166
- } catch(event) {
167
-
168
- // Throw error
169
- throw new Error("Error: Cannot write HTML file!");
170
-
171
- }
172
-
173
- }
174
-
175
- }
176
-
177
- module.exports = HTMLWriter;
package/Passage.js DELETED
@@ -1,20 +0,0 @@
1
- /**
2
- * @class Passage
3
- * @module Passage
4
- */
5
- class Passage {
6
- /**
7
- * @method Passage
8
- * @constructor
9
- */
10
- constructor (name = "", tags = [], metadata = {}, text = "", pid = 1) {
11
- this.name = name;
12
- this.tags = tags;
13
- this.metadata = metadata;
14
- this.text = text;
15
- this.pid = pid;
16
- }
17
-
18
- }
19
-
20
- module.exports = Passage;
package/Story.js DELETED
@@ -1,148 +0,0 @@
1
- const pkg = require('./package.json');
2
- /**
3
- * @class Story
4
- * @module Story
5
- */
6
- class Story {
7
- /**
8
- * @method Story
9
- * @constructor
10
- */
11
- constructor () {
12
- this.name = "Unknown";
13
- this.metadata = {
14
- "ifid": "",
15
- "format": "",
16
- "formatVersion": "",
17
- "zoom": "",
18
- "start": ""
19
- };
20
-
21
- this.passages = [];
22
-
23
- // Store the creator and version
24
- this.creator = pkg.name;
25
- this.creatorVersion = pkg.version;
26
-
27
- }
28
-
29
- /**
30
- * @method getStylePassages()
31
- */
32
- getStylePassages() {
33
-
34
- let stylePassages = [];
35
-
36
- if(this.passages.length > 0) {
37
-
38
- stylePassages = this.passages.filter(function(passage){
39
-
40
- let results = passage.tags.filter(tag => tag == "stylesheet");
41
-
42
- return (results.length > 0);
43
-
44
- });
45
-
46
- }
47
-
48
- return stylePassages;
49
-
50
- }
51
-
52
- /**
53
- * @method getScriptPassages()
54
- */
55
- getScriptPassages() {
56
-
57
- let scriptPassages = [];
58
-
59
- if(this.passages.length > 0) {
60
-
61
- scriptPassages = this.passages.filter(function(passage) {
62
-
63
- let results = passage.tags.filter(tag => tag == "script");
64
-
65
- return (results.length > 0);
66
-
67
- });
68
-
69
- }
70
-
71
- return scriptPassages;
72
-
73
- }
74
-
75
- /**
76
- * @method deleteAllByTag()
77
- */
78
- deleteAllByTag(searchTag) {
79
-
80
- if(this.passages.length > 0) {
81
-
82
- this.passages = this.passages.filter(function(passage) {
83
-
84
- return !passage.tags.includes(searchTag);
85
-
86
- });
87
-
88
- }
89
-
90
- }
91
-
92
- /**
93
- * @method getStartingPassage()
94
- * @return String
95
- */
96
- getStartingPassage() {
97
-
98
- let pid = null;
99
- let searchName = null;
100
-
101
- if(this.metadata.hasOwnProperty("start")) {
102
-
103
- // Check if the property is an empty string
104
- // If so, ignore it.
105
- if(this.metadata.start != "") {
106
-
107
- searchName = this.metadata.start;
108
-
109
- }
110
-
111
- }
112
-
113
- if(this.passages.length > 0) {
114
-
115
- for(let passage in this.passages) {
116
-
117
- if(this.passages[passage].name == searchName) {
118
-
119
- pid = this.passages[passage].pid;
120
- break;
121
-
122
- }
123
-
124
- if(this.passages[passage].name == "Start") {
125
-
126
- pid = this.passages[passage].pid;
127
-
128
- }
129
-
130
- }
131
-
132
- }
133
-
134
- if(pid == null) {
135
-
136
- throw new Error("Starting passage not found!");
137
-
138
- } else {
139
-
140
- return pid;
141
-
142
- }
143
-
144
- }
145
-
146
- }
147
-
148
- module.exports = Story;
package/StoryFormat.js DELETED
@@ -1,41 +0,0 @@
1
- /**
2
- * @class StoryFormat
3
- * @module StoryFormat
4
- */
5
- class StoryFormat {
6
- /**
7
- * @method StoryFormat
8
- * @constructor
9
- */
10
- constructor (object) {
11
-
12
- // Borrowed from Underscore
13
- // https://github.com/jashkenas/underscore/blob/master/underscore.js#L1319-L1323
14
- let isObject = function(obj) {
15
- var type = typeof obj;
16
- return type === 'function' || type === 'object' && !!obj;
17
- };
18
-
19
- if(isObject(object) ) {
20
-
21
- this.name = object.name || null;
22
- this.version = object.version || null;
23
- this.description = object.description || null;
24
- this.author = object.author || null;
25
- this.image = object.image || null;
26
- this.url = object.url || null;
27
- this.license = object.license || null;
28
- this.proofing = object.proofing || null;
29
- this.source = object.source || null;
30
-
31
- } else {
32
-
33
- throw new Error("Expected JSON object!");
34
-
35
- }
36
-
37
- }
38
-
39
- }
40
-
41
- module.exports = StoryFormat;
@@ -1,65 +0,0 @@
1
- const StoryFormat = require('./StoryFormat.js');
2
- const FileReader = require('./FileReader.js');
3
- /**
4
- * @class StoryFormatParser
5
- * @module StoryFormatParser
6
- */
7
- class StoryFormatParser {
8
- /**
9
- * @method StoryFormatParser
10
- * @constructor
11
- */
12
- constructor (file) {
13
-
14
- this.storyformat = null;
15
-
16
- this.parse(file);
17
- }
18
-
19
- parse(file) {
20
-
21
- let contents = new FileReader(file).contents;
22
-
23
- // Harlowe has malformed JSON, so we have to test for it
24
- let harlowePosition = contents.indexOf('harlowe');
25
-
26
- if(harlowePosition != -1) {
27
- // The 'setup' property is malformed
28
- let setupPosition = contents.lastIndexOf(',"setup": function');
29
- contents = contents.slice(0, setupPosition) + '}';
30
-
31
- }
32
-
33
- let openingCurlyBracketPosition = contents.indexOf('{');
34
- let closingCurlyBracketPosition = contents.lastIndexOf('}');
35
-
36
- if(openingCurlyBracketPosition != -1 && closingCurlyBracketPosition != -1) {
37
-
38
- // Slice out the JSON
39
- contents = contents.slice(openingCurlyBracketPosition, closingCurlyBracketPosition+1);
40
-
41
- } else {
42
-
43
- throw new Error("Unable to find Twine2 JSON chunk!");
44
-
45
- }
46
-
47
- let jsonContent = "";
48
-
49
- try {
50
-
51
- jsonContent = JSON.parse(contents);
52
-
53
- } catch (event) {
54
-
55
- throw new Error("Unable to parse Twine2 JSON chunk!");
56
-
57
- }
58
-
59
- this.storyformat = new StoryFormat(jsonContent);
60
-
61
- }
62
-
63
- }
64
-
65
- module.exports = StoryFormatParser;