@rohal12/twee-ts 1.4.0 → 1.6.0
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/dist/bin/twee-ts.js +225 -58
- package/dist/bin/twee-ts.js.map +1 -1
- package/dist/{chunk-76URFKGD.js → chunk-HXL3JC4L.js} +209 -51
- package/dist/chunk-HXL3JC4L.js.map +1 -0
- package/dist/index.cjs +240 -76
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +221 -57
- package/dist/index.js.map +1 -1
- package/dist/plugins/rollup.d.ts +1 -1
- package/dist/plugins/rollup.js +1 -1
- package/dist/plugins/vite.d.ts +1 -1
- package/dist/plugins/vite.js +1 -1
- package/dist/{types-B3qtPxs8.d.ts → types-BbEu2Szm.d.ts} +2 -0
- package/package.json +1 -1
- package/dist/chunk-76URFKGD.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -50,7 +50,7 @@ __export(src_exports, {
|
|
|
50
50
|
module.exports = __toCommonJS(src_exports);
|
|
51
51
|
|
|
52
52
|
// src/compiler.ts
|
|
53
|
-
var
|
|
53
|
+
var import_node_fs7 = require("fs");
|
|
54
54
|
|
|
55
55
|
// src/ifid.ts
|
|
56
56
|
var import_node_crypto = require("crypto");
|
|
@@ -241,7 +241,7 @@ function passageToTwee(p, outMode) {
|
|
|
241
241
|
output += "\n\n";
|
|
242
242
|
return output;
|
|
243
243
|
}
|
|
244
|
-
function passageToPassagedata(p, pid) {
|
|
244
|
+
function passageToPassagedata(p, pid, options) {
|
|
245
245
|
let position;
|
|
246
246
|
let size;
|
|
247
247
|
if (hasMetadataPosition(p)) {
|
|
@@ -258,7 +258,11 @@ function passageToPassagedata(p, pid) {
|
|
|
258
258
|
} else {
|
|
259
259
|
size = "100,100";
|
|
260
260
|
}
|
|
261
|
-
|
|
261
|
+
let attrs = `<tw-passagedata pid="${pid}" name=${quote(fullAttrEscape(p.name))} tags=${quote(attrEscape(p.tags.join(" ")))} position=${quote(attrEscape(position))} size=${quote(attrEscape(size))}`;
|
|
262
|
+
if (options?.sourceInfo && p.source) {
|
|
263
|
+
attrs += ` data-source-file=${quote(attrEscape(p.source.file))} data-source-line="${p.source.line}"`;
|
|
264
|
+
}
|
|
265
|
+
return `${attrs}>${htmlEscape(p.text)}</tw-passagedata>`;
|
|
262
266
|
}
|
|
263
267
|
function passageToTiddler(p, pid, obfuscateRot13 = false) {
|
|
264
268
|
let position;
|
|
@@ -305,8 +309,21 @@ function quote(s) {
|
|
|
305
309
|
}
|
|
306
310
|
|
|
307
311
|
// src/story.ts
|
|
312
|
+
var passageIndex = /* @__PURE__ */ new WeakMap();
|
|
313
|
+
function getIndex(story) {
|
|
314
|
+
let index = passageIndex.get(story);
|
|
315
|
+
if (!index) {
|
|
316
|
+
index = /* @__PURE__ */ new Map();
|
|
317
|
+
for (let i = 0; i < story.passages.length; i++) {
|
|
318
|
+
const passage = story.passages[i];
|
|
319
|
+
if (passage) index.set(passage.name, i);
|
|
320
|
+
}
|
|
321
|
+
passageIndex.set(story, index);
|
|
322
|
+
}
|
|
323
|
+
return index;
|
|
324
|
+
}
|
|
308
325
|
function createStory() {
|
|
309
|
-
|
|
326
|
+
const story = {
|
|
310
327
|
name: "",
|
|
311
328
|
ifid: "",
|
|
312
329
|
passages: [],
|
|
@@ -322,16 +339,17 @@ function createStory() {
|
|
|
322
339
|
zoom: 1
|
|
323
340
|
}
|
|
324
341
|
};
|
|
342
|
+
passageIndex.set(story, /* @__PURE__ */ new Map());
|
|
343
|
+
return story;
|
|
325
344
|
}
|
|
326
345
|
function storyHas(story, name) {
|
|
327
|
-
return story.
|
|
328
|
-
}
|
|
329
|
-
function storyIndex(story, name) {
|
|
330
|
-
return story.passages.findIndex((p) => p.name === name);
|
|
346
|
+
return getIndex(story).has(name);
|
|
331
347
|
}
|
|
332
348
|
function storyAppend(story, p, diagnostics) {
|
|
333
|
-
const
|
|
349
|
+
const index = getIndex(story);
|
|
350
|
+
const i = index.get(p.name) ?? -1;
|
|
334
351
|
if (i === -1) {
|
|
352
|
+
index.set(p.name, story.passages.length);
|
|
335
353
|
story.passages.push(p);
|
|
336
354
|
} else {
|
|
337
355
|
diagnostics.push({
|
|
@@ -342,9 +360,15 @@ function storyAppend(story, p, diagnostics) {
|
|
|
342
360
|
}
|
|
343
361
|
}
|
|
344
362
|
function storyPrepend(story, p, diagnostics) {
|
|
345
|
-
const
|
|
363
|
+
const index = getIndex(story);
|
|
364
|
+
const i = index.get(p.name) ?? -1;
|
|
346
365
|
if (i === -1) {
|
|
347
366
|
story.passages.unshift(p);
|
|
367
|
+
index.clear();
|
|
368
|
+
for (let j = 0; j < story.passages.length; j++) {
|
|
369
|
+
const passage = story.passages[j];
|
|
370
|
+
if (passage) index.set(passage.name, j);
|
|
371
|
+
}
|
|
348
372
|
} else {
|
|
349
373
|
diagnostics.push({
|
|
350
374
|
level: "warning",
|
|
@@ -634,11 +658,15 @@ function watchFilesystem(pathnames, outFilename, callback) {
|
|
|
634
658
|
const watchers = [];
|
|
635
659
|
let buildTimer = null;
|
|
636
660
|
const BUILD_DEBOUNCE = 500;
|
|
637
|
-
|
|
661
|
+
const pendingFiles = /* @__PURE__ */ new Set();
|
|
662
|
+
function scheduleBuild(changedFile) {
|
|
663
|
+
if (changedFile) pendingFiles.add(changedFile);
|
|
638
664
|
if (buildTimer) clearTimeout(buildTimer);
|
|
639
665
|
buildTimer = setTimeout(() => {
|
|
640
666
|
buildTimer = null;
|
|
641
|
-
|
|
667
|
+
const files = pendingFiles.size > 0 ? new Set(pendingFiles) : void 0;
|
|
668
|
+
pendingFiles.clear();
|
|
669
|
+
callback(files);
|
|
642
670
|
}, BUILD_DEBOUNCE);
|
|
643
671
|
}
|
|
644
672
|
for (const pathname of pathnames) {
|
|
@@ -648,7 +676,8 @@ function watchFilesystem(pathnames, outFilename, callback) {
|
|
|
648
676
|
const abs = (0, import_node_path2.resolve)(pathname, filename);
|
|
649
677
|
if (abs === absOutFile) return;
|
|
650
678
|
if (isKnownFileType(filename)) {
|
|
651
|
-
|
|
679
|
+
const rel = (0, import_node_path2.relative)(process.cwd(), abs);
|
|
680
|
+
scheduleBuild(rel || abs);
|
|
652
681
|
}
|
|
653
682
|
});
|
|
654
683
|
watchers.push(watcher);
|
|
@@ -907,6 +936,7 @@ function readFormatSource(format) {
|
|
|
907
936
|
|
|
908
937
|
// src/loader.ts
|
|
909
938
|
var import_node_path5 = require("path");
|
|
939
|
+
var import_node_fs4 = require("fs");
|
|
910
940
|
|
|
911
941
|
// src/lexer.ts
|
|
912
942
|
var EOF = -1;
|
|
@@ -1238,7 +1268,7 @@ function parseTwee(source, options = {}) {
|
|
|
1238
1268
|
if (pCount > 1 && current) {
|
|
1239
1269
|
passages.push(current);
|
|
1240
1270
|
}
|
|
1241
|
-
current = { name: "", tags: [], text: "" };
|
|
1271
|
+
current = { name: "", tags: [], text: "", source: { file: filename, line: item.line } };
|
|
1242
1272
|
break;
|
|
1243
1273
|
case 3 /* Name */: {
|
|
1244
1274
|
if (!current) break;
|
|
@@ -1430,54 +1460,182 @@ function loadInlineSources(story, sources, opts, diagnostics) {
|
|
|
1430
1460
|
}
|
|
1431
1461
|
}
|
|
1432
1462
|
}
|
|
1433
|
-
function
|
|
1463
|
+
function parseTweeFile(filename, opts) {
|
|
1434
1464
|
const source = readUTF8(filename);
|
|
1435
1465
|
const result = parseTwee(source, {
|
|
1436
1466
|
filename,
|
|
1437
1467
|
trim: opts.trim ?? true,
|
|
1438
1468
|
twee2Compat: opts.twee2Compat ?? false
|
|
1439
1469
|
});
|
|
1440
|
-
diagnostics
|
|
1441
|
-
for (const p of result.passages) {
|
|
1442
|
-
storyAdd(story, p, diagnostics);
|
|
1443
|
-
}
|
|
1470
|
+
return { passages: result.passages, diagnostics: [...result.diagnostics] };
|
|
1444
1471
|
}
|
|
1445
|
-
function
|
|
1472
|
+
function parseTaggedFile(tag, filename) {
|
|
1446
1473
|
const source = readUTF8(filename);
|
|
1447
|
-
|
|
1474
|
+
return { passages: [{ name: (0, import_node_path5.basename)(filename), tags: [tag], text: source }], diagnostics: [] };
|
|
1448
1475
|
}
|
|
1449
|
-
function
|
|
1476
|
+
function parseMediaFile(tag, filename) {
|
|
1450
1477
|
const source = readBase64(filename);
|
|
1451
1478
|
const name = baseNameWithoutExt(filename);
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
tags: [tag],
|
|
1457
|
-
text: `data:${mediaTypeFromFilename(filename)};base64,${source}`
|
|
1458
|
-
},
|
|
1459
|
-
diagnostics
|
|
1460
|
-
);
|
|
1479
|
+
return {
|
|
1480
|
+
passages: [{ name, tags: [tag], text: `data:${mediaTypeFromFilename(filename)};base64,${source}` }],
|
|
1481
|
+
diagnostics: []
|
|
1482
|
+
};
|
|
1461
1483
|
}
|
|
1462
|
-
function
|
|
1484
|
+
function parseFontFile(filename) {
|
|
1463
1485
|
const source = readBase64(filename);
|
|
1464
1486
|
const name = (0, import_node_path5.basename)(filename);
|
|
1465
1487
|
const family = baseNameWithoutExt(filename);
|
|
1466
1488
|
const ext = normalizedFileExt(filename);
|
|
1467
1489
|
const mediaType = mediaTypeFromExt(ext);
|
|
1468
1490
|
const hint = fontFormatHint(ext);
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1491
|
+
return {
|
|
1492
|
+
passages: [
|
|
1493
|
+
{
|
|
1494
|
+
name,
|
|
1495
|
+
tags: ["stylesheet"],
|
|
1496
|
+
text: `@font-face {
|
|
1475
1497
|
font-family: "${family}";
|
|
1476
1498
|
src: url("data:${mediaType};base64,${source}") format("${hint}");
|
|
1477
1499
|
}`
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1500
|
+
}
|
|
1501
|
+
],
|
|
1502
|
+
diagnostics: []
|
|
1503
|
+
};
|
|
1504
|
+
}
|
|
1505
|
+
function parseFile(filename, opts) {
|
|
1506
|
+
const ext = normalizedFileExt(filename);
|
|
1507
|
+
switch (ext) {
|
|
1508
|
+
case "tw":
|
|
1509
|
+
case "twee":
|
|
1510
|
+
return parseTweeFile(filename, opts);
|
|
1511
|
+
case "tw2":
|
|
1512
|
+
case "twee2":
|
|
1513
|
+
return parseTweeFile(filename, { ...opts, twee2Compat: true });
|
|
1514
|
+
case "css":
|
|
1515
|
+
return parseTaggedFile("stylesheet", filename);
|
|
1516
|
+
case "js":
|
|
1517
|
+
return parseTaggedFile("script", filename);
|
|
1518
|
+
case "otf":
|
|
1519
|
+
case "ttf":
|
|
1520
|
+
case "woff":
|
|
1521
|
+
case "woff2":
|
|
1522
|
+
return parseFontFile(filename);
|
|
1523
|
+
case "gif":
|
|
1524
|
+
case "jpeg":
|
|
1525
|
+
case "jpg":
|
|
1526
|
+
case "png":
|
|
1527
|
+
case "svg":
|
|
1528
|
+
case "tif":
|
|
1529
|
+
case "tiff":
|
|
1530
|
+
case "webp":
|
|
1531
|
+
return parseMediaFile("Twine.image", filename);
|
|
1532
|
+
case "aac":
|
|
1533
|
+
case "flac":
|
|
1534
|
+
case "m4a":
|
|
1535
|
+
case "mp3":
|
|
1536
|
+
case "oga":
|
|
1537
|
+
case "ogg":
|
|
1538
|
+
case "opus":
|
|
1539
|
+
case "wav":
|
|
1540
|
+
case "wave":
|
|
1541
|
+
case "weba":
|
|
1542
|
+
return parseMediaFile("Twine.audio", filename);
|
|
1543
|
+
case "mp4":
|
|
1544
|
+
case "ogv":
|
|
1545
|
+
case "webm":
|
|
1546
|
+
return parseMediaFile("Twine.video", filename);
|
|
1547
|
+
case "vtt":
|
|
1548
|
+
return parseMediaFile("Twine.vtt", filename);
|
|
1549
|
+
default:
|
|
1550
|
+
return void 0;
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
function loadTwee(story, filename, opts, diagnostics) {
|
|
1554
|
+
const result = parseTweeFile(filename, opts);
|
|
1555
|
+
diagnostics.push(...result.diagnostics);
|
|
1556
|
+
for (const p of result.passages) {
|
|
1557
|
+
storyAdd(story, p, diagnostics);
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
function loadTagged(story, tag, filename, diagnostics) {
|
|
1561
|
+
const result = parseTaggedFile(tag, filename);
|
|
1562
|
+
for (const p of result.passages) {
|
|
1563
|
+
storyAdd(story, p, diagnostics);
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
function loadMedia(story, tag, filename, diagnostics) {
|
|
1567
|
+
const result = parseMediaFile(tag, filename);
|
|
1568
|
+
for (const p of result.passages) {
|
|
1569
|
+
storyAdd(story, p, diagnostics);
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
function loadFont(story, filename, diagnostics) {
|
|
1573
|
+
const result = parseFontFile(filename);
|
|
1574
|
+
for (const p of result.passages) {
|
|
1575
|
+
storyAdd(story, p, diagnostics);
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
function loadSourcesCached(story, filenames, opts, diagnostics, processedFiles, cache, changedFiles) {
|
|
1579
|
+
const currentFiles = /* @__PURE__ */ new Set();
|
|
1580
|
+
for (const filename of filenames) {
|
|
1581
|
+
if (processedFiles.has(filename)) {
|
|
1582
|
+
diagnostics.push({ level: "warning", message: `load ${filename}: Skipping duplicate.` });
|
|
1583
|
+
continue;
|
|
1584
|
+
}
|
|
1585
|
+
currentFiles.add(filename);
|
|
1586
|
+
const cached = cache.get(filename);
|
|
1587
|
+
if (changedFiles && cached && !changedFiles.has(filename)) {
|
|
1588
|
+
diagnostics.push(...cached.diagnostics);
|
|
1589
|
+
for (const p of cached.passages) {
|
|
1590
|
+
storyAdd(story, p, diagnostics);
|
|
1591
|
+
}
|
|
1592
|
+
processedFiles.add(filename);
|
|
1593
|
+
continue;
|
|
1594
|
+
}
|
|
1595
|
+
let mtimeMs;
|
|
1596
|
+
try {
|
|
1597
|
+
mtimeMs = (0, import_node_fs4.statSync)(filename).mtimeMs;
|
|
1598
|
+
} catch {
|
|
1599
|
+
continue;
|
|
1600
|
+
}
|
|
1601
|
+
if (cached && cached.mtimeMs === mtimeMs) {
|
|
1602
|
+
diagnostics.push(...cached.diagnostics);
|
|
1603
|
+
for (const p of cached.passages) {
|
|
1604
|
+
storyAdd(story, p, diagnostics);
|
|
1605
|
+
}
|
|
1606
|
+
processedFiles.add(filename);
|
|
1607
|
+
continue;
|
|
1608
|
+
}
|
|
1609
|
+
try {
|
|
1610
|
+
const result = parseFile(filename, opts);
|
|
1611
|
+
if (!result) continue;
|
|
1612
|
+
cache.set(filename, {
|
|
1613
|
+
mtimeMs,
|
|
1614
|
+
passages: result.passages,
|
|
1615
|
+
diagnostics: result.diagnostics
|
|
1616
|
+
});
|
|
1617
|
+
diagnostics.push(...result.diagnostics);
|
|
1618
|
+
for (const p of result.passages) {
|
|
1619
|
+
storyAdd(story, p, diagnostics);
|
|
1620
|
+
}
|
|
1621
|
+
} catch (e) {
|
|
1622
|
+
diagnostics.push({
|
|
1623
|
+
level: "error",
|
|
1624
|
+
message: `load ${filename}: ${e instanceof Error ? e.message : String(e)}`,
|
|
1625
|
+
file: filename
|
|
1626
|
+
});
|
|
1627
|
+
continue;
|
|
1628
|
+
}
|
|
1629
|
+
processedFiles.add(filename);
|
|
1630
|
+
}
|
|
1631
|
+
for (const key of cache.keys()) {
|
|
1632
|
+
if (!currentFiles.has(key)) {
|
|
1633
|
+
cache.delete(key);
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
if (story.name !== "" && !story.passages.some((p) => p.name === "StoryTitle")) {
|
|
1637
|
+
storyPrepend(story, { name: "StoryTitle", tags: [], text: story.name }, diagnostics);
|
|
1638
|
+
}
|
|
1481
1639
|
}
|
|
1482
1640
|
|
|
1483
1641
|
// src/version.ts
|
|
@@ -1485,20 +1643,20 @@ var VERSION = "1.2.0";
|
|
|
1485
1643
|
|
|
1486
1644
|
// src/output-twine2.ts
|
|
1487
1645
|
var CREATOR_NAME = "Twee-ts";
|
|
1488
|
-
function toTwine2Archive(story, startName, diagnostics) {
|
|
1489
|
-
return getTwine2DataChunk(story, startName, diagnostics) + "\n";
|
|
1646
|
+
function toTwine2Archive(story, startName, diagnostics, options) {
|
|
1647
|
+
return getTwine2DataChunk(story, startName, diagnostics, options) + "\n";
|
|
1490
1648
|
}
|
|
1491
|
-
function toTwine2HTML(story, format, startName, diagnostics) {
|
|
1649
|
+
function toTwine2HTML(story, format, startName, diagnostics, options) {
|
|
1492
1650
|
let template = readFormatSource(format);
|
|
1493
1651
|
if (template.includes("{{STORY_NAME}}")) {
|
|
1494
1652
|
template = template.replaceAll("{{STORY_NAME}}", htmlEscape(story.name));
|
|
1495
1653
|
}
|
|
1496
1654
|
if (template.includes("{{STORY_DATA}}")) {
|
|
1497
|
-
template = template.replace("{{STORY_DATA}}", getTwine2DataChunk(story, startName, diagnostics));
|
|
1655
|
+
template = template.replace("{{STORY_DATA}}", getTwine2DataChunk(story, startName, diagnostics, options));
|
|
1498
1656
|
}
|
|
1499
1657
|
return template;
|
|
1500
1658
|
}
|
|
1501
|
-
function getTwine2DataChunk(story, startName, diagnostics) {
|
|
1659
|
+
function getTwine2DataChunk(story, startName, diagnostics, options) {
|
|
1502
1660
|
ensureIFID(story, diagnostics);
|
|
1503
1661
|
const parts = [];
|
|
1504
1662
|
let startID = "";
|
|
@@ -1553,7 +1711,7 @@ function getTwine2DataChunk(story, startName, diagnostics) {
|
|
|
1553
1711
|
if (p.name === "StorySettings" && story.twine1.settings.size === 0) {
|
|
1554
1712
|
continue;
|
|
1555
1713
|
}
|
|
1556
|
-
parts.push(passageToPassagedata(p, pid));
|
|
1714
|
+
parts.push(passageToPassagedata(p, pid, options));
|
|
1557
1715
|
if (startName === p.name) {
|
|
1558
1716
|
startID = String(pid);
|
|
1559
1717
|
}
|
|
@@ -1563,9 +1721,9 @@ function getTwine2DataChunk(story, startName, diagnostics) {
|
|
|
1563
1721
|
for (const [opt, val] of story.twine2.options) {
|
|
1564
1722
|
if (val) opts.push(opt);
|
|
1565
1723
|
}
|
|
1566
|
-
const
|
|
1724
|
+
const optionsStr = opts.join(" ");
|
|
1567
1725
|
const zoom = String(story.twine2.zoom);
|
|
1568
|
-
const wrapper = `<!-- UUID://${htmlCommentSanitize(story.ifid)}// --><tw-storydata name="${attrEscape(story.name)}" startnode="${attrEscape(startID)}" creator="${attrEscape(CREATOR_NAME)}" creator-version="${attrEscape(VERSION)}" ifid="${attrEscape(story.ifid)}" zoom="${attrEscape(zoom)}" format="${attrEscape(story.twine2.format)}" format-version="${attrEscape(story.twine2.formatVersion)}" options="${attrEscape(
|
|
1726
|
+
const wrapper = `<!-- UUID://${htmlCommentSanitize(story.ifid)}// --><tw-storydata name="${attrEscape(story.name)}" startnode="${attrEscape(startID)}" creator="${attrEscape(CREATOR_NAME)}" creator-version="${attrEscape(VERSION)}" ifid="${attrEscape(story.ifid)}" zoom="${attrEscape(zoom)}" format="${attrEscape(story.twine2.format)}" format-version="${attrEscape(story.twine2.formatVersion)}" options="${attrEscape(optionsStr)}" tags="${attrEscape(story.twine2.tags)}" hidden>`;
|
|
1569
1727
|
return wrapper + parts.join("") + "</tw-storydata>";
|
|
1570
1728
|
}
|
|
1571
1729
|
function ensureIFID(story, diagnostics) {
|
|
@@ -1587,7 +1745,7 @@ function ensureIFID(story, diagnostics) {
|
|
|
1587
1745
|
}
|
|
1588
1746
|
|
|
1589
1747
|
// src/output-twine1.ts
|
|
1590
|
-
var
|
|
1748
|
+
var import_node_fs5 = require("fs");
|
|
1591
1749
|
var import_node_path6 = require("path");
|
|
1592
1750
|
var CREATOR_NAME2 = "twee-ts";
|
|
1593
1751
|
function toTwine1Archive(story, _startName) {
|
|
@@ -1620,7 +1778,7 @@ function toTwine1HTML(story, format, startName, _diagnostics) {
|
|
|
1620
1778
|
} else {
|
|
1621
1779
|
let footer;
|
|
1622
1780
|
try {
|
|
1623
|
-
footer = (0,
|
|
1781
|
+
footer = (0, import_node_fs5.readFileSync)((0, import_node_path6.join)(formatDir, "footer.html"), "utf-8");
|
|
1624
1782
|
} catch {
|
|
1625
1783
|
footer = "</div>\n</body>\n</html>\n";
|
|
1626
1784
|
}
|
|
@@ -1650,7 +1808,7 @@ function getTwine1PassageChunk(story) {
|
|
|
1650
1808
|
function tryReplaceComponent(template, placeholder, componentPath, required) {
|
|
1651
1809
|
if (!template.includes(placeholder)) return template;
|
|
1652
1810
|
try {
|
|
1653
|
-
let content = (0,
|
|
1811
|
+
let content = (0, import_node_fs5.readFileSync)(componentPath, "utf-8");
|
|
1654
1812
|
if (content.charCodeAt(0) === 65279) content = content.slice(1);
|
|
1655
1813
|
return template.replace(placeholder, content);
|
|
1656
1814
|
} catch (e) {
|
|
@@ -1746,7 +1904,7 @@ function modifyHead(html, modulePaths, headFile, diagnostics) {
|
|
|
1746
1904
|
}
|
|
1747
1905
|
|
|
1748
1906
|
// src/remote-formats.ts
|
|
1749
|
-
var
|
|
1907
|
+
var import_node_fs6 = require("fs");
|
|
1750
1908
|
var import_node_path7 = require("path");
|
|
1751
1909
|
var import_node_os2 = require("os");
|
|
1752
1910
|
var DEFAULT_SFA_INDICES = [
|
|
@@ -1847,9 +2005,9 @@ async function fetchAndCacheFormat(entry, downloadUrl) {
|
|
|
1847
2005
|
}
|
|
1848
2006
|
const cacheDir = getCacheDir();
|
|
1849
2007
|
const formatDir = (0, import_node_path7.join)(cacheDir, entry.name, entry.version);
|
|
1850
|
-
(0,
|
|
2008
|
+
(0, import_node_fs6.mkdirSync)(formatDir, { recursive: true });
|
|
1851
2009
|
const formatPath = (0, import_node_path7.join)(formatDir, "format.js");
|
|
1852
|
-
(0,
|
|
2010
|
+
(0, import_node_fs6.writeFileSync)(formatPath, text, "utf-8");
|
|
1853
2011
|
return {
|
|
1854
2012
|
id,
|
|
1855
2013
|
filename: formatPath,
|
|
@@ -1873,9 +2031,9 @@ async function fetchDirectFormat(url) {
|
|
|
1873
2031
|
const id = makeFormatId(data.name, data.version);
|
|
1874
2032
|
const cacheDir = getCacheDir();
|
|
1875
2033
|
const formatDir = (0, import_node_path7.join)(cacheDir, data.name, data.version);
|
|
1876
|
-
(0,
|
|
2034
|
+
(0, import_node_fs6.mkdirSync)(formatDir, { recursive: true });
|
|
1877
2035
|
const formatPath = (0, import_node_path7.join)(formatDir, "format.js");
|
|
1878
|
-
(0,
|
|
2036
|
+
(0, import_node_fs6.writeFileSync)(formatPath, text, "utf-8");
|
|
1879
2037
|
return {
|
|
1880
2038
|
id,
|
|
1881
2039
|
filename: formatPath,
|
|
@@ -1924,8 +2082,8 @@ async function resolveRemoteFormat(name, version, indices, urls) {
|
|
|
1924
2082
|
function getCachedFormat(name, version) {
|
|
1925
2083
|
const formatPath = (0, import_node_path7.join)(getCacheDir(), name, version, "format.js");
|
|
1926
2084
|
try {
|
|
1927
|
-
if (!(0,
|
|
1928
|
-
const source = (0,
|
|
2085
|
+
if (!(0, import_node_fs6.existsSync)(formatPath)) return void 0;
|
|
2086
|
+
const source = (0, import_node_fs6.readFileSync)(formatPath, "utf-8");
|
|
1929
2087
|
const id = makeFormatId(name, version);
|
|
1930
2088
|
const data = parseFormatJSON(source, id);
|
|
1931
2089
|
if (!data) return void 0;
|
|
@@ -1945,26 +2103,26 @@ function discoverCachedFormats() {
|
|
|
1945
2103
|
const formats = /* @__PURE__ */ new Map();
|
|
1946
2104
|
const cacheDir = getCacheDir();
|
|
1947
2105
|
try {
|
|
1948
|
-
if (!(0,
|
|
2106
|
+
if (!(0, import_node_fs6.existsSync)(cacheDir)) return formats;
|
|
1949
2107
|
} catch {
|
|
1950
2108
|
return formats;
|
|
1951
2109
|
}
|
|
1952
2110
|
let names;
|
|
1953
2111
|
try {
|
|
1954
|
-
names = (0,
|
|
2112
|
+
names = (0, import_node_fs6.readdirSync)(cacheDir);
|
|
1955
2113
|
} catch {
|
|
1956
2114
|
return formats;
|
|
1957
2115
|
}
|
|
1958
2116
|
for (const name of names) {
|
|
1959
2117
|
const nameDir = (0, import_node_path7.join)(cacheDir, name);
|
|
1960
2118
|
try {
|
|
1961
|
-
if (!(0,
|
|
2119
|
+
if (!(0, import_node_fs6.statSync)(nameDir).isDirectory()) continue;
|
|
1962
2120
|
} catch {
|
|
1963
2121
|
continue;
|
|
1964
2122
|
}
|
|
1965
2123
|
let versions;
|
|
1966
2124
|
try {
|
|
1967
|
-
versions = (0,
|
|
2125
|
+
versions = (0, import_node_fs6.readdirSync)(nameDir);
|
|
1968
2126
|
} catch {
|
|
1969
2127
|
continue;
|
|
1970
2128
|
}
|
|
@@ -1994,17 +2152,18 @@ async function compile(options) {
|
|
|
1994
2152
|
}
|
|
1995
2153
|
async function compileToFile(options) {
|
|
1996
2154
|
const result = await compile(options);
|
|
1997
|
-
(0,
|
|
2155
|
+
(0, import_node_fs7.writeFileSync)(options.outFile, result.output, "utf-8");
|
|
1998
2156
|
return result;
|
|
1999
2157
|
}
|
|
2000
2158
|
async function watch(options) {
|
|
2001
2159
|
const controller = new AbortController();
|
|
2160
|
+
const cache = /* @__PURE__ */ new Map();
|
|
2002
2161
|
const filePaths = options.sources.filter((s) => typeof s === "string");
|
|
2003
2162
|
const modulePaths = options.modules ?? [];
|
|
2004
2163
|
const allPaths = [...filePaths, ...modulePaths];
|
|
2005
|
-
const handle = watchFilesystem(allPaths, options.outFile, () => {
|
|
2006
|
-
buildOutput(options).then((result) => {
|
|
2007
|
-
(0,
|
|
2164
|
+
const handle = watchFilesystem(allPaths, options.outFile, (changedFiles) => {
|
|
2165
|
+
buildOutput(options, cache, changedFiles).then((result) => {
|
|
2166
|
+
(0, import_node_fs7.writeFileSync)(options.outFile, result.output, "utf-8");
|
|
2008
2167
|
options.onBuild?.(result);
|
|
2009
2168
|
}).catch((e) => {
|
|
2010
2169
|
options.onError?.(e instanceof Error ? e : new Error(String(e)));
|
|
@@ -2013,13 +2172,14 @@ async function watch(options) {
|
|
|
2013
2172
|
controller.signal.addEventListener("abort", () => handle.close());
|
|
2014
2173
|
return controller;
|
|
2015
2174
|
}
|
|
2016
|
-
async function buildOutput(options) {
|
|
2175
|
+
async function buildOutput(options, cache, changedFiles) {
|
|
2017
2176
|
const diagnostics = [];
|
|
2018
2177
|
const outputMode = options.outputMode ?? "html";
|
|
2019
2178
|
const trim = options.trim ?? true;
|
|
2020
2179
|
const twee2Compat = options.twee2Compat ?? false;
|
|
2021
2180
|
const testMode = options.testMode ?? false;
|
|
2022
2181
|
const noRemote = options.noRemote ?? false;
|
|
2182
|
+
const sourceInfo = options.sourceInfo ?? false;
|
|
2023
2183
|
clearIndexCache();
|
|
2024
2184
|
const filePaths = [];
|
|
2025
2185
|
const inlineSources = [];
|
|
@@ -2033,7 +2193,11 @@ async function buildOutput(options) {
|
|
|
2033
2193
|
const sourceFilenames = getFilenames(filePaths);
|
|
2034
2194
|
const story = createStory();
|
|
2035
2195
|
const processedFiles = /* @__PURE__ */ new Set();
|
|
2036
|
-
|
|
2196
|
+
if (cache) {
|
|
2197
|
+
loadSourcesCached(story, sourceFilenames, { trim, twee2Compat }, diagnostics, processedFiles, cache, changedFiles);
|
|
2198
|
+
} else {
|
|
2199
|
+
loadSources(story, sourceFilenames, { trim, twee2Compat }, diagnostics, processedFiles);
|
|
2200
|
+
}
|
|
2037
2201
|
loadInlineSources(story, inlineSources, { trim, twee2Compat }, diagnostics);
|
|
2038
2202
|
if (options.tagAliases) {
|
|
2039
2203
|
story.passages = applyTagAliases(story.passages, options.tagAliases);
|
|
@@ -2081,7 +2245,7 @@ async function buildOutput(options) {
|
|
|
2081
2245
|
output = toTwee(story, outputMode);
|
|
2082
2246
|
break;
|
|
2083
2247
|
case "twine2-archive":
|
|
2084
|
-
output = toTwine2Archive(story, startName, diagnostics);
|
|
2248
|
+
output = toTwine2Archive(story, startName, diagnostics, { sourceInfo });
|
|
2085
2249
|
break;
|
|
2086
2250
|
case "twine1-archive":
|
|
2087
2251
|
output = toTwine1Archive(story, startName);
|
|
@@ -2100,7 +2264,7 @@ async function buildOutput(options) {
|
|
|
2100
2264
|
throw new TweeTsError("No story format available for HTML output.", diagnostics);
|
|
2101
2265
|
}
|
|
2102
2266
|
if (format.isTwine2) {
|
|
2103
|
-
output = toTwine2HTML(story, format, startName, diagnostics);
|
|
2267
|
+
output = toTwine2HTML(story, format, startName, diagnostics, { sourceInfo });
|
|
2104
2268
|
} else {
|
|
2105
2269
|
if (story.name === "" && !storyHas(story, "StoryTitle")) {
|
|
2106
2270
|
diagnostics.push({
|
|
@@ -2274,17 +2438,17 @@ function storyInspect(story) {
|
|
|
2274
2438
|
}
|
|
2275
2439
|
|
|
2276
2440
|
// src/config.ts
|
|
2277
|
-
var
|
|
2441
|
+
var import_node_fs8 = require("fs");
|
|
2278
2442
|
var import_node_path8 = require("path");
|
|
2279
2443
|
var CONFIG_FILENAME = "twee-ts.config.json";
|
|
2280
2444
|
var VALID_OUTPUT_MODES = ["html", "twee3", "twee1", "twine2-archive", "twine1-archive", "json"];
|
|
2281
2445
|
function loadConfig(dir) {
|
|
2282
2446
|
const base = dir ?? process.cwd();
|
|
2283
2447
|
const configPath = (0, import_node_path8.join)(base, CONFIG_FILENAME);
|
|
2284
|
-
if (!(0,
|
|
2448
|
+
if (!(0, import_node_fs8.existsSync)(configPath)) return null;
|
|
2285
2449
|
let raw;
|
|
2286
2450
|
try {
|
|
2287
|
-
raw = (0,
|
|
2451
|
+
raw = (0, import_node_fs8.readFileSync)(configPath, "utf-8");
|
|
2288
2452
|
} catch {
|
|
2289
2453
|
return null;
|
|
2290
2454
|
}
|
|
@@ -2304,7 +2468,7 @@ function loadConfig(dir) {
|
|
|
2304
2468
|
function loadConfigFile(filePath) {
|
|
2305
2469
|
let raw;
|
|
2306
2470
|
try {
|
|
2307
|
-
raw = (0,
|
|
2471
|
+
raw = (0, import_node_fs8.readFileSync)(filePath, "utf-8");
|
|
2308
2472
|
} catch (e) {
|
|
2309
2473
|
throw new Error(`Cannot read config file ${filePath}: ${e instanceof Error ? e.message : String(e)}`);
|
|
2310
2474
|
}
|
|
@@ -2333,7 +2497,7 @@ function validateConfig(data) {
|
|
|
2333
2497
|
errors.push(`"${key}" must be a string.`);
|
|
2334
2498
|
}
|
|
2335
2499
|
}
|
|
2336
|
-
for (const key of ["useTweegoPath", "trim", "twee2Compat", "testMode", "noRemote"]) {
|
|
2500
|
+
for (const key of ["useTweegoPath", "trim", "twee2Compat", "testMode", "noRemote", "sourceInfo"]) {
|
|
2337
2501
|
if (key in obj && typeof obj[key] !== "boolean") {
|
|
2338
2502
|
errors.push(`"${key}" must be a boolean.`);
|
|
2339
2503
|
}
|