extwee 2.3.2 → 2.3.4

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 (55) hide show
  1. package/build/extwee.core.min.js +1 -0
  2. package/build/extwee.twine1html.min.js +1 -0
  3. package/build/extwee.twine2archive.min.js +1 -0
  4. package/build/extwee.tws.min.js +1 -0
  5. package/build/test-modular.html +126 -0
  6. package/docs/build/extwee.core.min.js +1 -0
  7. package/docs/build/extwee.twine1html.min.js +1 -0
  8. package/docs/build/extwee.twine2archive.min.js +1 -0
  9. package/docs/build/extwee.tws.min.js +1 -0
  10. package/docs/demos/compiler/extwee.core.min.js +1 -0
  11. package/docs/demos/compiler/index.css +105 -0
  12. package/docs/demos/compiler/index.html +359 -0
  13. package/eslint.config.js +4 -1
  14. package/package.json +25 -22
  15. package/src/IFID/generate.js +2 -2
  16. package/src/Story.js +1 -1
  17. package/src/Twine1HTML/parse-web.js +255 -0
  18. package/src/Twine2ArchiveHTML/parse-web.js +134 -0
  19. package/src/Twine2HTML/parse-web.js +434 -0
  20. package/src/Web/web-core.js +51 -0
  21. package/src/Web/web-twine1html.js +35 -0
  22. package/src/Web/web-twine2archive.js +35 -0
  23. package/src/Web/web-tws.js +30 -0
  24. package/test/Config/Config.test.js +1 -1
  25. package/test/Config/isDirectory.test.js +15 -9
  26. package/test/Config/isFile.test.js +14 -11
  27. package/test/Config/loadStoryFormat.test.js +49 -33
  28. package/test/Config/readDirectories.test.js +25 -15
  29. package/test/Objects/Story.test.js +1 -0
  30. package/test/StoryFormat/StoryFormat.Parse.test.js +1 -0
  31. package/test/Twine1HTML/Twine1HTML.Parse.Web.test.js +484 -0
  32. package/test/Twine2ArchiveHTML/Twine2ArchiveHTML.Parse.Web.test.js +293 -0
  33. package/test/Twine2ArchiveHTML/Twine2ArchiveHTML.Parse.test.js +1 -0
  34. package/test/Twine2HTML/Twine2HTML.Parse.Web.test.js +329 -0
  35. package/test/Twine2HTML/Twine2HTML.Parse.test.js +1 -0
  36. package/test/Web/web-core-coverage.test.js +175 -0
  37. package/test/Web/web-core-global.test.js +93 -0
  38. package/test/Web/web-core.test.js +156 -0
  39. package/test/Web/window.Extwee.test.js +25 -13
  40. package/types/src/Story.d.ts +1 -1
  41. package/types/src/Twine1HTML/parse-web.d.ts +10 -0
  42. package/types/src/Twine2ArchiveHTML/parse-web.d.ts +37 -0
  43. package/types/src/Twine2HTML/parse-web.d.ts +21 -0
  44. package/types/src/Web/html-entities-lite.d.ts +12 -0
  45. package/types/src/Web/semver-lite.d.ts +10 -0
  46. package/types/src/Web/uuid-lite.d.ts +6 -0
  47. package/types/src/Web/web-core.d.ts +23 -0
  48. package/types/src/Web/web-index.d.ts +1 -0
  49. package/types/src/Web/web-twine1html.d.ts +10 -0
  50. package/types/src/Web/web-twine2archive.d.ts +10 -0
  51. package/types/src/Web/web-tws.d.ts +7 -0
  52. package/webpack.config.js +23 -2
  53. package/build/extwee.web.min.js +0 -2
  54. package/build/extwee.web.min.js.LICENSE.txt +0 -1
  55. package/web-index.js +0 -31
@@ -1,11 +1,14 @@
1
- import { isFile } from '../../src/CLI/isFile.js';
2
- import { statSync } from 'node:fs';
1
+ import {jest} from '@jest/globals';
3
2
 
