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/TweeParser.js DELETED
@@ -1,255 +0,0 @@
1
- const Passage = require('./Passage.js');
2
- const Story = require('./Story.js');
3
- /**
4
- * @class TweeParser
5
- * @module TweeParser
6
- */
7
- class TweeParser {
8
- /**
9
- * @method TweeParser
10
- * @constructor
11
- */
12
- constructor (content) {
13
- this.story = new Story();
14
- this._passageMetadatError = false;
15
- this._storydataError = false;
16
-
17
- this.parse(content);
18
- }
19
-
20
- /**
21
- * @method parse
22
- * @returns Array or Null on error
23
- */
24
- parse(fileContents) {
25
-
26
- let passages = [];
27
-
28
- // Check if there are extra content in the files
29
- // If so, cut it all out for the parser
30
- if(fileContents[0] != ':' && fileContents[1] != ':') {
31
-
32
- let firstPassagePos = fileContents.indexOf('::');
33
- fileContents = fileContents.slice(firstPassagePos, fileContents.length);
34
-
35
- }
36
-
37
- // Split the file based on the passage sigil (::) preceeded by a newline
38
- let parsingPassages = fileContents.split('\n::');
39
-
40
- // Check if any passages exist
41
- if(parsingPassages == 0) {
42
-
43
- throw new Error("No passages were found!");
44
-
45
- }
46
-
47
- // Fix the first result
48
- parsingPassages[0] = parsingPassages[0].slice(2, parsingPassages[0].length);
49
-
50
- // Set the initial pid
51
- let pid = 0;
52
-
53
- // Iterate through the passages
54
- for(let passage of parsingPassages) {
55
-
56
- // Set default values
57
- let tags = "";
58
- let position = "";
59
- let metadata = "";
60
- let text = "";
61
- let name = "";
62
-
63
- // Header is everything to the first newline
64
- let header = passage.slice(0, passage.indexOf('\n'));
65
- // Text is everything else
66
- // (Also eat the leading newline character.)
67
- // (And trim any remaining whitespace.)
68
- text = passage.substring(header.length+1, passage.length).trim();
69
-
70
- // Test for metadata
71
- let openingCurlyBracketPosition = header.lastIndexOf('{');
72
- let closingCurlyBracketPosition = header.lastIndexOf('}');
73
-
74
- if(openingCurlyBracketPosition != -1 && closingCurlyBracketPosition != -1) {
75
-
76
- // Save the text metadata
77
- metadata = header.slice(openingCurlyBracketPosition, closingCurlyBracketPosition+1);
78
-
79
- // Remove the metadata from the header
80
- header = header.substring(0, openingCurlyBracketPosition) + header.substring(closingCurlyBracketPosition+1);
81
- }
82
-
83
- // There was passage metadata
84
- if(metadata.length > 0) {
85
-
86
- // Try to parse the metadata
87
- try {
88
-
89
- metadata = JSON.parse(metadata);
90
-
91
- } catch(event) {
92
-
93
- this._passageMetadatError = true;
94
-
95
- }
96
-
97
- }
98
-
99
- // Test for tags
100
- let openingSquareBracketPosition = header.lastIndexOf('[');
101
- let closingSquareBracketPosition = header.lastIndexOf(']');
102
-
103
- if(openingSquareBracketPosition != -1 && closingSquareBracketPosition != -1) {
104
-
105
- tags = header.slice(openingSquareBracketPosition, closingSquareBracketPosition+1);
106
-
107
- // Remove the tags from the header
108
- header = header.substring(0, openingSquareBracketPosition) + header.substring(closingSquareBracketPosition+1);
109
- }
110
-
111
- // Parse tags
112
- if(tags.length > 0) {
113
-
114
- // Eat the opening and closing square brackets
115
- tags = tags.substring(1, tags.length-1);
116
-
117
- // Set empty default
118
- let tagsArray = [];
119
-
120
- // Test if tags is not single, empty string
121
- if( !(tags == "") ) {
122
-
123
- tagsArray = tags.split(" ");
124
- }
125
-
126
- // There are multiple tags
127
- if(tagsArray.length > 1) {
128
-
129
- // Create future array
130
- let futureTagArray = [];
131
-
132
- // Move through entries
133
- for(let tag in tagsArray) {
134
-
135
- // Add a trimmed verion into future array
136
- futureTagArray.push(tagsArray[tag].trim());
137
-
138
- }
139
-
140
- // Set the tags back to the future array
141
- tags = futureTagArray;
142
-
143
- } else if (tagsArray.length == 1) {
144
-
145
- // There was only one tag
146
- // Store it
147
- let temp = tags;
148
-
149
- // Switch tags over to an array
150
- tags = new Array();
151
- // Push the single entry
152
- tags.push(temp);
153
-
154
- } else {
155
-
156
- // Make sure tags is set to empty array if no tags were found
157
- tags = [];
158
-
159
- }
160
-
161
- } else {
162
- // There were no tags, so set it to an empty array;
163
- tags = [];
164
- }
165
-
166
- // Filter out any empty string tags
167
- tags = tags.filter(tag => tag != "");
168
-
169
- // Trim any remaining whitespace
170
- header = header.trim();
171
-
172
- // Check if there is a name left
173
- if(header.length > 0) {
174
-
175
- name = header;
176
-
177
- } else {
178
-
179
- // No name left. Something went wrong. Blame user.
180
- throw new Error("Malformed passage header!");
181
-
182
- }
183
-
184
- if(this._passageMetadatError) {
185
-
186
- console.warn('Error parsing metadata for "' + name + '". It was ignored.');
187
-
188
- }
189
-
190
- // Add the new Passage to the internal array
191
- passages.push(new Passage(name, tags, metadata, text, pid));
192
-
193
- // Increase pid
194
- pid++;
195
-
196
- }
197
-
198
- // All formats share StoryTitle
199
- // Find it and set it
200
- let pos = passages.find((el) => {
201
- return el.name == "StoryTitle";
202
- });
203
-
204
- if(pos != undefined) {
205
-
206
- this.story.name = pos.text;
207
- // Remove the StoryTitle passage
208
- passages = passages.filter(p => p.name !== "StoryTitle");
209
-
210
- } else {
211
-
212
- // There was no StoryTitle passage
213
- // Set a value of "Unknown"
214
- this.story.name = "Unknown";
215
-
216
- }
217
-
218
- // Look for StoryData
219
- pos = passages.find((el) => {
220
- return el.name == "StoryData";
221
- });
222
-
223
- if(pos != undefined ) {
224
-
225
- // Try to parse the StoryData
226
- try {
227
-
228
- this.story.metadata = JSON.parse(pos.text);
229
-
230
- } catch(event) {
231
-
232
- // Silently fail with default values
233
- this._storydataError = true;
234
-
235
- }
236
-
237
- // Remove the StoryData passage
238
- passages = passages.filter(p => p.name !== "StoryData");
239
-
240
- }
241
-
242
- if(this._storydataError) {
243
-
244
- console.warn("Error with processing StoryData JSON data. It was ignored.");
245
-
246
- }
247
-
248
- // Set the passages to the internal story
249
- this.story.passages = passages;
250
-
251
- }
252
-
253
- }
254
-
255
- module.exports = TweeParser;
package/TweeWriter.js DELETED
@@ -1,111 +0,0 @@
1
- const fs = require("fs");
2
- const path = require('path');
3
- const Story = require('./Story.js');
4
-
5
- /**
6
- * @class TweeWriter
7
- * @module TweeWriter
8
- */
9
- class TweeWriter {
10
- /**
11
- * @method TweeWriter
12
- * @constructor
13
- */
14
- constructor (story, file) {
15
-
16
- if( !(story instanceof Story) ) {
17
- throw new Error("Not a Story object!");
18
- }
19
-
20
- this.writeFile(file, story);
21
- }
22
-
23
- writeFile(file, story) {
24
-
25
- // Write StoryTitle first
26
- let outputContents = ":: StoryTitle\n" + story.name + "\n\n";
27
-
28
- // Write the StoryData second
29
- outputContents += ":: StoryData\n"
30
-
31
- // Borrowed from Underscore
32
- // https://github.com/jashkenas/underscore/blob/master/underscore.js#L1319-L1323
33
- let isObject = function(obj) {
34
- var type = typeof obj;
35
- return type === 'function' || type === 'object' && !!obj;
36
- };
37
-
38
- // Test if story.metadata is an object or not
39
- if(isObject(story.metadata) ) {
40
-
41
- // Write any metadata in pretty format
42
- outputContents += " " + JSON.stringify(story.metadata, undefined, 2);
43
-
44
- } else {
45
-
46
- // If, for whatever reason, story.metadata is not an object, throw error.
47
- throw new Error("Story Metadata MUST be an object!");
48
-
49
- }
50
-
51
- // Add two newlines
52
- outputContents += "\n\n";
53
-
54
- // Are there any passages?
55
- if(story.passages.length > 0) {
56
-
57
- // Build the contents
58
- for(let passage in story.passages) {
59
-
60
- // Write the name
61
- outputContents += ":: " + story.passages[passage].name;
62
-
63
- // Test if it has any tags
64
- if(story.passages[passage].tags.length > 0) {
65
-
66
- outputContents += " [";
67
-
68
- for(let tag of story.passages[passage].tags) {
69
-
70
- outputContents += " " + tag;
71
-
72
- }
73
-
74
- outputContents += "]";
75
-
76
- }
77
-
78
- // Write out any passage metadata
79
- outputContents += JSON.stringify(story.passages[passage].metadata);
80
-
81
- // Add the text and two newlines
82
- outputContents += "\n" + story.passages[passage].text + "\n\n";
83
-
84
- }
85
-
86
- } else {
87
-
88
- // Create empty Start passage
89
- outputContents += ":: Start\n";
90
-
91
- }
92
-
93
- try {
94
-
95
- // Try to write
96
- fs.writeFileSync(file, outputContents);
97
-
98
- } catch(event) {
99
-
100
- // Throw error
101
- throw new Error("Error: Cannot write Twee file!");
102
-
103
- }
104
-
105
- // Writing was successful
106
- console.info("Created " + fs.realpathSync(file) );
107
-
108
- }
109
- }
110
-
111
- module.exports = TweeWriter;
package/main.js DELETED
@@ -1,103 +0,0 @@
1
- const argv = require('yargs')
2
- .describe('i', 'Source')
3
- .describe('v', 'Version')
4
- .describe('f', 'Story Format')
5
- .describe('d', 'File to decompile')
6
- .describe('o', 'Output File')
7
- .describe('r', 'Directory')
8
- .describe('w', 'Watch')
9
- .alias('v', 'version')
10
- .alias('i', 'input')
11
- .alias('f', 'format')
12
- .alias('d', 'decompile')
13
- .alias('o', 'output')
14
- .alias('h', 'help')
15
- .alias('r', 'dir')
16
- .alias('w', 'watch')
17
- .argv;
18
-
19
- const FileReader = require('./FileReader.js');
20
- const TweeParser = require('./TweeParser.js');
21
- const TweeWriter = require('./TweeWriter.js');
22
- const StoryFormatParser = require('./StoryFormatParser.js');
23
- const HTMLParser = require('./HTMLParser.js');
24
- const HTMLWriter = require('./HTMLWriter.js');
25
- const DirectoryReader = require('./DirectoryReader.js');
26
- const DirectoryWatcher = require('./DirectoryWatcher.js');
27
-
28
- if(argv.hasOwnProperty("input") ) {
29
-
30
- if(argv.hasOwnProperty("format") ) {
31
-
32
- if(argv.hasOwnProperty("output") ) {
33
-
34
- let fr = new FileReader(argv.input);
35
- let tp = new TweeParser(fr.contents);
36
- let sfp = new StoryFormatParser(argv.format);
37
- let hw = new HTMLWriter(argv.output, tp.story, sfp.storyformat);
38
-
39
- } else {
40
- throw new Error("Missing output file!");
41
- }
42
-
43
- } else {
44
- throw new Error("Missing format file");
45
- }
46
- } else if(argv.hasOwnProperty("decompile") ) {
47
-
48
- if(argv.hasOwnProperty("output") )
49
- {
50
- let fr = new FileReader(argv.decompile);
51
- let hd = new HTMLParser(fr.contents);
52
- let tw = new TweeWriter(hd.story, argv.output);
53
-
54
- } else {
55
- throw new Error("Missing output file!");
56
- }
57
- } else if(argv.hasOwnProperty("dir") ) {
58
-
59
- const dir = new DirectoryReader(argv.dir);
60
-
61
- if(argv.hasOwnProperty("format") ) {
62
-
63
- if(argv.hasOwnProperty("output") ) {
64
-
65
- let tp = new TweeParser(dir.tweeContents);
66
- let sfp = new StoryFormatParser(argv.format);
67
- let hw = new HTMLWriter(argv.output, tp.story, sfp.storyformat, dir.CSScontents, dir.JScontents);
68
-
69
- } else {
70
- throw new Error("Missing output file!");
71
- }
72
-
73
- } else {
74
- throw new Error("Missing format file");
75
- }
76
-
77
- } else if(argv.hasOwnProperty("watch") ) {
78
-
79
- if(argv.hasOwnProperty("format") ) {
80
-
81
- if(argv.hasOwnProperty("output") ) {
82
-
83
- let dir = new DirectoryReader(argv.watch);
84
-
85
- let dw = new DirectoryWatcher(argv.watch, () => {
86
-
87
- console.info("Re-building files.");
88
- dir.update();
89
- let tp = new TweeParser(dir.tweeContents);
90
- let sfp = new StoryFormatParser(argv.format);
91
- let hw = new HTMLWriter(argv.output, tp.story, sfp.storyformat, dir.CSScontents, dir.JScontents);
92
-
93
- });
94
-
95
- } else {
96
- throw new Error("Missing output file!");
97
- }
98
-
99
- } else {
100
- throw new Error("Missing format file");
101
- }
102
-
103
- }