extwee 2.0.3 → 2.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/extwee.js +10 -12
- package/package.json +17 -18
- package/src/HTMLParser.js +2 -0
- package/src/HTMLWriter.js +2 -2
- package/src/Story.js +43 -10
- package/src/TweeWriter.js +23 -0
- package/test/CLI/test2.html +1 -3
- package/test/CLI.test.js +6 -6
- package/test/FileReader.test.js +4 -4
- package/test/HTMLParser/twineExample.html +11 -3
- package/test/HTMLParser.test.js +31 -31
- package/test/HTMLWriter/creator.html +1 -2
- package/test/HTMLWriter/test11.html +1 -3
- package/test/HTMLWriter/test2.html +0 -3
- package/test/HTMLWriter/test3.html +0 -1
- package/test/HTMLWriter/test4.html +1 -2
- package/test/HTMLWriter/test6.html +1 -2
- package/test/HTMLWriter.test.js +1 -3
- package/test/Passage.test.js +14 -14
- package/test/Roundtrip/example4.twee +27 -0
- package/test/Roundtrip/round.html +1 -4
- package/test/Roundtrip.test.js +2 -2
- package/test/Story.test.js +74 -20
- package/test/StoryFormat.test.js +30 -30
- package/test/StoryFormatParser.test.js +16 -16
- package/test/TweeWriter/test1.twee +1 -1
- package/test/TweeWriter/test3.twee +3 -3
- package/test/TweeWriter/test5.twee +1 -1
- package/test/TweeWriter/test6.twee +15 -0
- package/test/TweeWriter/test7.twee +15 -0
- package/test/TweeWriter.test.js +25 -3
package/bin/extwee.js
CHANGED
|
@@ -10,20 +10,18 @@ import Extwee from '../index.js';
|
|
|
10
10
|
// Import Commander
|
|
11
11
|
import { Command } from 'commander';
|
|
12
12
|
|
|
13
|
-
//
|
|
13
|
+
// Create a new Command
|
|
14
14
|
const program = new Command();
|
|
15
15
|
|
|
16
16
|
program
|
|
17
|
-
.
|
|
17
|
+
.name('extwee')
|
|
18
|
+
.version('2.0.6')
|
|
18
19
|
.option('-c', 'From Twee into HTML')
|
|
19
20
|
.option('-d', 'From HTML into Twee')
|
|
20
21
|
.option('-s <storyformat>', 'Path to storyformat')
|
|
21
22
|
.option('-i <inputFile>', 'Path to input file')
|
|
22
23
|
.option('-o <outputFile>', 'Path to output file');
|
|
23
24
|
|
|
24
|
-
// Set the process title
|
|
25
|
-
process.title = 'extwee';
|
|
26
|
-
|
|
27
25
|
// Parse the passed arguments
|
|
28
26
|
program.parse(process.argv);
|
|
29
27
|
|
|
@@ -31,19 +29,19 @@ program.parse(process.argv);
|
|
|
31
29
|
const options = program.opts();
|
|
32
30
|
|
|
33
31
|
// Decompile branch
|
|
34
|
-
if(options.
|
|
35
|
-
const inputHTML = Extwee.readFile(options.
|
|
32
|
+
if(options.d === true) {
|
|
33
|
+
const inputHTML = Extwee.readFile(options.i);
|
|
36
34
|
const storyObject = Extwee.parseHTML(inputHTML);
|
|
37
|
-
Extwee.writeTwee(storyObject, options.
|
|
35
|
+
Extwee.writeTwee(storyObject, options.o);
|
|
38
36
|
process.exit();
|
|
39
37
|
}
|
|
40
38
|
|
|
41
39
|
// Compile branch
|
|
42
|
-
if(options.
|
|
43
|
-
const inputTwee = Extwee.readFile(options.
|
|
40
|
+
if(options.c === true) {
|
|
41
|
+
const inputTwee = Extwee.readFile(options.i);
|
|
44
42
|
const story = Extwee.parseTwee(inputTwee);
|
|
45
|
-
const inputStoryFormat = Extwee.readFile(options.
|
|
43
|
+
const inputStoryFormat = Extwee.readFile(options.s);
|
|
46
44
|
const parsedStoryFormat = Extwee.parseStoryFormat(inputStoryFormat);
|
|
47
|
-
Extwee.writeHTML(options.
|
|
45
|
+
Extwee.writeHTML(options.o, story, parsedStoryFormat);
|
|
48
46
|
process.exit();
|
|
49
47
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "extwee",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.6",
|
|
4
4
|
"description": "A Twee 3 compiler written in JS.",
|
|
5
5
|
"author": "Dan Cox",
|
|
6
6
|
"main": "index.js",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"extwee": "bin/extwee.js"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
|
-
"test": "jest --runInBand --coverage --colors",
|
|
11
|
+
"test": "jest --silent --runInBand --coverage --colors",
|
|
12
12
|
"lint": "eslint ./src/**/*.js --fix",
|
|
13
13
|
"lint:test": "eslint ./test/*.test.js --fix",
|
|
14
14
|
"all": "npm run lint && npm run lint:test && npm run test"
|
|
@@ -21,31 +21,30 @@
|
|
|
21
21
|
],
|
|
22
22
|
"license": "MIT",
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"commander": "^
|
|
25
|
-
"node-html-parser": "^
|
|
24
|
+
"commander": "^9.3.0",
|
|
25
|
+
"node-html-parser": "^5.3.3",
|
|
26
|
+
"semver": "^7.3.7",
|
|
26
27
|
"uuid": "^8.3.2"
|
|
27
28
|
},
|
|
28
29
|
"devDependencies": {
|
|
29
|
-
"@babel/cli": "^7.
|
|
30
|
-
"@babel/core": "^7.
|
|
30
|
+
"@babel/cli": "^7.17.10",
|
|
31
|
+
"@babel/core": "^7.18.5",
|
|
31
32
|
"@babel/eslint-parser": "^7.12.1",
|
|
32
33
|
"@babel/eslint-plugin": "^7.12.1",
|
|
33
34
|
"@babel/plugin-proposal-class-properties": "^7.12.1",
|
|
34
|
-
"@babel/plugin-transform-runtime": "^7.
|
|
35
|
-
"@babel/
|
|
36
|
-
"@babel/preset-env": "^7.12.11",
|
|
35
|
+
"@babel/plugin-transform-runtime": "^7.18.5",
|
|
36
|
+
"@babel/preset-env": "^7.18.2",
|
|
37
37
|
"babel-loader": "^8.2.2",
|
|
38
|
-
"core-js": "^3.8
|
|
39
|
-
"eslint": "^
|
|
40
|
-
"eslint-config-standard": "^
|
|
38
|
+
"core-js": "^3.22.8",
|
|
39
|
+
"eslint": "^8.17.0",
|
|
40
|
+
"eslint-config-standard": "^17.0.0",
|
|
41
41
|
"eslint-plugin-import": "^2.20.1",
|
|
42
|
-
"eslint-plugin-jest": "^
|
|
43
|
-
"eslint-plugin-jsdoc": "^
|
|
42
|
+
"eslint-plugin-jest": "^26.5.3",
|
|
43
|
+
"eslint-plugin-jsdoc": "^39.3.2",
|
|
44
44
|
"eslint-plugin-node": "^11.0.0",
|
|
45
|
-
"eslint-plugin-promise": "^
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"semver": "^5.7.1",
|
|
45
|
+
"eslint-plugin-promise": "^6.0.0",
|
|
46
|
+
"jest": "^28.1.1",
|
|
47
|
+
"regenerator-runtime": "^0.13.9",
|
|
49
48
|
"shelljs": "^0.8.4"
|
|
50
49
|
},
|
|
51
50
|
"repository": {
|
package/src/HTMLParser.js
CHANGED
|
@@ -51,6 +51,8 @@ export default class HTMLParser {
|
|
|
51
51
|
if (Object.prototype.hasOwnProperty.call(storyData.attributes, 'name')) {
|
|
52
52
|
// Create StoryTitle passage based on name
|
|
53
53
|
story.addPassage(new Passage('StoryTitle', storyData.attributes.name));
|
|
54
|
+
// Set the story name
|
|
55
|
+
story.name = storyData.attributes.name;
|
|
54
56
|
} else {
|
|
55
57
|
// Name is a required filed. Warn user.
|
|
56
58
|
console.warn('Twine 2 HTML must have a name!');
|
package/src/HTMLWriter.js
CHANGED
|
@@ -107,7 +107,7 @@ export default class HTMLWriter {
|
|
|
107
107
|
// Add text of passages
|
|
108
108
|
storyData += passage.text;
|
|
109
109
|
// Remove from story
|
|
110
|
-
story.
|
|
110
|
+
story.removePassageByName(passage.name);
|
|
111
111
|
});
|
|
112
112
|
|
|
113
113
|
// Close the STYLE
|
|
@@ -124,7 +124,7 @@ export default class HTMLWriter {
|
|
|
124
124
|
// Add text of passages
|
|
125
125
|
storyData += passage.text;
|
|
126
126
|
// Remove from story
|
|
127
|
-
story.
|
|
127
|
+
story.removePassageByName(passage.name);
|
|
128
128
|
});
|
|
129
129
|
|
|
130
130
|
// Close SCRIPT
|
package/src/Story.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import Passage from './Passage.js';
|
|
2
|
-
import FileReader from './FileReader.js';
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
const
|
|
3
|
+
const name = 'extwee';
|
|
4
|
+
const version = '2.0.6';
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* @class Story
|
|
@@ -14,7 +13,7 @@ export default class Story {
|
|
|
14
13
|
*
|
|
15
14
|
* @private
|
|
16
15
|
*/
|
|
17
|
-
|
|
16
|
+
#_name = '';
|
|
18
17
|
|
|
19
18
|
/**
|
|
20
19
|
* Internal start
|
|
@@ -28,7 +27,7 @@ export default class Story {
|
|
|
28
27
|
*
|
|
29
28
|
* @private
|
|
30
29
|
*/
|
|
31
|
-
#_IFID = ''
|
|
30
|
+
#_IFID = '';
|
|
32
31
|
|
|
33
32
|
/**
|
|
34
33
|
* Internal story format
|
|
@@ -370,7 +369,7 @@ export default class Story {
|
|
|
370
369
|
}
|
|
371
370
|
|
|
372
371
|
// Test for default value.
|
|
373
|
-
// (This might occur if using Story
|
|
372
|
+
// (This might occur if using Story directly
|
|
374
373
|
// outside of using HTMLParser or TweeParser.)
|
|
375
374
|
if (p.pid === -1) {
|
|
376
375
|
// Set the internal counter.
|
|
@@ -396,11 +395,11 @@ export default class Story {
|
|
|
396
395
|
* Remove a passage from the story by name
|
|
397
396
|
*
|
|
398
397
|
* @public
|
|
399
|
-
* @function
|
|
398
|
+
* @function removePassageByName
|
|
400
399
|
* @memberof Story
|
|
401
400
|
* @param {string} name - Passage name to remove
|
|
402
401
|
*/
|
|
403
|
-
|
|
402
|
+
removePassageByName (name) {
|
|
404
403
|
this.#_passages = this.#_passages.filter(passage => passage.name !== name);
|
|
405
404
|
}
|
|
406
405
|
|
|
@@ -455,7 +454,8 @@ export default class Story {
|
|
|
455
454
|
|
|
456
455
|
/**
|
|
457
456
|
* Size (number of passages).
|
|
458
|
-
* Does not include StoryAuthor
|
|
457
|
+
* Does not include StoryAuthor or StoryTitle.
|
|
458
|
+
* Does not include passages with 'script' or 'stylesheet' tags.
|
|
459
459
|
*
|
|
460
460
|
* @public
|
|
461
461
|
* @function size
|
|
@@ -463,7 +463,26 @@ export default class Story {
|
|
|
463
463
|
* @returns {number} Return number of passages
|
|
464
464
|
*/
|
|
465
465
|
size () {
|
|
466
|
-
|
|
466
|
+
let count = 0;
|
|
467
|
+
this.#_passages.forEach((passage) => {
|
|
468
|
+
// Exclude StoryTitle
|
|
469
|
+
if (passage.name === 'StoryTitle') {
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// Exclude if 'script' tags exists
|
|
474
|
+
if (passage.tags.includes('script')) {
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// Exclude if 'stylesheet' exists
|
|
479
|
+
if (passage.tags.includes('stylesheet')) {
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
count++;
|
|
484
|
+
});
|
|
485
|
+
return count;
|
|
467
486
|
}
|
|
468
487
|
|
|
469
488
|
/**
|
|
@@ -483,6 +502,20 @@ export default class Story {
|
|
|
483
502
|
|
|
484
503
|
// Use internal forEach
|
|
485
504
|
this.#_passages.forEach((element, index) => {
|
|
505
|
+
// Exclude StoryTitle
|
|
506
|
+
if (element.name === 'StoryTitle') {
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// Exclude if 'script' tags exists
|
|
511
|
+
if (element.tags.includes('script')) {
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// Exclude if 'stylesheet' exists
|
|
516
|
+
if (element.tags.includes('stylesheet')) {
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
486
519
|
// Call callback function with element and index
|
|
487
520
|
callback(element, index);
|
|
488
521
|
});
|
package/src/TweeWriter.js
CHANGED
|
@@ -81,12 +81,35 @@ export default class TweeWriter {
|
|
|
81
81
|
// Add two newlines.
|
|
82
82
|
outputContents += '\n\n';
|
|
83
83
|
|
|
84
|
+
// Look for StoryTitle
|
|
85
|
+
const storyTitlePassage = story.getPassageByName('StoryTitle');
|
|
86
|
+
|
|
87
|
+
// Does it exist?
|
|
88
|
+
if (storyTitlePassage !== null) {
|
|
89
|
+
// Append StoryTitle content
|
|
90
|
+
outputContents += storyTitlePassage.toString();
|
|
91
|
+
}
|
|
92
|
+
|
|
84
93
|
// For each passage, append it to the output.
|
|
85
94
|
story.forEach((passage) => {
|
|
86
95
|
// For each passage, append it to the output.
|
|
87
96
|
outputContents += passage.toString();
|
|
88
97
|
});
|
|
89
98
|
|
|
99
|
+
// Look for 'script' passages
|
|
100
|
+
const scriptPassages = story.getPassagesByTag('script');
|
|
101
|
+
// For each 'script', add it back
|
|
102
|
+
scriptPassages.forEach(passage => {
|
|
103
|
+
outputContents += passage.toString();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// Look for 'stylesheet' passages
|
|
107
|
+
const stylesheetPassages = story.getPassagesByTag('stylesheet');
|
|
108
|
+
// For each 'stylesheet', add it back
|
|
109
|
+
stylesheetPassages.forEach(passage => {
|
|
110
|
+
outputContents += passage.toString();
|
|
111
|
+
});
|
|
112
|
+
|
|
90
113
|
try {
|
|
91
114
|
// Try to write
|
|
92
115
|
fs.writeFileSync(file, outputContents);
|
package/test/CLI/test2.html
CHANGED
|
@@ -11,12 +11,10 @@
|
|
|
11
11
|
|
|
12
12
|
<tw-story></tw-story>
|
|
13
13
|
|
|
14
|
-
<tw-storydata name="twineExample" startnode="2" creator="extwee" creator-version="2.0.
|
|
14
|
+
<tw-storydata name="twineExample" startnode="2" creator="extwee" creator-version="2.0.6" ifid="2B68ECD6-348F-4CF5-96F8-549A512A8128" zoom="0" format="Harlowe" format-version="3.0.2" options hidden>
|
|
15
15
|
<style role="stylesheet" id="twine-user-stylesheet" type="text/twine-css">body {background-color: green;}</style>
|
|
16
16
|
<script role="script" id="twine-user-script" type="text/twine-javascript"></script>
|
|
17
|
-
<tw-passagedata pid="1" name="StoryTitle">twineExample</tw-passagedata>
|
|
18
17
|
<tw-passagedata pid="2" name="Start" tags="tag tags" position="200,200" size="100,100" >Content</tw-passagedata>
|
|
19
|
-
<tw-passagedata pid="3" name="Style1" tags="stylesheet" >body {background-color: green;}</tw-passagedata>
|
|
20
18
|
</tw-storydata>
|
|
21
19
|
|
|
22
20
|
<script title="Twine engine code" data-main="harlowe">"use strict";function _defineProperty(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function _toConsumableArray(e){if(Array.isArray(e)){for(var t=0,n=Array(e.length);t<e.length;t++)n[t]=e[t];return n}return Array.from(e)}var _slicedToArray=function(){function e(e,t){var n=[],r=!0,i=!1,o=void 0;try{for(var a,s=e[Symbol.iterator]();!(r=(a=s.next()).done)&&(n.push(a.value),!t||n.length!==t);r=!0);}catch(e){i=!0,o=e}finally{try{!r&&s.return&&s.return()}finally{if(i)throw o}}return n}return function(t,n){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return e(t,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};!function(){/**
|
package/test/CLI.test.js
CHANGED
|
@@ -6,23 +6,23 @@ import shell from 'shelljs';
|
|
|
6
6
|
const currentPath = shell.pwd().stdout;
|
|
7
7
|
const testFilePath = currentPath + '/test/CLI';
|
|
8
8
|
|
|
9
|
-
describe('CLI',
|
|
9
|
+
describe('CLI', () => {
|
|
10
10
|
// Remove the test files, if they exist
|
|
11
|
-
beforeAll(
|
|
11
|
+
beforeAll(() => {
|
|
12
12
|
shell.rm(`${testFilePath}/test.*`);
|
|
13
13
|
});
|
|
14
14
|
|
|
15
15
|
// Test generating Twee files
|
|
16
|
-
describe('Decompile',
|
|
17
|
-
|
|
16
|
+
describe('Decompile', () => {
|
|
17
|
+
it('Decompile: HTML into Twee', () => {
|
|
18
18
|
shell.exec(`node ${currentPath}/bin/extwee.js -d -i ${testFilePath}/input.html -o ${testFilePath}/test.twee`);
|
|
19
19
|
expect(shell.test('-e', `${testFilePath}/test.twee`)).toBe(true);
|
|
20
20
|
});
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
// Test generating HTML files
|
|
24
|
-
describe('Compile',
|
|
25
|
-
|
|
24
|
+
describe('Compile', () => {
|
|
25
|
+
it('Compile: Twee + StoryFormat into Twee', () => {
|
|
26
26
|
shell.exec(`node ${currentPath}/bin/extwee.js -c -i ${testFilePath}/example6.twee -s ${testFilePath}/harlowe.js -o ${testFilePath}/test2.html`);
|
|
27
27
|
expect(shell.test('-e', `${testFilePath}/test2.html`)).toBe(true);
|
|
28
28
|
});
|
package/test/FileReader.test.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import FileReader from '../src/FileReader.js';
|
|
2
2
|
|
|
3
|
-
describe('FileReader',
|
|
4
|
-
describe('#readFile()',
|
|
5
|
-
|
|
3
|
+
describe('FileReader', () => {
|
|
4
|
+
describe('#readFile()', () => {
|
|
5
|
+
it('Should throw error if file not found', () => {
|
|
6
6
|
expect(() => { FileReader.read('test/FileReader/t2.txt'); }).toThrow();
|
|
7
7
|
});
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
it('Should read the contents of a file', () => {
|
|
10
10
|
const fr = FileReader.read('test/FileReader/t1.txt');
|
|
11
11
|
expect(fr).toBe('Gibberish');
|
|
12
12
|
});
|
|
@@ -6,10 +6,18 @@
|
|
|
6
6
|
</head>
|
|
7
7
|
<body>
|
|
8
8
|
<tw-story></tw-story>
|
|
9
|
-
<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
|
|
9
|
+
<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>
|
|
10
|
+
<style role="stylesheet" id="twine-user-stylesheet" type="text/twine-css"></style>
|
|
11
|
+
<script role="script" id="twine-user-script" type="text/twine-javascript"></script>
|
|
12
|
+
<tw-passagedata pid="1" name="Start" tags="" position="102,104" size="100,100">[[Another passage]]
|
|
10
13
|
|
|
11
|
-
[[A third passage]]</tw-passagedata
|
|
14
|
+
[[A third passage]]</tw-passagedata>
|
|
15
|
+
<tw-passagedata pid="2" name="Another passage" tags="" position="353,60" size="100,100">[[A fourth passage]]
|
|
12
16
|
|
|
13
|
-
[[A third passage]] </tw-passagedata
|
|
17
|
+
[[A third passage]] </tw-passagedata>
|
|
18
|
+
<tw-passagedata pid="3" name="A third passage" tags="" position="350,288" size="100,100">[[Start]]</tw-passagedata>
|
|
19
|
+
<tw-passagedata pid="4" name="A fourth passage" tags="" position="587,197" size="100,100">[[A fifth passage]]</tw-passagedata>
|
|
20
|
+
<tw-passagedata pid="5" name="A fifth passage" tags="" position="800,306" size="100,100">Double-click this passage to edit it.</tw-passagedata>
|
|
21
|
+
</tw-storydata>
|
|
14
22
|
</body>
|
|
15
23
|
</html>
|
package/test/HTMLParser.test.js
CHANGED
|
@@ -5,111 +5,111 @@ import HTMLParser from '../src/HTMLParser.js';
|
|
|
5
5
|
// These are used as the 'creator' and 'creator-version'.
|
|
6
6
|
const { version } = JSON.parse(FileReader.read('package.json'));
|
|
7
7
|
|
|
8
|
-
describe('HTMLParser',
|
|
9
|
-
describe('#parse()',
|
|
10
|
-
|
|
8
|
+
describe('HTMLParser', () => {
|
|
9
|
+
describe('#parse()', () => {
|
|
10
|
+
it('Should throw error if content is not Twine-2 style HTML', () => {
|
|
11
11
|
expect(() => { HTMLParser.parse(''); }).toThrow();
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
it('Should be able to parse Twine 2 HTML for story name', () => {
|
|
15
15
|
const fr = FileReader.read('test/HTMLParser/twineExample.html');
|
|
16
16
|
const story = HTMLParser.parse(fr);
|
|
17
17
|
const storyTitle = story.getPassageByName('StoryTitle');
|
|
18
18
|
expect(storyTitle.text).toBe('twineExample');
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
it('Should be able to parse Twine 2 HTML for correct number of passages', () => {
|
|
22
22
|
const fr = FileReader.read('test/HTMLParser/twineExample.html');
|
|
23
23
|
const tp = HTMLParser.parse(fr);
|
|
24
|
-
expect(tp.size()).toBe(
|
|
24
|
+
expect(tp.size()).toBe(5);
|
|
25
25
|
});
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
it('Should be able to correctly parse passage tags', () => {
|
|
28
28
|
const fr = FileReader.read('test/HTMLParser/Tags.html');
|
|
29
29
|
const story = HTMLParser.parse(fr);
|
|
30
30
|
const p = story.getPassageByName('Untitled Passage');
|
|
31
31
|
expect(p.tags).toHaveLength(2);
|
|
32
32
|
});
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
it('Should set a missing name to Untitled', () => {
|
|
35
35
|
const fr = FileReader.read('test/HTMLParser/missingName.html');
|
|
36
36
|
const story = HTMLParser.parse(fr);
|
|
37
37
|
const p = story.getPassageByName('StoryTitle');
|
|
38
38
|
expect(p.text).toBe('Untitled');
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
it('Should set a missing IFID to an empty string', () => {
|
|
42
42
|
const fr = FileReader.read('test/HTMLParser/missingIFID.html');
|
|
43
43
|
const tp = HTMLParser.parse(fr);
|
|
44
44
|
expect(tp.IFID).toBe('');
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
it('Should have Extwee for creator when missing', () => {
|
|
48
48
|
const fr = FileReader.read('test/HTMLParser/missingCreator.html');
|
|
49
49
|
const tp = HTMLParser.parse(fr);
|
|
50
50
|
expect(tp.creator).toBe('extwee');
|
|
51
51
|
});
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
it('Should have correct for creatorVersion when missing', () => {
|
|
54
54
|
const fr = FileReader.read('test/HTMLParser/missingCreatorVersion.html');
|
|
55
55
|
const tp = HTMLParser.parse(fr);
|
|
56
56
|
expect(tp.creatorVersion).toBe(version);
|
|
57
57
|
});
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
it('Should have empty string as format when missing', () => {
|
|
60
60
|
const fr = FileReader.read('test/HTMLParser/missingFormat.html');
|
|
61
61
|
const tp = HTMLParser.parse(fr);
|
|
62
62
|
expect(tp.format).toBe('');
|
|
63
63
|
});
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
it('Should have empty string as formatVersion when missing', () => {
|
|
66
66
|
const fr = FileReader.read('test/HTMLParser/missingFormatVersion.html');
|
|
67
67
|
const tp = HTMLParser.parse(fr);
|
|
68
68
|
expect(tp.formatVersion).toBe('');
|
|
69
69
|
});
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
it('Should have empty string as zoom when missing', () => {
|
|
72
72
|
const fr = FileReader.read('test/HTMLParser/missingZoom.html');
|
|
73
73
|
const tp = HTMLParser.parse(fr);
|
|
74
74
|
expect(tp.zoom).toBe(0);
|
|
75
75
|
});
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
it('Should not have position if passage does not', () => {
|
|
78
78
|
const fr = FileReader.read('test/HTMLParser/missingPosition.html');
|
|
79
79
|
const story = HTMLParser.parse(fr);
|
|
80
80
|
const p = story.getPassageByName('Untitled Passage');
|
|
81
81
|
expect(Object.prototype.hasOwnProperty.call(p.metadata, 'position')).toBe(false);
|
|
82
82
|
});
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
it('Should not have size if passage does not', () => {
|
|
85
85
|
const fr = FileReader.read('test/HTMLParser/missingSize.html');
|
|
86
86
|
const story = HTMLParser.parse(fr);
|
|
87
87
|
const p = story.getPassageByName('Untitled Passage');
|
|
88
88
|
expect(Object.prototype.hasOwnProperty.call(p.metadata, 'size')).toBe(false);
|
|
89
89
|
});
|
|
90
90
|
|
|
91
|
-
|
|
91
|
+
it('Should have empty array as tags if tags is missing', () => {
|
|
92
92
|
const fr = FileReader.read('test/HTMLParser/missingPassageTags.html');
|
|
93
93
|
const story = HTMLParser.parse(fr);
|
|
94
94
|
const p = story.getPassageByName('Untitled Passage');
|
|
95
95
|
expect(p.tags).toHaveLength(0);
|
|
96
96
|
});
|
|
97
97
|
|
|
98
|
-
|
|
98
|
+
it('Should not have stylesheet tag if no passages exist with it', () => {
|
|
99
99
|
const fr = FileReader.read('test/HTMLParser/missingStyle.html');
|
|
100
100
|
const story = HTMLParser.parse(fr);
|
|
101
101
|
const passages = story.getPassagesByTag('stylesheet');
|
|
102
102
|
expect(passages.length).toBe(0);
|
|
103
103
|
});
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
it('Should not have script tag if no passages exist with it', () => {
|
|
106
106
|
const fr = FileReader.read('test/HTMLParser/missingScript.html');
|
|
107
107
|
const story = HTMLParser.parse(fr);
|
|
108
108
|
const passages = story.getPassagesByTag('script');
|
|
109
109
|
expect(passages.length).toBe(0);
|
|
110
110
|
});
|
|
111
111
|
|
|
112
|
-
|
|
112
|
+
it('Should have script and style tags normally', () => {
|
|
113
113
|
const fr = FileReader.read('test/HTMLParser/Example1.html');
|
|
114
114
|
const story = HTMLParser.parse(fr);
|
|
115
115
|
const scriptPassages = story.getPassagesByTag('script');
|
|
@@ -118,27 +118,27 @@ describe('HTMLParser', function () {
|
|
|
118
118
|
expect(stylesheetPassages.length).toBe(1);
|
|
119
119
|
});
|
|
120
120
|
|
|
121
|
-
|
|
121
|
+
it('Should not have start property if startNode does not exist when parsed', () => {
|
|
122
122
|
const fr = FileReader.read('test/HTMLParser/missingStartnode.html');
|
|
123
123
|
const story = HTMLParser.parse(fr);
|
|
124
124
|
expect(story.start).toBe('');
|
|
125
125
|
});
|
|
126
126
|
|
|
127
|
-
|
|
127
|
+
it('Should not add passages without names', () => {
|
|
128
128
|
const fr = FileReader.read('test/HTMLParser/missingPassageName.html');
|
|
129
129
|
const story = HTMLParser.parse(fr);
|
|
130
130
|
// There is only one passage, StoryTitle
|
|
131
|
-
expect(story.size()).toBe(
|
|
131
|
+
expect(story.size()).toBe(0);
|
|
132
132
|
});
|
|
133
133
|
|
|
134
|
-
|
|
134
|
+
it('Should not add passages without PID', () => {
|
|
135
135
|
const fr = FileReader.read('test/HTMLParser/missingPID.html');
|
|
136
136
|
const story = HTMLParser.parse(fr);
|
|
137
137
|
// There is only one passage, StoryTitle
|
|
138
|
-
expect(story.size()).toBe(
|
|
138
|
+
expect(story.size()).toBe(0);
|
|
139
139
|
});
|
|
140
140
|
|
|
141
|
-
|
|
141
|
+
it('Parse tag colors', () => {
|
|
142
142
|
const fr = FileReader.read('test/HTMLParser/tagColors.html');
|
|
143
143
|
const story = HTMLParser.parse(fr);
|
|
144
144
|
// Test for tag colors
|
|
@@ -146,21 +146,21 @@ describe('HTMLParser', function () {
|
|
|
146
146
|
expect(tagColors.a).toBe('red');
|
|
147
147
|
});
|
|
148
148
|
|
|
149
|
-
|
|
149
|
+
it('Will not set start if startnode is missing', () => {
|
|
150
150
|
const fr = FileReader.read('test/HTMLParser/missingStartnode.html');
|
|
151
151
|
const story = HTMLParser.parse(fr);
|
|
152
152
|
// Test for default start
|
|
153
153
|
expect(story.start).toBe('');
|
|
154
154
|
});
|
|
155
155
|
|
|
156
|
-
|
|
156
|
+
it('Throw error when startnode has PID that does not exist', () => {
|
|
157
157
|
const fr = FileReader.read('test/HTMLParser/lyingStartnode.html');
|
|
158
158
|
expect(() => {
|
|
159
159
|
HTMLParser.parse(fr);
|
|
160
160
|
}).toThrow();
|
|
161
161
|
});
|
|
162
162
|
|
|
163
|
-
|
|
163
|
+
it('Do not update name and color if those attributes do not exist', () => {
|
|
164
164
|
const fr = FileReader.read('test/HTMLParser/lyingTagColors.html');
|
|
165
165
|
const story = HTMLParser.parse(fr);
|
|
166
166
|
const tagColorProperties = Object.keys(story.tagColors).length;
|
|
@@ -168,8 +168,8 @@ describe('HTMLParser', function () {
|
|
|
168
168
|
});
|
|
169
169
|
});
|
|
170
170
|
|
|
171
|
-
describe('#escapeMetacharacters()',
|
|
172
|
-
|
|
171
|
+
describe('#escapeMetacharacters()', () => {
|
|
172
|
+
it('Should escape metacharacters', () => {
|
|
173
173
|
/* eslint no-useless-escape: "off" */
|
|
174
174
|
expect(HTMLParser.escapeMetacharacters('\\\{\\\}\\\[\\\]\\\\')).toBe('\\\\{\\\\}\\\\[\\\\]\\\\');
|
|
175
175
|
});
|
|
@@ -9,12 +9,11 @@
|
|
|
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.
|
|
12
|
+
<tw-storydata name="Title" startnode="4" creator="extwee" creator-version="2.0.6" ifid="AE48EB3C-00FE-41CF-A659-E48068758B06" 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
16
|
<tw-passagedata pid="2" name="B"></tw-passagedata>
|
|
17
|
-
<tw-passagedata pid="3" name="StoryTitle">Title</tw-passagedata>
|
|
18
17
|
<tw-passagedata pid="4" name="Start">Content</tw-passagedata>
|
|
19
18
|
</tw-storydata>
|
|
20
19
|
<script>
|
|
@@ -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…</div></div>
|
|
102
102
|
</div>
|
|
103
|
-
<tw-storydata name="twineExample" startnode="2" creator="extwee" creator-version="2.0.
|
|
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 */
|
|
@@ -12,7 +12,6 @@
|
|
|
12
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>
|
|
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
15
|
<tw-passagedata pid="1" name="Start" position="102,104" size="100,100" >[[Another passage]]
|
|
17
16
|
|
|
18
17
|
[[A third passage]]</tw-passagedata>
|
|
@@ -22,8 +21,6 @@
|
|
|
22
21
|
<tw-passagedata pid="3" name="A third passage" position="350,288" size="100,100" >[[Start]]</tw-passagedata>
|
|
23
22
|
<tw-passagedata pid="4" name="A fourth passage" position="587,197" size="100,100" >[[A fifth passage]]</tw-passagedata>
|
|
24
23
|
<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>
|
|
27
24
|
</tw-storydata>
|
|
28
25
|
<script>
|
|
29
26
|
(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){
|
|
@@ -12,7 +12,6 @@
|
|
|
12
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>
|
|
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>
|