extwee 2.2.4 → 2.2.5

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/README.md CHANGED
@@ -145,17 +145,17 @@ De-compile Twine 2 HTML into Twee 3:
145
145
 
146
146
  ### Compiling Twee 3 into Twine 1 HTML
147
147
 
148
- Enabling Twine 1 mode requires using the `-t1` or `--twine1` flag.
148
+ Enabling Twine 1 mode requires using the `--twine1` flag.
149
149
 
150
150
  Because Twine 1 story formats can be split across files, compilation requires the "engine" from Twine 1 named `engine.js`, the name of the story format, and then its `header.html` template code and the optional but often included `code.js` file.
151
151
 
152
- `extwee -t1 -c -i <tweeFile> -o <Twine1HTML> -engine <engineJS> -name <storyFormatName> -codejs <CodeJS> -header <header>`
152
+ `extwee --twine1 -c -i <tweeFile> -o <Twine1HTML> --engine <engineJS> --name <storyFormatName> --codejs <CodeJS> --header <header>`
153
153
 
154
154
  ### De-compiling Twine 1 HTML into Twee 3
155
155
 
156
- Enabling Twine 1 mode requires using the `-t1` or `--twine1` flag.
156
+ Enabling Twine 1 mode requires using the `--twine1` flag.
157
157
 
158
- `extwee -t1 -d -i <twine1HTML> -o <outputTwee>`
158
+ `extwee --twine1 -d -i <twine1HTML> -o <outputTwee>`
159
159
 
160
160
  <p align="right">(<a href="#readme-top">back to top</a>)</p>
161
161
 
@@ -163,7 +163,6 @@ Enabling Twine 1 mode requires using the `-t1` or `--twine1` flag.
163
163
 
164
164
  Each major version has its own GitHub project:
165
165
 
