extwee 2.3.3 → 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.
@@ -0,0 +1,105 @@
1
+ body {
2
+ background-color: #f8f9fa;
3
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
4
+ }
5
+
6
+ .demo-container {
7
+ max-width: 1200px;
8
+ margin: 0 auto;
9
+ padding: 20px;
10
+ }
11
+
12
+ .demo-header {
13
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
14
+ color: white;
15
+ padding: 40px 20px;
16
+ border-radius: 10px;
17
+ margin-bottom: 30px;
18
+ text-align: center;
19
+ }
20
+
21
+ .demo-section {
22
+ background: white;
23
+ border-radius: 10px;
24
+ padding: 30px;
25
+ margin-bottom: 20px;
26
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
27
+ }
28
+
29
+ .form-control, .form-select {
30
+ border-radius: 8px;
31
+ border: 2px solid #e9ecef;
32
+ transition: border-color 0.3s ease;
33
+ }
34
+
35
+ .form-control:focus, .form-select:focus {
36
+ border-color: #667eea;
37
+ box-shadow: 0 0 0 0.2rem rgba(102, 126, 234, 0.25);
38
+ }
39
+
40
+ .btn-primary {
41
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
42
+ border: none;
43
+ border-radius: 8px;
44
+ padding: 12px 30px;
45
+ font-weight: 600;
46
+ transition: all 0.3s ease;
47
+ }
48
+
49
+ .btn-primary:hover {
50
+ transform: translateY(-2px);
51
+ box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
52
+ }
53
+
54
+ .output-container {
55
+ background-color: #f8f9fa;
56
+ border: 2px solid #e9ecef;
57
+ border-radius: 8px;
58
+ padding: 20px;
59
+ margin-top: 20px;
60
+ min-height: 200px;
61
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
62
+ font-size: 14px;
63
+ white-space: pre-wrap;
64
+ overflow-x: auto;
65
+ }
66
+
67
+ .loading {
68
+ text-align: center;
69
+ color: #6c757d;
70
+ font-style: italic;
71
+ }
72
+
73
+ .error {
74
+ color: #dc3545;
75
+ background-color: #f8d7da;
76
+ border: 1px solid #f5c6cb;
77
+ border-radius: 5px;
78
+ padding: 10px;
79
+ margin-top: 10px;
80
+ }
81
+
82
+ .success {
83
+ color: #155724;
84
+ background-color: #d4edda;
85
+ border: 1px solid #c3e6cb;
86
+ border-radius: 5px;
87
+ padding: 10px;
88
+ margin-top: 10px;
89
+ }
90
+
91
+ .example-twee {
92
+ background-color: #f1f3f4;
93
+ border-left: 4px solid #667eea;
94
+ padding: 15px;
95
+ margin: 15px 0;
96
+ border-radius: 0 8px 8px 0;
97
+ }
98
+
99
+ .format-info {
100
+ background-color: #e7f3ff;
101
+ border: 1px solid #b8daff;
102
+ border-radius: 8px;
103
+ padding: 15px;
104
+ margin-top: 15px;
105
+ }
@@ -0,0 +1,359 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Extwee Story Format Compiler Demo</title>
7
+
8
+ <!-- Bootstrap CSS for styling -->
9
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
10
+
11
+ <!-- Custom CSS -->
12
+ <link href="./index.css" rel="stylesheet">
13
+ </head>
14
+ <body>
15
+ <div class="demo-container">
16
+ <!-- Header -->
17
+ <div class="demo-header">
18
+ <h1 class="mb-3">Example Extwee Story Format Compiler</h1>
19
+ <p class="lead mb-0">Compile Twee code with different Twine story formats</p>
20
+ </div>
21
+
22
+ <!-- Instructions -->
23
+ <div class="demo-section">
24
+ <h3>📝 How to Use</h3>
25
+ <ol>
26
+ <li><strong>Select a Story Format:</strong> Choose from Harlowe, SugarCube, Snowman, or Chapbook</li>
27
+ <li><strong>Enter Twee Code:</strong> Write or paste your Twee story code in the text area</li>
28
+ <li><strong>Compile:</strong> Click the "Compile Story" button to generate the HTML output</li>
29
+ </ol>
30
+
31
+ <div class="example-twee">
32
+ <strong>Example Twee Code:</strong><br>
33
+ <code>:: Start<br>
34
+ This is the beginning of your story.<br>
35
+ <br>
36
+ [[Continue to the next passage->Next]]<br>
37
+ <br>
38
+ :: Next<br>
39
+ This is the second passage of your story.<br>
40
+ <br>
41
+ The End.
42
+ </code>
43
+ </div>
44
+ <div>
45
+ <p>Similar to Twine, this page will automatically assign an IFID to your story.</p>
46
+ </div>
47
+ </div>
48
+
49
+ <!-- Main Demo Interface -->
50
+ <div class="demo-section">
51
+ <div class="row">
52
+ <div class="col-md-4 mb-3">
53
+ <label for="storyFormat" class="form-label"><strong>Story Format</strong></label>
54
+ <select id="storyFormat" class="form-select">
55
+ <option value="">Select a story format...</option>
56
+ <option value="harlowe" data-version="3.3.9">Harlowe (3.3.9)</option>
57
+ <option value="sugarcube" data-version="2.37.3">SugarCube (2.37.3)</option>
58
+ <option value="snowman" data-version="2.0.2">Snowman (2.0.2)</option>
59
+ <option value="chapbook" data-version="2.3.0">Chapbook (2.3.0)</option>
60
+ </select>
61
+ </div>
62
+
63
+ <div class="col-md-8 mb-3">
64
+ <div class="d-flex justify-content-between align-items-center">
65
+ <label for="tweeCode" class="form-label"><strong>Twee Code</strong></label>
66
+ <button id="loadExample" class="btn btn-sm btn-outline-secondary">Load Example</button>
67
+ </div>
68
+ <textarea id="tweeCode" class="form-control" rows="15"
69
+ placeholder="Enter your Twee code here..."></textarea>
70
+ </div>
71
+ </div>
72
+
73
+ <div class="row">
74
+ <div class="col-12 text-center">
75
+ <button id="compileBtn" class="btn btn-primary btn-lg" disabled>
76
+ <span id="compileSpinner" class="spinner-border spinner-border-sm me-2" style="display: none;"></span>
77
+ <span id="compileBtnText">Compile Story</span>
78
+ </button>
79
+ </div>
80
+ </div>
81
+ </div>
82
+
83
+ <!-- Output Section -->
84
+ <div class="demo-section">
85
+ <h4>📄 Compiled Output</h4>
86
+ <div id="outputContainer" class="output-container">
87
+ <div class="loading">Select a story format and enter Twee code, then click "Compile Story" to see the output here.</div>
88
+ </div>
89
+
90
+ <div class="row mt-3">
91
+ <div class="col-6">
92
+ <button id="downloadBtn" class="btn btn-success w-100" style="display: none;">
93
+ 📥 Download HTML File
94
+ </button>
95
+ </div>
96
+ <div class="col-6">
97
+ <button id="previewBtn" class="btn btn-info w-100" style="display: none;">
98
+ 👁️ Preview in New Tab
99
+ </button>
100
+ </div>
101
+ </div>
102
+ </div>
103
+
104
+ <!-- Footer -->
105
+ <div class="demo-section">
106
+ <div class="row">
107
+ <div class="col-md-12">
108
+ <h5>About This Demo</h5>
109
+ <p>This demo uses the <strong>Extwee</strong> web build to compile Twee code with story formats loaded dynamically from the <a href="https://github.com/videlais/story-formats-archive" target="_blank">Story Formats Archive</a>.</p>
110
+ </div>
111
+ </div>
112
+ </div>
113
+ </div>
114
+
115
+ <!-- Load Dependencies -->
116
+ <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
117
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
118
+
119
+ <!-- Load Local Extwee build -->
120
+ <script src="./extwee.core.min.js"></script>
121
+
122
+ <script>
123
+ $(document).ready(function() {
124
+ let storyFormats = {};
125
+ let currentCompiledHTML = '';
126
+
127
+ // Load story formats index
128
+ async function loadStoryFormatsIndex() {
129
+ try {
130
+ const response = await fetch('https://raw.githubusercontent.com/videlais/story-formats-archive/docs/official/index.json');
131
+ // Convert to JSON.
132
+ const data = await response.json();
133
+ // Use Twine 2 formats only.
134
+ storyFormats = data.twine2;
135
+ // Show versions on console
136
+ console.log('Loaded story formats index:', storyFormats);
137
+
138
+ } catch (error) {
139
+ console.error('Failed to load story formats index:', error);
140
+ showError('Failed to load story formats. Please check your internet connection.');
141
+ }
142
+ }
143
+
144
+ // Update format info when selection changes
145
+ $('#storyFormat').on('change', function() {
146
+ const selectedFormat = $(this).val();
147
+ const $compileBtn = $('#compileBtn');
148
+ const $formatInfo = $('#formatInfo');
149
+
150
+ if (selectedFormat) {
151
+ $compileBtn.prop('disabled', false);
152
+ $formatInfo.show();
153
+ } else {
154
+ $compileBtn.prop('disabled', true);
155
+ $formatInfo.hide();
156
+ }
157
+ });
158
+
159
+ // Load example code
160
+ $('#loadExample').on('click', function() {
161
+ const exampleCode = `:: Start
162
+ Welcome to your interactive story!
163
+
164
+ You find yourself at a crossroads in a mysterious forest.
165
+
166
+ [[Take the left path->LeftPath]]
167
+ [[Take the right path->RightPath]]
168
+
169
+ :: LeftPath
170
+ You venture down the left path and discover a hidden cottage.
171
+
172
+ The door creaks open as you approach...
173
+
174
+ [[Enter the cottage->Cottage]]
175
+ [[Return to the crossroads->Start]]
176
+
177
+ :: RightPath
178
+ The right path leads to a sparkling stream.
179
+
180
+ The water is crystal clear and you can see fish swimming below.
181
+
182
+ [[Follow the stream->Stream]]
183
+ [[Return to the crossroads->Start]]
184
+
185
+ :: Cottage
186
+ Inside the cottage, you find an old book on a dusty table.
187
+
188
+ As you open it, magical words begin to glow on the pages...
189
+
190
+ *The End*
191
+
192
+ :: Stream
193
+ You follow the stream until you reach a beautiful waterfall.
194
+
195
+ Behind the waterfall, you discover a secret cave filled with treasure!
196
+
197
+ *The End*`;
198
+
199
+ $('#tweeCode').val(exampleCode);
200
+ });
201
+
202
+ // Show error message
203
+
204
+ // Escape HTML helper to prevent XSS
205
+ function escapeHtml(str) {
206
+ return String(str)
207
+ .replace(/&/g, "&amp;")
208
+ .replace(/</g, "&lt;")
209
+ .replace(/>/g, "&gt;")
210
+ .replace(/"/g, "&quot;")
211
+ .replace(/'/g, "&#39;");
212
+ }
213
+ function showError(message) {
214
+ // Escape the error message to prevent XSS
215
+ $('#outputContainer').html(`<div class="error">❌ Error: ${escapeHtml(message)}</div>`);
216
+ }
217
+
218
+ // Show success message
219
+ function showSuccess(message) {
220
+ $('#outputContainer').html(`<div class="success">✅ ${message}</div>`);
221
+ }
222
+
223
+ // Compile story
224
+ $('#compileBtn').on('click', async function() {
225
+ const selectedFormat = $('#storyFormat').val();
226
+ const formatVersion = $('#storyFormat option:selected').data('version');
227
+ let tweeCode = $('#tweeCode').val().trim();
228
+
229
+ // Check if the input contains the "StoryData" passage
230
+ const hasStoryData = /::\s*StoryData/i.test(tweeCode);
231
+ // If it doesn't, we will add a default one
232
+ // and generate a new IFID
233
+ if (hasStoryData == false) {
234
+
235
+ const ifid = Extwee.generateIFID();
236
+ const storyDataPassage = `:: StoryData
237
+ {"ifid": "${ifid}"}`;
238
+ // Append to the start of the Twee code
239
+ tweeCode = storyDataPassage + '\n\n' + tweeCode;
240
+ console.log('Added StoryData passage with IFID:', ifid);
241
+ }
242
+
243
+ if (!selectedFormat) {
244
+ showError('Please select a story format.');
245
+ return;
246
+ }
247
+
248
+ if (!tweeCode) {
249
+ showError('Please enter some Twee code.');
250
+ return;
251
+ }
252
+
253
+ // Show loading state
254
+ const $btn = $(this);
255
+ const $spinner = $('#compileSpinner');
256
+ const $btnText = $('#compileBtnText');
257
+
258
+ $btn.prop('disabled', true);
259
+ $spinner.show();
260
+ $btnText.text('Compiling...');
261
+ $('#outputContainer').html('<div class="loading">🔄 Loading story format and compiling...</div>');
262
+
263
+ try {
264
+ // Fetch the latest version of the selected format
265
+ const formatData = storyFormats[selectedFormat];
266
+ let formatUrl = `https://raw.githubusercontent.com/videlais/story-formats-archive/docs/official/twine2/${selectedFormat}/${formatVersion}/format.js`;
267
+
268
+
269
+ console.log('Fetching format from:', formatUrl);
270
+
271
+ // Fetch the story format
272
+ const formatResponse = await fetch(formatUrl);
273
+ if (!formatResponse.ok) {
274
+ throw new Error(`Failed to fetch story format: ${formatResponse.status}`);
275
+ }
276
+
277
+ const formatCode = await formatResponse.text();
278
+ console.log('Story format loaded, size:', formatCode.length);
279
+
280
+ // Parse the story format
281
+ const storyFormat = Extwee.parseStoryFormat(formatCode);
282
+ console.log('Story format parsed:', storyFormat.name, storyFormat.version);
283
+
284
+ // Parse the Twee code
285
+ const story = Extwee.parseTwee(tweeCode);
286
+ console.log('Story parsed, passages:', story.passages.length);
287
+
288
+ // Set story format info
289
+ story.format = storyFormat.name;
290
+ story.formatVersion = storyFormat.version;
291
+
292
+ // Compile to HTML
293
+ const compiledHTML = Extwee.compileTwine2HTML(story, storyFormat);
294
+ currentCompiledHTML = compiledHTML;
295
+
296
+ // Show the compiled output (truncated for display)
297
+ const displayHTML = compiledHTML.length > 2000
298
+ ? compiledHTML.substring(0, 2000) + '\n\n... (output truncated, full HTML available for download) ...'
299
+ : compiledHTML;
300
+
301
+ $('#outputContainer').html(`<div class="success">✅ Story compiled successfully!</div><pre>${escapeHtml(displayHTML)}</pre>`);
302
+
303
+ // Show download and preview buttons
304
+ $('#downloadBtn, #previewBtn').show();
305
+
306
+ } catch (error) {
307
+ console.error('Compilation error:', error);
308
+ showError(error.message || 'An unexpected error occurred during compilation.');
309
+ } finally {
310
+ // Reset button state
311
+ $btn.prop('disabled', false);
312
+ $spinner.hide();
313
+ $btnText.text('Compile Story');
314
+ }
315
+ });
316
+
317
+ // Download compiled HTML
318
+ $('#downloadBtn').on('click', function() {
319
+ if (!currentCompiledHTML) {
320
+ showError('No compiled HTML available for download.');
321
+ return;
322
+ }
323
+
324
+ const blob = new Blob([currentCompiledHTML], { type: 'text/html' });
325
+ const url = URL.createObjectURL(blob);
326
+ const a = document.createElement('a');
327
+ a.href = url;
328
+ a.download = 'compiled-story.html';
329
+ document.body.appendChild(a);
330
+ a.click();
331
+ document.body.removeChild(a);
332
+ URL.revokeObjectURL(url);
333
+ });
334
+
335
+ // Preview compiled HTML
336
+ $('#previewBtn').on('click', function() {
337
+ if (!currentCompiledHTML) {
338
+ showError('No compiled HTML available for preview.');
339
+ return;
340
+ }
341
+
342
+ const previewWindow = window.open('', '_blank');
343
+ previewWindow.document.write(currentCompiledHTML);
344
+ previewWindow.document.close();
345
+ });
346
+
347
+ // Utility function to escape HTML
348
+ function escapeHtml(text) {
349
+ const div = document.createElement('div');
350
+ div.textContent = text;
351
+ return div.innerHTML;
352
+ }
353
+
354
+ // Initialize
355
+ loadStoryFormatsIndex();
356
+ });
357
+ </script>
358
+ </body>
359
+ </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "extwee",
3
- "version": "2.3.3",
3
+ "version": "2.3.4",
4
4
  "description": "A story compiler tool using Twine-compatible formats",
5
5
  "author": "Dan Cox",
6
6
  "main": "index.js",
@@ -14,7 +14,8 @@
14
14
  "build:web": "webpack",
15
15
  "analyze:web": "webpack-bundle-analyzer build/extwee.web.min.js",
16
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 build:web && npm run gen-types"
17
+ "copy:build": "cp build/*.js docs/build",
18
+ "all": "npm run lint && npm run lint:test && npm run test && npm run build:web && npm run gen-types && npm run copy:build"
18
19
  },
19
20
  "keywords": [
20
21
  "twine",
@@ -24,37 +25,37 @@
24
25
  ],
25
26
  "license": "MIT",
26
27
  "dependencies": {
27
- "commander": "^14.0.0",
28
+ "commander": "^14.0.1",
28
29
  "graphemer": "^1.4.0",
29
30
  "html-entities": "^2.6.0",
30
31
  "node-html-parser": "^7.0.1",
31
32
  "pickleparser": "^0.2.1",
32
33
  "semver": "^7.7.2",
33
34
  "shelljs": "^0.10.0",
34
- "uuid": "^12.0.0"
35
+ "uuid": "^13.0.0"
35
36
  },
36
37
  "devDependencies": {
37
38
  "@babel/cli": "^7.28.3",
38
39
  "@babel/core": "^7.28.4",
39
40
  "@babel/preset-env": "^7.28.3",
40
- "@eslint/js": "^9.35.0",
41
- "@inquirer/prompts": "^7.8.4",
42
- "@types/node": "^24.3.1",
41
+ "@eslint/js": "^9.36.0",
42
+ "@inquirer/prompts": "^7.8.6",
43
+ "@types/node": "^24.6.1",
43
44
  "@types/semver": "^7.7.1",
44
- "@types/uuid": "^10.0.0",
45
+ "@types/uuid": "^11.0.0",
45
46
  "babel-loader": "^10.0.0",
46
47
  "clean-jsdoc-theme": "^4.3.0",
47
48
  "core-js": "^3.45.1",
48
- "eslint": "^9.35.0",
49
+ "eslint": "^9.36.0",
49
50
  "eslint-plugin-jest": "^29.0.1",
50
- "eslint-plugin-jsdoc": "^54.5.0",
51
- "globals": "^16.3.0",
52
- "jest": "^30.1.3",
53
- "jest-environment-jsdom": "^30.1.2",
51
+ "eslint-plugin-jsdoc": "^60.7.0",
52
+ "globals": "^16.4.0",
53
+ "jest": "^30.2.0",
54
+ "jest-environment-jsdom": "^30.2.0",
54
55
  "regenerator-runtime": "^0.14.1",
55
- "typescript": "^5.9.2",
56
- "typescript-eslint": "^8.42.0",
57
- "webpack": "^5.101.3",
56
+ "typescript": "^5.9.3",
57
+ "typescript-eslint": "^8.45.0",
58
+ "webpack": "^5.102.0",
58
59
  "webpack-bundle-analyzer": "^4.10.2",
59
60
  "webpack-cli": "^6.0.1"
60
61
  },
package/src/Story.js CHANGED
@@ -7,7 +7,7 @@ import { encode } from 'html-entities';
7
7
  const creatorName = 'extwee';
8
8
 
9
9
  // Set the creator version.
10
- const creatorVersion = '2.3.3';
10
+ const creatorVersion = '2.3.4';
11
11
 
12
12
  /**
13
13
  * Story class.
@@ -101,11 +101,17 @@ class LightweightTwine2Parser {
101
101
  parseAttributes(elementHtml) {
102
102
  const attributes = {};
103
103
 
104
+ // Extract just the opening tag to avoid getting attributes from nested elements
105
+ const openingTagMatch = elementHtml.match(/^<[^>]*>/);
106
+ if (!openingTagMatch) return attributes;
107
+
108
+ const openingTag = openingTagMatch[0];
109
+
104
110
  // Common attribute patterns
105
111
  const attributeRegex = /(\w+(?:-\w+)*)=["']([^"']*)["']/g;
106
112
  let match;
107
113
 
108
- while ((match = attributeRegex.exec(elementHtml)) !== null) {
114
+ while ((match = attributeRegex.exec(openingTag)) !== null) {
109
115
  attributes[match[1]] = match[2];
110
116
  }
111
117
 
@@ -10,7 +10,7 @@ import Passage from '../Passage.js';
10
10
  import StoryFormat from '../StoryFormat.js';
11
11
 
12
12
  // Core functionality - most commonly used
13
- window.Extwee = {
13
+ const Extwee = {
14
14
  // Core parsers (immediately available)
15
15
  parseTwee,
16
16
  parseJSON,
@@ -27,5 +27,25 @@ window.Extwee = {
27
27
  StoryFormat,
28
28
 
29
29
  // Version info
30
- version: '2.3.2'
30
+ version: '2.3.3'
31
31
  };
32
+
33
+ // Export individual functions for ES6 module usage
34
+ export { parseTwee, parseJSON, parseStoryFormat, parseTwine2HTML, compileTwine2HTML, generateIFID, Story, Passage, StoryFormat };
35
+
36
+ // Export default for webpack UMD build
37
+ export default Extwee;
38
+
39
+ // For direct ES6 module usage, also assign to global object
40
+ // Use globalThis for cross-environment compatibility (browser, Node.js, Web Workers)
41
+ const globalObject = (function() {
42
+ if (typeof globalThis !== 'undefined') return globalThis;
43
+ if (typeof window !== 'undefined') return window;
44
+ if (typeof global !== 'undefined') return global;
45
+ if (typeof self !== 'undefined') return self;
46
+ return null;
47
+ })();
48
+
49
+ if (globalObject) {
50
+ globalObject.Extwee = Extwee;
51
+ }
@@ -2,14 +2,34 @@
2
2
  import { parse as parseTwine1HTML } from '../Twine1HTML/parse-web.js';
3
3
  import { compile as compileTwine1HTML } from '../Twine1HTML/compile.js';
4
4
 
5
- // Export for use as a separate module
5
+ // Create UMD-compatible export object
6
+ const Extwee = {
7
+ parseTwine1HTML,
8
+ compileTwine1HTML,
9
+ parse: parseTwine1HTML, // For module consistency
10
+ compile: compileTwine1HTML // For module consistency
11
+ };
12
+
13
+ // Export for webpack UMD build
14
+ export default Extwee;
15
+
16
+ // Also export individual functions for ES6 module usage
6
17
  export {
7
18
  parseTwine1HTML as parse,
8
19
  compileTwine1HTML as compile
9
20
  };
10
21
 
11
- // Also add to global Extwee if it exists
12
- if (typeof window !== 'undefined' && window.Extwee) {
13
- window.Extwee.parseTwine1HTML = parseTwine1HTML;
14
- window.Extwee.compileTwine1HTML = compileTwine1HTML;
22
+ // Add to global Extwee object for direct usage
23
+ const globalObject = (function() {
24
+ if (typeof globalThis !== 'undefined') return globalThis;
25
+ if (typeof window !== 'undefined') return window;
26
+ if (typeof global !== 'undefined') return global;
27
+ if (typeof self !== 'undefined') return self;
28
+ return null;
29
+ })();
30
+
31
+ if (globalObject) {
32
+ globalObject.Extwee = globalObject.Extwee || {};
33
+ globalObject.Extwee.parseTwine1HTML = parseTwine1HTML;
34
+ globalObject.Extwee.compileTwine1HTML = compileTwine1HTML;
15
35
  }
@@ -2,14 +2,34 @@
2
2
  import { parse as parseTwine2ArchiveHTML } from '../Twine2ArchiveHTML/parse-web.js';
3
3
  import { compile as compileTwine2ArchiveHTML } from '../Twine2ArchiveHTML/compile.js';
4
4
 
5
- // Export for use as a separate module
5
+ // Create UMD-compatible export object
6
+ const Extwee = {
7
+ parseTwine2ArchiveHTML,
8
+ compileTwine2ArchiveHTML,
9
+ parse: parseTwine2ArchiveHTML, // For module consistency
10
+ compile: compileTwine2ArchiveHTML // For module consistency
11
+ };
12
+
13
+ // Export for webpack UMD build
14
+ export default Extwee;
15
+
16
+ // Also export individual functions for ES6 module usage
6
17
  export {
7
18
  parseTwine2ArchiveHTML as parse,
8
19
  compileTwine2ArchiveHTML as compile
9
20
  };
10
21
 
11
- // Also add to global Extwee if it exists
12
- if (typeof window !== 'undefined' && window.Extwee) {
13
- window.Extwee.parseTwine2ArchiveHTML = parseTwine2ArchiveHTML;
14
- window.Extwee.compileTwine2ArchiveHTML = compileTwine2ArchiveHTML;
22
+ // Add to global Extwee object for direct usage
23
+ const globalObject = (function() {
24
+ if (typeof globalThis !== 'undefined') return globalThis;
25
+ if (typeof window !== 'undefined') return window;
26
+ if (typeof global !== 'undefined') return global;
27
+ if (typeof self !== 'undefined') return self;
28
+ return null;
29
+ })();
30
+
31
+ if (globalObject) {
32
+ globalObject.Extwee = globalObject.Extwee || {};
33
+ globalObject.Extwee.parseTwine2ArchiveHTML = parseTwine2ArchiveHTML;
34
+ globalObject.Extwee.compileTwine2ArchiveHTML = compileTwine2ArchiveHTML;
15
35
  }