4
- // Mock the statSync function from 'fs'.
5
- jest.mock('node:fs', () => ({
6
- statSync: jest.fn(),
3
+ // Mock the fs module before importing anything that uses it
4
+ const mockStatSync = jest.fn();
5
+ jest.unstable_mockModule('node:fs', () => ({
6
+ statSync: mockStatSync
7
7
  }));
8
8
 
9
+ // Now import the modules that depend on the mocked module
10
+ const { isFile } = await import('../../src/CLI/isFile.js');
11
+
9
12
  describe('isFile', () => {
10
13
  afterEach(() => {
11
14
  jest.clearAllMocks();
@@ -13,36 +16,36 @@ describe('isFile', () => {
13
16
 
14
17
  it('should return true if the path is a valid file', () => {
15
18
  // Mock statSync to return an object with isFile() returning true.
16
- statSync.mockReturnValue({
19
+ mockStatSync.mockReturnValue({
17
20
  isFile: jest.fn(() => true),
18
21
  });
19
22
 
20
23
  const result = isFile('/path/to/file');
21
24
  expect(result).toBe(true);
22
- expect(statSync).toHaveBeenCalledWith('/path/to/file');
25
+ expect(mockStatSync).toHaveBeenCalledWith('/path/to/file');
23
26
  });
24
27
 
25
28
  it('should return false if the path is not a valid file', () => {
26
29
  // Mock statSync to return an object with isFile() returning false.
27
- statSync.mockReturnValue({
30
+ mockStatSync.mockReturnValue({
28
31
  isFile: jest.fn(() => false),
29
32
  });
30
33
 
31
34
  const result = isFile('/path/to/directory');
32
35
  expect(result).toBe(false);
33
- expect(statSync).toHaveBeenCalledWith('/path/to/directory');
36
+ expect(mockStatSync).toHaveBeenCalledWith('/path/to/directory');
34
37
  });
35
38
 
36
39
  it('should return false and log an error if statSync throws an error', () => {
37
40
  // Mock statSync to throw an error.
38
41
  const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
39
- statSync.mockImplementation(() => {
42
+ mockStatSync.mockImplementation(() => {
40
43
  throw new Error('File not found');
41
44
  });
42
45
 
43
46
  const result = isFile('/invalid/path');
44
47
  expect(result).toBe(false);
45
- expect(statSync).toHaveBeenCalledWith('/invalid/path');
48
+ expect(mockStatSync).toHaveBeenCalledWith('/invalid/path');
46
49
  expect(consoleErrorSpy).toHaveBeenCalledWith(expect.stringContaining('Error: Error: File not found'));
47
50
 
48
51
  consoleErrorSpy.mockRestore();
@@ -1,13 +1,29 @@
1
- import { loadStoryFormat } from "../../src/CLI/ProcessConfig/loadStoryFormat.js";
2
- import { isDirectory } from "../../src/CLI/isDirectory.js";
3
- import { isFile } from "../../src/CLI/isFile.js";
4
- import { readDirectories } from "../../src/CLI/ProcessConfig/readDirectories.js";
5
- import { readFileSync } from "node:fs";
1
+ import {jest} from '@jest/globals';
6
2
 
7
- jest.mock("../../src/CLI/isDirectory.js");
8
- jest.mock("../../src/CLI/isFile.js");
9
- jest.mock("../../src/CLI/ProcessConfig/readDirectories.js");
10
- jest.mock("node:fs");
3
+ // Mock all dependencies before importing anything that uses them
4
+ const mockIsDirectory = jest.fn();
5
+ const mockIsFile = jest.fn();
6
+ const mockReadDirectories = jest.fn();
7
+ const mockReadFileSync = jest.fn();
8
+
9
+ jest.unstable_mockModule("../../src/CLI/isDirectory.js", () => ({
10
+ isDirectory: mockIsDirectory
11
+ }));
12
+
13
+ jest.unstable_mockModule("../../src/CLI/isFile.js", () => ({
14
+ isFile: mockIsFile
15
+ }));
16
+
17
+ jest.unstable_mockModule("../../src/CLI/ProcessConfig/readDirectories.js", () => ({
18
+ readDirectories: mockReadDirectories
19
+ }));
20
+
21
+ jest.unstable_mockModule("node:fs", () => ({
22
+ readFileSync: mockReadFileSync
23
+ }));
24
+
25
+ // Now import the modules that depend on the mocked modules
26
+ const { loadStoryFormat } = await import("../../src/CLI/ProcessConfig/loadStoryFormat.js");
11
27
 
12
28
  describe("loadStoryFormat", () => {
13
29
  afterEach(() => {
@@ -15,7 +31,7 @@ describe("loadStoryFormat", () => {
15
31
  });
16
32
 
17
33
  it("should throw an error if the story-formats directory does not exist", () => {
18
- isDirectory.mockReturnValueOnce(false);
34
+ mockIsDirectory.mockReturnValueOnce(false);
19
35
 
20
36
  expect(() => loadStoryFormat("Harlowe", "3.2.0")).toThrow(
21
37
  "Error: story-formats directory does not exist. Consider running 'npx sfa-get' to download the latest story formats."
@@ -23,7 +39,7 @@ describe("loadStoryFormat", () => {
23
39
  });
24
40
 
25
41
  it("should throw an error if the named story format directory does not exist", () => {
26
- isDirectory.mockReturnValueOnce(true).mockReturnValueOnce(false);
42
+ mockIsDirectory.mockReturnValueOnce(true).mockReturnValueOnce(false);
27
43
 
28
44
  expect(() => loadStoryFormat("Harlowe", "3.2.0")).toThrow(
29
45
  "Error: story format Harlowe does not exist in the story-formats directory."
@@ -31,7 +47,7 @@ describe("loadStoryFormat", () => {
31
47
  });
32
48
 
33
49
  it("should throw an error if the version directory does not exist", () => {
34
- isDirectory.mockReturnValueOnce(true).mockReturnValueOnce(true).mockReturnValueOnce(false);
50
+ mockIsDirectory.mockReturnValueOnce(true).mockReturnValueOnce(true).mockReturnValueOnce(false);
35
51
 
36
52
  expect(() => loadStoryFormat("Harlowe", "3.2.0")).toThrow(
37
53
  "Error: story format Harlowe version 3.2.0 does not exist in the story-formats directory."
@@ -39,8 +55,8 @@ describe("loadStoryFormat", () => {
39
55
  });
40
56
 
41
57
  it("should throw an error if the format.js file does not exist in the version directory", () => {
42
- isDirectory.mockReturnValueOnce(true).mockReturnValueOnce(true).mockReturnValueOnce(true);
43
- isFile.mockReturnValueOnce(false);
58
+ mockIsDirectory.mockReturnValueOnce(true).mockReturnValueOnce(true).mockReturnValueOnce(true);
59
+ mockIsFile.mockReturnValueOnce(false);
44
60
 
45
61
  expect(() => loadStoryFormat("Harlowe", "3.2.0")).toThrow(
46
62
  "Error: story format Harlowe version 3.2.0 does not have a format.js file."
@@ -48,29 +64,29 @@ describe("loadStoryFormat", () => {
48
64
  });
49
65
 
50
66
  it("should return the contents of the format.js file if all checks pass", () => {
51
- isDirectory.mockReturnValueOnce(true).mockReturnValueOnce(true).mockReturnValueOnce(true);
52
- isFile.mockReturnValueOnce(true);
53
- readFileSync.mockReturnValueOnce("format.js content");
67
+ mockIsDirectory.mockReturnValueOnce(true).mockReturnValueOnce(true).mockReturnValueOnce(true);
68
+ mockIsFile.mockReturnValueOnce(true);
69
+ mockReadFileSync.mockReturnValueOnce("format.js content");
54
70
 
55
71
  const result = loadStoryFormat("Harlowe", "3.2.0");
56
72
  expect(result).toBe("format.js content");
57
73
  });
58
74
 
59
75
  it("should handle 'latest' version and return the contents of the format.js file", () => {
60
- isDirectory.mockReturnValueOnce(true).mockReturnValueOnce(true);
61
- isFile.mockReturnValueOnce(false).mockReturnValueOnce(true);
62
- readDirectories.mockReturnValueOnce(["3.2.0", "3.1.0"]);
63
- readFileSync.mockReturnValueOnce("latest format.js content");
76
+ mockIsDirectory.mockReturnValueOnce(true).mockReturnValueOnce(true);
77
+ mockIsFile.mockReturnValueOnce(false).mockReturnValueOnce(true);
78
+ mockReadDirectories.mockReturnValueOnce(["3.2.0", "3.1.0"]);
79
+ mockReadFileSync.mockReturnValueOnce("latest format.js content");
64
80
 
65
81
  const result = loadStoryFormat("Harlowe", "latest");
66
82
  expect(result).toBe("latest format.js content");
67
- expect(readDirectories).toHaveBeenCalledWith("story-formats/Harlowe");
83
+ expect(mockReadDirectories).toHaveBeenCalledWith("story-formats/Harlowe");
68
84
  });
69
85
 
70
86
  it("should throw an error if 'latest' version has no format.js file", () => {
71
- isDirectory.mockReturnValueOnce(true).mockReturnValueOnce(true);
72
- isFile.mockReturnValueOnce(false).mockReturnValueOnce(false);
73
- readDirectories.mockReturnValueOnce(["3.2.0", "3.1.0"]);
87
+ mockIsDirectory.mockReturnValueOnce(true).mockReturnValueOnce(true);
88
+ mockIsFile.mockReturnValueOnce(false).mockReturnValueOnce(false);
89
+ mockReadDirectories.mockReturnValueOnce(["3.2.0", "3.1.0"]);
74
90
 
75
91
  expect(() => loadStoryFormat("Harlowe", "latest")).toThrow(
76
92
  "Error: story format Harlowe version latest does not have a format.js file."
@@ -78,20 +94,20 @@ describe("loadStoryFormat", () => {
78
94
  });
79
95
 
80
96
  it("should read format.js file from the story format directory if it exists", () => {
81
- isDirectory.mockReturnValueOnce(true).mockReturnValueOnce(true);
82
- isFile.mockReturnValueOnce(true);
83
- readDirectories.mockReturnValueOnce([]);
84
- readFileSync.mockReturnValueOnce("latest format.js content");
97
+ mockIsDirectory.mockReturnValueOnce(true).mockReturnValueOnce(true);
98
+ mockIsFile.mockReturnValueOnce(true);
99
+ mockReadDirectories.mockReturnValueOnce([]);
100
+ mockReadFileSync.mockReturnValueOnce("latest format.js content");
85
101
 
86
102
  const result = loadStoryFormat("Harlowe", "latest");
87
103
  expect(result).toBe("latest format.js content");
88
- expect(readFileSync).toHaveBeenCalledWith("story-formats/Harlowe/format.js", "utf-8");
104
+ expect(mockReadFileSync).toHaveBeenCalledWith("story-formats/Harlowe/format.js", "utf-8");
89
105
  });
90
106
 
91
107
  it("should throw an error if the story format version is not 'latest' and version directories do not exist", () => {
92
- isDirectory.mockReturnValueOnce(true).mockReturnValueOnce(true);
93
- isFile.mockReturnValueOnce(false);
94
- readDirectories.mockReturnValueOnce([]);
108
+ mockIsDirectory.mockReturnValueOnce(true).mockReturnValueOnce(true);
109
+ mockIsFile.mockReturnValueOnce(false);
110
+ mockReadDirectories.mockReturnValueOnce([]);
95
111
 
96
112
  expect(() => loadStoryFormat("Harlowe", "latest")).toThrow(
97
113
  `Error: story format Harlowe does not have any version directories.`
@@ -1,9 +1,19 @@
1
- import { readDirectories } from '../../src/CLI/ProcessConfig/readDirectories.js';
2
- import { readdirSync } from 'node:fs';
3
- import { isDirectory } from '../../src/CLI/isDirectory.js';
1
+ import {jest} from '@jest/globals';
4
2
 
5
- jest.mock('node:fs');
6
- jest.mock('../../src/CLI/isDirectory.js');
3
+ // Mock the fs module and isDirectory before importing anything that uses them
4
+ const mockReaddirSync = jest.fn();
5
+ const mockIsDirectory = jest.fn();
6
+
7
+ jest.unstable_mockModule('node:fs', () => ({
8
+ readdirSync: mockReaddirSync
9
+ }));
10
+
11
+ jest.unstable_mockModule('../../src/CLI/isDirectory.js', () => ({
12
+ isDirectory: mockIsDirectory
13
+ }));
14
+
15
+ // Now import the modules that depend on the mocked modules
16
+ const { readDirectories } = await import('../../src/CLI/ProcessConfig/readDirectories.js');
7
17
 
8
18
  describe('readDirectories', () => {
9
19
  afterEach(() => {
@@ -12,7 +22,7 @@ describe('readDirectories', () => {
12
22
 
13
23
  it('should return an empty array and log an error if the directory does not exist', () => {
14
24
  const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
15
- isDirectory.mockReturnValue(false);
25
+ mockIsDirectory.mockReturnValue(false);
16
26
 
17
27
  const result = readDirectories('/nonexistent');
18
28
 
@@ -23,8 +33,8 @@ describe('readDirectories', () => {
23
33
 
24
34
  it('should return an empty array and log an error if readdirSync throws an error', () => {
25
35
  const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
26
- isDirectory.mockReturnValue(true);
27
- readdirSync.mockImplementation(() => {
36
+ mockIsDirectory.mockReturnValue(true);
37
+ mockReaddirSync.mockImplementation(() => {
28
38
  throw new Error('Permission denied');
29
39
  });
30
40
 
@@ -36,8 +46,8 @@ describe('readDirectories', () => {
36
46
  });
37
47
 
38
48
  it('should return an empty array if the directory is empty', () => {
39
- isDirectory.mockReturnValue(true);
40
- readdirSync.mockReturnValue([]);
49
+ mockIsDirectory.mockReturnValue(true);
50
+ mockReaddirSync.mockReturnValue([]);
41
51
 
42
52
  const result = readDirectories('/empty');
43
53
 
@@ -45,10 +55,10 @@ describe('readDirectories', () => {
45
55
  });
46
56
 
47
57
  it('should return an array of directories', () => {
48
- isDirectory.mockReturnValue(true);
49
- readdirSync.mockReturnValue(['dir1', 'file1', 'dir2']);
58
+ mockIsDirectory.mockReturnValue(true);
59
+ mockReaddirSync.mockReturnValue(['dir1', 'file1', 'dir2']);
50
60
 
51
- isDirectory.mockImplementation((path) => {
61
+ mockIsDirectory.mockImplementation((path) => {
52
62
  return path === '/test/dir1' || path === '/test/dir2';
53
63
  });
54
64
 
@@ -58,8 +68,8 @@ describe('readDirectories', () => {
58
68
  });
59
69
 
60
70
  it('should return an empty array if the result is not an array', () => {
61
- isDirectory.mockReturnValue(true);
62
- readdirSync.mockReturnValue('not an array');
71
+ mockIsDirectory.mockReturnValue(true);
72
+ mockReaddirSync.mockReturnValue('not an array');
63
73
 
64
74
  const result = readDirectories('/test');
65
75
 
@@ -1,3 +1,4 @@
1
+ import {jest} from '@jest/globals';
1
2
  import { Story, creatorName, creatorVersion } from '../../src/Story.js';
2
3
  import Passage from '../../src/Passage.js';
3
4
  import { parse as parseTwee } from '../../src/Twee/parse.js';
@@ -1,3 +1,4 @@
1
+ import {jest} from '@jest/globals';
1
2
  import { parse as parseStoryFormat } from '../../src/StoryFormat/parse.js';
2
3
 
3
4
  describe('StoryFormat', () => {