extwee 2.2.1 → 2.2.3

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 (68) hide show
  1. package/.eslintrc.json +7 -13
  2. package/.github/codeql-analysis.yml +51 -0
  3. package/README.md +9 -3
  4. package/build/extwee +0 -0
  5. package/build/extwee.web.min.js +1 -1
  6. package/docs/objects/story.md +1 -2
  7. package/index.js +2 -0
  8. package/jest.config.json +5 -0
  9. package/package.json +24 -21
  10. package/src/IFID/generate.js +20 -0
  11. package/src/JSON/parse.js +43 -0
  12. package/src/Passage.js +52 -3
  13. package/src/Story.js +266 -107
  14. package/src/StoryFormat/parse.js +190 -80
  15. package/src/StoryFormat.js +78 -88
  16. package/src/TWS/parse.js +2 -2
  17. package/src/Twee/parse.js +2 -3
  18. package/src/Twine1HTML/compile.js +2 -0
  19. package/src/Twine1HTML/parse.js +2 -3
  20. package/src/Twine2ArchiveHTML/compile.js +8 -0
  21. package/src/Twine2ArchiveHTML/parse.js +33 -3
  22. package/src/Twine2HTML/compile.js +31 -6
  23. package/src/Twine2HTML/parse.js +49 -54
  24. package/test/IFID/IFID.Generate.test.js +10 -0
  25. package/test/JSON/JSON.Parse.test.js +4 -4
  26. package/test/{Passage.test.js → Objects/Passage.test.js} +4 -4
  27. package/test/{Story.test.js → Objects/Story.test.js} +259 -50
  28. package/test/{StoryFormat.test.js → Objects/StoryFormat.test.js} +10 -3
  29. package/test/StoryFormat/StoryFormat.Parse.test.js +442 -55
  30. package/test/TWS/Parse.test.js +1 -1
  31. package/test/Twine2ArchiveHTML/Twine2ArchiveHTML.Parse.test.js +20 -4
  32. package/test/Twine2HTML/Twine2HTML.Compile.test.js +35 -120
  33. package/test/Twine2HTML/Twine2HTML.Parse.test.js +57 -38
  34. package/test/Twine2HTML/Twine2HTMLCompiler/format.js +9 -0
  35. package/test/Twine2HTML/Twine2HTMLParser/missingZoom.html +1 -1
  36. package/types/IFID/generate.d.ts +14 -0
  37. package/types/JSON/parse.d.ts +51 -0
  38. package/types/Passage.d.ts +117 -0
  39. package/types/Story.d.ts +230 -0
  40. package/types/StoryFormat/parse.d.ts +50 -0
  41. package/types/StoryFormat.d.ts +121 -0
  42. package/types/TWS/parse.d.ts +10 -0
  43. package/types/Twee/parse.d.ts +9 -0
  44. package/types/Twine1HTML/compile.d.ts +19 -0
  45. package/types/Twine1HTML/parse.d.ts +9 -0
  46. package/types/Twine2ArchiveHTML/compile.d.ts +14 -0
  47. package/types/Twine2ArchiveHTML/parse.d.ts +36 -0
  48. package/types/Twine2HTML/compile.d.ts +14 -0
  49. package/types/Twine2HTML/parse.d.ts +20 -0
  50. package/web-index.js +2 -0
  51. package/test/StoryFormat/StoryFormatParser/example.js +0 -3
  52. package/test/StoryFormat/StoryFormatParser/example2.js +0 -3
  53. package/test/StoryFormat/StoryFormatParser/format.js +0 -1
  54. package/test/StoryFormat/StoryFormatParser/format_doublename.js +0 -1
  55. package/test/StoryFormat/StoryFormatParser/harlowe.js +0 -3
  56. package/test/StoryFormat/StoryFormatParser/missingAuthor.js +0 -1
  57. package/test/StoryFormat/StoryFormatParser/missingDescription.js +0 -1
  58. package/test/StoryFormat/StoryFormatParser/missingImage.js +0 -1
  59. package/test/StoryFormat/StoryFormatParser/missingLicense.js +0 -1
  60. package/test/StoryFormat/StoryFormatParser/missingName.js +0 -1
  61. package/test/StoryFormat/StoryFormatParser/missingProofing.js +0 -1
  62. package/test/StoryFormat/StoryFormatParser/missingSource.js +0 -1
  63. package/test/StoryFormat/StoryFormatParser/missingURL.js +0 -1
  64. package/test/StoryFormat/StoryFormatParser/missingVersion.js +0 -1
  65. package/test/StoryFormat/StoryFormatParser/versionWrong.js +0 -1
  66. package/test/Twine2HTML/Twine2HTMLParser/missingName.html +0 -33
  67. package/test/Twine2HTML/Twine2HTMLParser/missingPID.html +0 -15
  68. package/test/Twine2HTML/Twine2HTMLParser/missingPassageName.html +0 -15