166
- - [Road to Extwee 2.2.0](https://github.com/users/videlais/projects/2)
167
166
  - [Road to Extwee 2.4.0](https://github.com/users/videlais/projects/4)
168
167
 
169
168
  ## Tree Shaking Support
package/eslint.config.js CHANGED
@@ -1,8 +1,10 @@
1
1
  import globals from "globals";
2
2
  import pluginJs from "@eslint/js";
3
3
  import jest from "eslint-plugin-jest";
4
+ import jsdoc from 'eslint-plugin-jsdoc';
4
5
 
5
6
  export default [
7
+ jsdoc.configs['flat/recommended'],
6
8
  {
7
9
  languageOptions: {
8
10
  globals: {
@@ -12,7 +14,11 @@ export default [
12
14
  }
13
15
  },
14
16
  plugins: {
15
- jest: jest
17
+ jest: jest,
18
+ jsdoc: jsdoc
19
+ },
20
+ rules: {
21
+ 'jsdoc/require-description': 'warn'
16
22
  }
17
23
  },
18
24
  pluginJs.configs.recommended,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "extwee",
3
- "version": "2.2.4",
3
+ "version": "2.2.5",
4
4
  "description": "A story compiler tool using Twine-compatible formats",
5
5
  "author": "Dan Cox",
6
6
  "main": "index.js",
@@ -24,34 +24,35 @@
24
24
  ],
25
25
  "license": "MIT",
26
26
  "dependencies": {
27
- "commander": "^12.1.0",
27
+ "commander": "^13.1.0",
28
28
  "graphemer": "^1.4.0",
29
29
  "html-entities": "^2.5.2",
30
- "node-html-parser": "^6.1.13",
30
+ "node-html-parser": "^7.0.1",
31
31
  "pickleparser": "^0.2.1",
32
- "semver": "^7.6.2",
33
- "uuid": "^10.0.0"
32
+ "semver": "^7.7.1",
33
+ "uuid": "^11.0.5"
34
34
  },
35
35
  "devDependencies": {
36
- "@babel/cli": "^7.25.6",
37
- "@babel/core": "^7.24.6",
38
- "@babel/preset-env": "^7.24.6",
39
- "@eslint/js": "^9.10.0",
36
+ "@babel/cli": "^7.26.4",
37
+ "@babel/core": "^7.26.8",
38
+ "@babel/preset-env": "^7.26.8",
39
+ "@eslint/js": "^9.20.0",
40
40
  "@types/uuid": "^10.0.0",
41
- "babel-loader": "^9.1.3",
41
+ "babel-loader": "^9.2.1",
42
42
  "clean-jsdoc-theme": "^4.3.0",
43
- "core-js": "^3.37.1",
44
- "esbuild": "^0.23.0",
45
- "eslint": "^9.10.0",
46
- "eslint-plugin-jest": "^28.8.3",
47
- "globals": "^15.9.0",
43
+ "core-js": "^3.40.0",
44
+ "esbuild": "^0.25.0",
45
+ "eslint": "^9.20.0",
46
+ "eslint-plugin-jest": "^28.11.0",
47
+ "eslint-plugin-jsdoc": "^50.6.3",
48
+ "globals": "^15.14.0",
48
49
  "jest": "^29.7.0",
49
50
  "regenerator-runtime": "^0.14.1",
50
51
  "shelljs": "^0.8.5",
51
- "typescript": "^5.4.5",
52
- "typescript-eslint": "^8.4.0",
53
- "webpack": "^5.91.0",
54
- "webpack-cli": "^5.1.4"
52
+ "typescript": "^5.7.3",
53
+ "typescript-eslint": "^8.23.0",
54
+ "webpack": "^5.97.1",
55
+ "webpack-cli": "^6.0.1"
55
56
  },
56
57
  "repository": {
57
58
  "type": "git",
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Parses a JSON object and extracts the StoryFormat, StoryTitle and StoryVersion.
3
+ * @param {object} obj Incoming JSON object.
4
+ * @returns {object} An object containing the extracted results.
5
+ */
6
+ export function parser(obj) {
7
+ // Check if the object is a valid JSON object.
8
+ if (typeof obj !== 'object' || obj === null) {
9
+ throw new Error('Error: Invalid JSON object');
10
+ }
11
+
12
+ // Extracted results.
13
+ let results = {
14
+ StoryFormat: null,
15
+ StoryTitle: null,
16
+ StoryVersion: null
17
+ };
18
+
19
+ // Does the object contain 'StoryFormat'?
20
+ if (Object.hasOwnProperty.call(obj, 'story-format')) {
21
+ results.StoryFormat = obj['story-format'];
22
+ }
23
+
24
+ // Does the object contain 'StoryTitle'?
25
+ if (Object.hasOwnProperty.call(obj, 'story-title')) {
26
+ results.StoryTitle = obj['story-title'];
27
+ }
28
+
29
+ // Does the object contain 'StoryVersion'?
30
+ if (Object.hasOwnProperty.call(obj, 'story-version')) {
31
+ results.StoryVersion = obj['story-version'];
32
+ }
33
+
34
+ // Return the extracted results.
35
+ return results;
36
+ }
@@ -0,0 +1,34 @@
1
+ import {readFileSync, existsSync} from 'node:fs';
2
+
3
+ /**
4
+ * Read a JSON file and return its contents.
5
+ * @param {string} path Path to the JSON file.
6
+ * @returns {object} Parsed JSON object.
7
+ * @throws {Error} If the file does not exist.
8
+ * @throws {Error} If the file is not a valid JSON file.
9
+ * @example
10
+ * const contents = reader('test/Config/files/valid.json');
11
+ * console.log(contents); // {"story-format": 'Harlowe', "story-title": "My Story"}
12
+ */
13
+ export function reader(path) {
14
+ // Does the file exist?
15
+ if (!existsSync(path)) {
16
+ throw new Error(`Error: File ${path} not found`);
17
+ }
18
+
19
+ // Read the file.
20
+ const contents = readFileSync(path, 'utf8');
21
+
22
+ // Parsed contents.
23
+ let parsedContents = null;
24
+
25
+ // Try to parse the contents into JSON object.
26
+ try {
27
+ parsedContents = JSON.parse(contents);
28
+ } catch (error) {
29
+ throw new Error(`Error: File ${path} is not a valid JSON file. ${error.message}`);
30
+ }
31
+
32
+ // Return the parsed contents.
33
+ return parsedContents;
34
+ }
package/src/Story.js CHANGED
@@ -5,7 +5,7 @@ import { encode } from 'html-entities';
5
5
  const creatorName = 'extwee';
6
6
 
7
7
  // Set the creator version.
8
- const creatorVersion = '2.2.4';
8
+ const creatorVersion = '2.2.5';
9
9
 
10
10
  /**
11
11
  * Story class.
package/src/TWS/parse.js CHANGED
@@ -28,9 +28,8 @@ function parse (binaryFileContents) {
28
28
  // Try to parse the pickle data, assuming it is pickle data.
29
29
  pythonObject = parser.parse(binaryFileContents);
30
30
  } catch (error) {
31
- console.log(error);
32
31
  // This is a Buffer, but not pickle data.
33
- throw new TypeError('Error: Buffer does not contain Python pickle data!');
32
+ throw new TypeError(`Error: Buffer does not contain Python pickle data! ${error}`);
34
33
  }
35
34
 
36
35
  // Create Story object.
package/src/extwee.js CHANGED
@@ -53,12 +53,12 @@ const isFile = (path) => {
53
53
  program
54
54
  .name('extwee')
55
55
  .description('CLI for Extwee')
56
- .version('2.2.0', '-v, -V, --version', 'Output the current version')
56
+ .option('-v, --version', '2.2.4')
57
57
  .option('-c, --compile', 'Compile input into output')
58
58
  .option('-d, --decompile', 'De-compile input into output')
59
- .option('-t1, --twine1', 'Enable Twine 1 processing')
60
- .option('-name <storyFormatName>', 'Name of the Twine 1 story format (needed for `code.js` inclusion)')
61
- .option('-codejs <codeJSFile>', 'Twine 1 code.js file for use with Twine 1 HTML', (value) => {
59
+ .option('--twine1', 'Enable Twine 1 processing')
60
+ .option('--name <storyFormatName>', 'Name of the Twine 1 story format (needed for `code.js` inclusion)')
61
+ .option('--codejs <codeJSFile>', 'Twine 1 code.js file for use with Twine 1 HTML', (value) => {
62
62
  // Does the input file exist?
63
63
  if (isFile(value) === false) {
64
64
  // We cannot do anything without valid input.
@@ -67,7 +67,7 @@ program
67
67
 
68
68
  return value;
69
69
  })
70
- .option('-engine <engineFile>', 'Twine 1 engine.js file for use with Twine 1 HTML', (value) => {
70
+ .option('--engine <engineFile>', 'Twine 1 engine.js file for use with Twine 1 HTML', (value) => {
71
71
  // Does the input file exist?
72
72
  if (isFile(value) === false) {
73
73
  // We cannot do anything without valid input.
@@ -76,7 +76,7 @@ program
76
76
 
77
77
  return value;
78
78
  })
79
- .option('-header <headerFile>', 'Twine 1 header.html file for use with Twine 1 HTML', (value) => {
79
+ .option('--header <headerFile>', 'Twine 1 header.html file for use with Twine 1 HTML', (value) => {
80
80
  // Does the input file exist?
81
81
  if (isFile(value) === false) {
82
82
  // We cannot do anything without valid input.
@@ -27,12 +27,12 @@ describe('CLI', () => {
27
27
  });
28
28
 
29
29
  it('Twine 1 - compile: Twee 3 + Twine 1 engine.js + Twine 1 code.js + Twine 1 header.html', () => {
30
- shell.exec(`node ${currentPath}/src/extwee.js -t1 -c -i ${testFilePath}/example6.twee -o ${testFilePath}/output/test3.html -codejs ${testFilePath}/twine1/code.js -engine ${testFilePath}/twine1/engine.js -header ${testFilePath}/twine1/header.html -name Test`);
30
+ shell.exec(`node ${currentPath}/src/extwee.js --twine1 -c -i ${testFilePath}/example6.twee -o ${testFilePath}/output/test3.html --codejs ${testFilePath}/twine1/code.js --engine ${testFilePath}/twine1/engine.js --header ${testFilePath}/twine1/header.html --name Test`);
31
31
  expect(shell.test('-e', `${testFilePath}/output/test3.html`)).toBe(true);
32
32
  });
33
33
 
34
34
  it('Twine 1 - de-compile: Twine 1 HTML into Twee 3', () => {
35
- shell.exec(`node ${currentPath}/src/extwee.js -t1 -d -i ${testFilePath}/twine1Test.html -o ${testFilePath}/output/test.twee`);
35
+ shell.exec(`node ${currentPath}/src/extwee.js --twine1 -d -i ${testFilePath}/twine1Test.html -o ${testFilePath}/output/test.twee`);
36
36
  expect(shell.test('-e', `${testFilePath}/output/test.twee`)).toBe(true);
37
37
  });
38
38
 
@@ -0,0 +1,46 @@
1
+ import {reader as ConfigReader} from '../../src/Config/reader.js';
2
+ import {parser as ConfigParser} from '../../src/Config/parser.js';
3
+
4
+ describe('src/Config/reader.js', () => {
5
+ describe('reader()', () => {
6
+ it('should throw an error if the file does not exist', () => {
7
+ expect(() => ConfigReader('non-existent-file.json')).toThrow('Error: File non-existent-file.json not found');
8
+ });
9
+
10
+ it('should throw an error if the file is not a valid JSON file', () => {
11
+ expect(() => ConfigReader('test/Config/files/invalid.json')).toThrow();
12
+ });
13
+
14
+ it('should return the parsed JSON contents of the file', () => {
15
+ const contents = ConfigReader('test/Config/files/valid.json');
16
+ expect(contents).toEqual({
17
+ "story-format": 'Harlowe',
18
+ "story-title": "My Story",
19
+ "story-version": "2.0.1"
20
+ });
21
+ });
22
+ });
23
+
24
+ describe('parser()', () => {
25
+
26
+ it('should throw an error if the object is not a valid JSON object', () => {
27
+ expect(() => ConfigParser('{')).toThrow();
28
+ });
29
+
30
+ it('should extract the StoryFormat, StoryTitle, and StoryVersion from the JSON object', () => {
31
+ const jsonObject = ConfigReader('test/Config/files/valid.json');
32
+ const contents = ConfigParser(jsonObject);
33
+ expect(contents.StoryFormat).toEqual('Harlowe');
34
+ expect(contents.StoryTitle).toEqual('My Story');
35
+ expect(contents.StoryVersion).toEqual('2.0.1');
36
+ });
37
+
38
+ it('should not extract the StoryFormat, StoryTitle, and StoryVersion if they do not exist in the JSON object', () => {
39
+ const jsonObject = ConfigReader('test/Config/files/empty.json');
40
+ const contents = ConfigParser(jsonObject);
41
+ expect(contents.StoryFormat).toBeNull();
42
+ expect(contents.StoryTitle).toBeNull();
43
+ expect(contents.StoryVersion).toBeNull();
44
+ });
45
+ });
46
+ });
@@ -0,0 +1,3 @@
1
+ {
2
+ "some": "value"
3
+ }
@@ -0,0 +1 @@
1
+ invalid
@@ -0,0 +1,5 @@
1
+ {
2
+ "story-format": "Harlowe",
3
+ "story-title": "My Story",
4
+ "story-version": "2.0.1"
5
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Parses a JSON object and extracts the StoryFormat, StoryTitle and StoryVersion.
3
+ * @param {object} obj Incoming JSON object.
4
+ * @returns {object} An object containing the extracted results.
5
+ */
6
+ export function parser(obj: object): object;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Read a JSON file and return its contents.
3
+ * @param {string} path Path to the JSON file.
4
+ * @returns {object} Parsed JSON object.
5
+ * @throws {Error} If the file does not exist.
6
+ * @throws {Error} If the file is not a valid JSON file.
7
+ * @example
8
+ * const contents = reader('test/Config/files/valid.json');
9
+ * console.log(contents); // {"story-format": 'Harlowe', "story-title": "My Story"}
10
+ */
11
+ export function reader(path: string): object;
@@ -68,12 +68,12 @@ export default class Passage {
68
68
  * @param {object} m - Replacement object
69
69
  * @throws {Error} Metadata must be an object literal!
70
70
  */
71
- set metadata(m: any);
71
+ set metadata(m: object);
72
72
  /**
73
73
  * Metadata
74
74
  * @returns {object} Metadata
75
75
  */
76
- get metadata(): any;
76
+ get metadata(): object;
77
77
  /**
78
78
  * @param {string} t - Replacement text
79
79
  * @throws {Error} Text should be a String!
package/types/Story.d.ts CHANGED
@@ -50,12 +50,12 @@ export class Story {
50
50
  /**
51
51
  * @param {object} a - Replacement tag colors
52
52
  */
53
- set tagColors(a: any);
53
+ set tagColors(a: object);
54
54
  /**
55
55
  * Tag Colors object (each property is a tag and its color)
56
56
  * @returns {object} tag colors array
57
57
  */
58
- get tagColors(): any;
58
+ get tagColors(): object;
59
59
  /**
60
60
  * @param {string} i - Replacement IFID.
61
61
  */
@@ -86,12 +86,12 @@ export class Story {
86
86
  /**
87
87
  * @param {object} o - Replacement metadata
88
88
  */
89
- set metadata(o: any);
89
+ set metadata(o: object);
90
90
  /**
91
91
  * Metadata of Story.
92
92
  * @returns {object} metadata of story
93
93
  */
94
- get metadata(): any;
94
+ get metadata(): object;
95
95
  /**
96
96
  * @param {string} f - Replacement format
97
97
  */
@@ -226,5 +226,5 @@ export class Story {
226
226
  #private;
227
227
  }
228
228
  export const creatorName: "extwee";
229
- export const creatorVersion: "2.2.4";
229
+ export const creatorVersion: "2.2.5";
230
230
  import Passage from './Passage.js';
package/build/extwee DELETED
Binary file
package/build/extwee.exe DELETED
Binary file