@@ -12,7 +12,7 @@ Depending on the incoming format or creation method, many possible properties ca
12
12
  - format ( string ) Name of the story format for Twine 2 HTML.
13
13
  - formatVersion ( string ) Semantic version of the named story format for Twine 2 HTML or Twee 3.
14
14
  - zoom ( float ) Zoom level for Twine 2 HTML or Twee 3.
15
- - passages ( array(Passage) ) **[Read-only]** Collection of internal passages.
15
+ - passages ( array(Passage) ) Collection of internal passages.
16
16
  - creator ( string ) Name of story creation tool. (Defaults to "Extwee").
17
17
  - creatorVersion ( string ) Semantic version of named creation tool.
18
18
  - metadata ( object ) Key-value pairs of metadata values.
@@ -41,7 +41,6 @@ As collections of passages, each **Story** has multiple methods for accessing an
41
41
  - `getPassagesByTags(string)`: Returns an array of any passages containing a particular tag value.
42
42
  - `getPassageByName(string)`: Returns either `null`` or the named passage.
43
43
  - `size()`: Returns the number of passages in the collection.
44
- - `forEachPassage(callback)`: Allows for iterating over the passage collection.
45
44
 
46
45
  ## Passage Creation Example
47
46
 
package/index.js CHANGED
@@ -8,6 +8,7 @@ import { parse as parseTWS } from './src/TWS/parse.js';
8
8
  import { compile as compileTwine1HTML } from './src/Twine1HTML/compile.js';
9
9
  import { compile as compileTwine2HTML } from './src/Twine2HTML/compile.js';
10
10
  import { compile as compileTwine2ArchiveHTML } from './src/Twine2ArchiveHTML/compile.js';
11
+ import { generate as generateIFID } from './src/IFID/generate.js';
11
12
  import { Story } from './src/Story.js';
12
13
  import Passage from './src/Passage.js';
13
14
  import StoryFormat from './src/StoryFormat.js';
@@ -23,6 +24,7 @@ export {
23
24
  compileTwine1HTML,
24
25
  compileTwine2HTML,
25
26
  compileTwine2ArchiveHTML,
27
+ generateIFID,
26
28
  Story,
27
29
  Passage,
28
30
  StoryFormat
@@ -0,0 +1,5 @@
1
+ {
2
+ "bail": 1,
3
+ "verbose": true,
4
+ "collectCoverage": true
5
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "extwee",
3
- "version": "2.2.1",
3
+ "version": "2.2.3",
4
4
  "description": "A story compiler tool using Twine-compatible formats",
5
5
  "author": "Dan Cox",
6
6
  "main": "index.js",
@@ -8,12 +8,13 @@
8
8
  "extwee": "src/extwee.js"
9
9
  },
10
10
  "scripts": {
11
- "test": "jest --silent --runInBand --coverage --colors",
11
+ "test": "jest --runInBand",
12
12
  "lint": "eslint ./src/**/*.js --fix",
13
13
  "lint:test": "eslint ./test/**/*.test.js --fix",
14
14
  "build:web": "webpack",
15
15
  "build:bin": "esbuild ./src/extwee.js --bundle --platform=node --target=node12 --outfile=out.js && pkg -t node18-macos-x64 out.js --output ./build/extwee && rm out.js",
16
- "all": "npm run lint && npm run lint:test && npm run test"
16
+ "gen-types": "npx -p typescript tsc src/**/*.js --declaration --allowJs --emitDeclarationOnly --outDir types",
17
+ "all": "npm run lint && npm run lint:test && npm run test && npm run gen-types"
17
18
  },
18
19
  "keywords": [
19
20
  "twine",
@@ -23,42 +24,44 @@
23
24
  ],
24
25
  "license": "MIT",
25
26
  "dependencies": {
26
- "commander": "^11.1.0",
27
- "html-entities": "^2.4.0",
28
- "node-html-parser": "^6.1.12",
27
+ "commander": "^12.0.0",
28
+ "graphemer": "^1.4.0",
29
+ "html-entities": "^2.5.2",
30
+ "node-html-parser": "^6.1.13",
29
31
  "pickleparser": "^0.2.1",
30
- "semver": "^7.5.4",
32
+ "semver": "^7.6.0",
31
33
  "uuid": "^9.0.1"
32
34
  },
33
35
  "devDependencies": {
34
- "@babel/cli": "^7.23.4",
35
- "@babel/core": "^7.23.7",
36
- "@babel/eslint-parser": "^7.23.3",
36
+ "@babel/cli": "^7.24.1",
37
+ "@babel/core": "^7.24.4",
38
+ "@babel/eslint-parser": "^7.24.1",
37
39
  "@babel/eslint-plugin": "^7.23.5",
38
- "@babel/preset-env": "^7.23.8",
40
+ "@babel/preset-env": "^7.24.4",
41
+ "@types/uuid": "^9.0.7",
39
42
  "babel-loader": "^9.1.3",
40
- "clean-jsdoc-theme": "^4.2.17",
41
- "core-js": "^3.35.0",
42
- "docsify-cli": "^4.4.4",
43
- "esbuild": "0.19.11",
44
- "eslint": "^8.56.0",
43
+ "clean-jsdoc-theme": "^4.2.18",
44
+ "core-js": "^3.36.1",
45
+ "esbuild": "^0.20.2",
46
+ "eslint": "^8.57.0",
45
47
  "eslint-config-standard": "^17.1.0",
46
48
  "eslint-plugin-import": "^2.29.1",
47
- "eslint-plugin-jest": "^27.6.1",
48
- "eslint-plugin-jsdoc": "^48.0.2",
49
+ "eslint-plugin-jest": "^28.2.0",
50
+ "eslint-plugin-jsdoc": "^48.2.3",
51
+ "eslint-plugin-n": "^16.6.2",
49
52
  "eslint-plugin-node": "^11.1.0",
50
53
  "eslint-plugin-promise": "^6.1.1",
51
54
  "jest": "^29.7.0",
52
55
  "pkg": "^5.8.1",
53
56
  "regenerator-runtime": "^0.14.1",
54
57
  "shelljs": "^0.8.5",
55
- "typescript": "^5.3.3",
56
- "webpack": "^5.89.0",
58
+ "typescript": "^5.4.5",
59
+ "webpack": "^5.91.0",
57
60
  "webpack-cli": "^5.1.4"
58
61
  },
59
62
  "repository": {
60
63
  "type": "git",
61
- "url": "https://github.com/videlais/extwee"
64
+ "url": "git+https://github.com/videlais/extwee.git"
62
65
  },
63
66
  "bugs": {
64
67
  "url": "https://github.com/videlais/extwee/issues"
@@ -0,0 +1,20 @@
1
+ import { v4 } from 'uuid';
2
+
3
+ /**
4
+ * Generates an Interactive Fiction Identification (IFID) based the Treaty of Babel.
5
+ *
6
+ * For Twine works, the IFID is a UUID (v4) in uppercase.
7
+ * @see Treaty of Babel ({@link https://babel.ifarchive.org/babel_rev11.html#the-ifid-for-an-html-story-file})
8
+ * @function generate
9
+ * @description Generates a new IFID.
10
+ * @returns {string} IFID
11
+ * @example
12
+ * const ifid = generate();
13
+ * console.log(ifid);
14
+ * // => 'A1B2C3D4-E5F6-G7H8-I9J0-K1L2M3N4O5P6'
15
+ */
16
+ function generate () {
17
+ return v4().toUpperCase();
18
+ }
19
+
20
+ export { generate };
package/src/JSON/parse.js CHANGED
@@ -3,9 +3,52 @@ import Passage from '../Passage.js';
3
3
 
4
4
  /**
5
5
  * Parse JSON representation into Story.
6
+ * @see {@link https://github.com/iftechfoundation/twine-specs/blob/master/twine-2-jsonoutput-doc.md Twine 2 JSON Specification}
6
7
  * @function parse
7
8
  * @param {string} jsonString - JSON string to convert to Story.
9
+ * @throws {Error} - Invalid JSON!
8
10
  * @returns {Story} Story object.
11
+ * @example
12
+ * const jsonString = `{
13
+ * "name": "My Story",
14
+ * "start": "First Passage",
15
+ * "ifid": "A1B2C3D4-E5F6-G7H8-I9J0-K1L2M3N4O5P6",
16
+ * "format": "SugarCube",
17
+ * "formatVersion": "2.31.0",
18
+ * "creator": "Twine",
19
+ * "creatorVersion": "2.3.9",
20
+ * "zoom": 1,
21
+ * "passages": [
22
+ * {
23
+ * "name": "First Passage",
24
+ * "tags": "",
25
+ * "metadata": "",
26
+ * "text": "This is the first passage."
27
+ * },
28
+ * ]
29
+ * }`;
30
+ * const story = parse(jsonString);
31
+ * console.log(story);
32
+ * // => Story {
33
+ * // name: 'My Story',
34
+ * // start: 'First Passage',
35
+ * // IFID: 'A1B2C3D4-E5F6-G7H8-I9J0-K1L2M3N4O5P6',
36
+ * // format: 'SugarCube',
37
+ * // formatVersion: '2.31.0',
38
+ * // creator: 'Twine',
39
+ * // creatorVersion: '2.3.9',
40
+ * // zoom: 1,
41
+ * // tagColors: {},
42
+ * // metadata: {},
43
+ * // passages: [
44
+ * // Passage {
45
+ * // name: 'First Passage',
46
+ * // tags: '',
47
+ * // metadata: '',
48
+ * // text: 'This is the first passage.'
49
+ * // }
50
+ * // ]
51
+ * // }
9
52
  */
10
53
  function parse (jsonString) {
11
54
  // Create future object.
package/src/Passage.js CHANGED
@@ -1,30 +1,68 @@
1
1
  import { encode } from 'html-entities';
2
2
 
3
3
  /**
4
- * A passage is the smallest unit of a Twine story.
5
- */
4
+ * Passage class.
5
+ * @class
6
+ * @classdesc Represents a passage in a Twine story.
7
+ * @property {string} name - Name of the passage.
8
+ * @property {Array} tags - Tags for the passage.
9
+ * @property {object} metadata - Metadata for the passage.
10
+ * @property {string} text - Text content of the passage.
11
+ * @method {string} toTwee - Return a Twee representation.
12
+ * @method {string} toJSON - Return JSON representation.
13
+ * @method {string} toTwine2HTML - Return Twine 2 HTML representation.
14
+ * @method {string} toTwine1HTML - Return Twine 1 HTML representation.
15
+ * @example
16
+ * const p = new Passage('Start', 'This is the start of the story.');
17
+ * console.log(p.toTwee());
18
+ * // :: Start
19
+ * // This is the start of the story.
20
+ * //
21
+ * console.log(p.toJSON());
22
+ * // {"name":"Start","tags":[],"metadata":{},"text":"This is the start of the story."}
23
+ * console.log(p.toTwine2HTML());
24
+ * // <tw-passagedata pid="1" name="Start" tags="" >This is the start of the story.</tw-passagedata>
25
+ * console.log(p.toTwine1HTML());
26
+ * // <div tiddler="Start" tags="" modifier="extwee" twine-position="10,10">This is the start of the story.</div>
27
+ * @example
28
+ * const p = new Passage('Start', 'This is the start of the story.', ['start', 'beginning'], {position: '10,10', size: '100,100'});
29
+ * console.log(p.toTwee());
30
+ * // :: Start [start beginning] {"position":"10,10","size":"100,100"}
31
+ * // This is the start of the story.
32
+ * //
33
+ * console.log(p.toJSON());
34
+ * // {"name":"Start","tags":["start","beginning"],"metadata":{"position":"10,10","size":"100,100"},"text":"This is the start of the story."}
35
+ * console.log(p.toTwine2HTML());
36
+ * // <tw-passagedata pid="1" name="Start" tags="start beginning" position="10,10" size="100,100">This is the start of the story.</tw-passagedata>
37
+ * console.log(p.toTwine1HTML());
38
+ * // <div tiddler="Start" tags="start beginning" modifier="extwee" twine-position="10,10">This is the start of the story.</div>
39
+ */
6
40
  export default class Passage {
7
41
  /**
8
42
  * Name of the Passage
9
43
  * @private
44
+ * @type {string}
10
45
  */
11
- #_name = null;
46
+ #_name = '';
12
47
 
13
48
  /**
14
49
  * Internal array of tags
15
50
  * @private
51
+ * @type {Array}
16
52
  */
17
53
  #_tags = [];
18
54
 
19
55
  /**
20
56
  * Internal metadata of passage
21
57
  * @private
58
+ * @type {object}
22
59
  */
23
60
  #_metadata = {};
24
61
 
25
62
  /**
26
63
  * Internal text of the passage
27
64
  * @private
65
+ * @type {string}
28
66
  */
29
67
  #_text = '';
30
68
 
@@ -57,6 +95,7 @@ export default class Passage {
57
95
 
58
96
  /**
59
97
  * @param {string} s - Name to replace
98
+ * @throws {Error} Name must be a String!
60
99
  */
61
100
  set name (s) {
62
101
  if (typeof s === 'string') {
@@ -74,6 +113,7 @@ export default class Passage {
74
113
 
75
114
  /**
76
115
  * @param {Array} t - Replacement array
116
+ * @throws {Error} Tags must be an array!
77
117
  */
78
118
  set tags (t) {
79
119
  // Test if tags is an array
@@ -93,6 +133,7 @@ export default class Passage {
93
133
 
94
134
  /**
95
135
  * @param {object} m - Replacement object
136
+ * @throws {Error} Metadata must be an object literal!
96
137
  */
97
138
  set metadata (m) {
98
139
  // Test if metadata was an object
@@ -111,6 +152,7 @@ export default class Passage {
111
152
 
112
153
  /**
113
154
  * @param {string} t - Replacement text
155
+ * @throws {Error} Text should be a String!
114
156
  */
115
157
  set text (t) {
116
158
  // Test if text is a String
@@ -123,6 +165,10 @@ export default class Passage {
123
165
 
124
166
  /**
125
167
  * Return a Twee representation.
168
+ *
169
+ * See: https://github.com/iftechfoundation/twine-specs/blob/master/twee-3-specification.md
170
+ *
171
+ * @method toTwee
126
172
  * @returns {string} String form of passage.
127
173
  */
128
174
  toTwee () {
@@ -153,6 +199,7 @@ export default class Passage {
153
199
 
154
200
  /**
155
201
  * Return JSON representation.
202
+ * @method toJSON
156
203
  * @returns {string} JSON string.
157
204
  */
158
205
  toJSON () {
@@ -171,6 +218,7 @@ export default class Passage {
171
218
  /**
172
219
  * Return Twine 2 HTML representation.
173
220
  * (Default Passage ID is 1.)
221
+ * @method toTwine2HTML
174
222
  * @param {number} pid - Passage ID (PID) to record in HTML.
175
223
  * @returns {string} Twine 2 HTML string.
176
224
  */
@@ -223,6 +271,7 @@ export default class Passage {
223
271
 
224
272
  /**
225
273
  * Return Twine 1 HTML representation.
274
+ * @method toTwine1HTML
226
275
  * @returns {string} Twine 1 HTML string.
227
276
  */
228
277
  toTwine1HTML () {