@rohal12/twee-ts 1.5.0 → 1.7.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 +393 -43
- package/dist/bin/twee-ts.js.map +1 -1
- package/dist/{chunk-KI4QMLEN.js → chunk-HXL3JC4L.js} +191 -38
- package/dist/chunk-HXL3JC4L.js.map +1 -0
- package/dist/index.cjs +288 -62
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +40 -1
- package/dist/index.d.ts +40 -1
- package/dist/index.js +267 -43
- package/dist/index.js.map +1 -1
- package/dist/plugins/rollup.js +1 -1
- package/dist/plugins/vite.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-KI4QMLEN.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -30,9 +30,11 @@ __export(src_exports, {
|
|
|
30
30
|
discoverFormats: () => discoverFormats,
|
|
31
31
|
fetchAndCacheFormat: () => fetchAndCacheFormat,
|
|
32
32
|
fetchDirectFormat: () => fetchDirectFormat,
|
|
33
|
+
formatLintReport: () => formatLintReport,
|
|
33
34
|
generateIFID: () => generateIFID,
|
|
34
35
|
getCacheDir: () => getCacheDir,
|
|
35
36
|
getFormatSearchDirs: () => getFormatSearchDirs,
|
|
37
|
+
lint: () => lint,
|
|
36
38
|
loadConfig: () => loadConfig,
|
|
37
39
|
loadConfigFile: () => loadConfigFile,
|
|
38
40
|
parseFormatJSON: () => parseFormatJSON,
|
|
@@ -50,7 +52,7 @@ __export(src_exports, {
|
|
|
50
52
|
module.exports = __toCommonJS(src_exports);
|
|
51
53
|
|
|
52
54
|
// src/compiler.ts
|
|
53
|
-
var
|
|
55
|
+
var import_node_fs7 = require("fs");
|
|
54
56
|
|
|
55
57
|
// src/ifid.ts
|
|
56
58
|
var import_node_crypto = require("crypto");
|
|
@@ -309,8 +311,21 @@ function quote(s) {
|
|
|
309
311
|
}
|
|
310
312
|
|
|
311
313
|
// src/story.ts
|
|
314
|
+
var passageIndex = /* @__PURE__ */ new WeakMap();
|
|
315
|
+
function getIndex(story) {
|
|
316
|
+
let index = passageIndex.get(story);
|
|
317
|
+
if (!index) {
|
|
318
|
+
index = /* @__PURE__ */ new Map();
|
|
319
|
+
for (let i = 0; i < story.passages.length; i++) {
|
|
320
|
+
const passage = story.passages[i];
|
|
321
|
+
if (passage) index.set(passage.name, i);
|
|
322
|
+
}
|
|
323
|
+
passageIndex.set(story, index);
|
|
324
|
+
}
|
|
325
|
+
return index;
|
|
326
|
+
}
|
|
312
327
|
function createStory() {
|
|
313
|
-
|
|
328
|
+
const story = {
|
|
314
329
|
name: "",
|
|
315
330
|
ifid: "",
|
|
316
331
|
passages: [],
|
|
@@ -326,16 +341,17 @@ function createStory() {
|
|
|
326
341
|
zoom: 1
|
|
327
342
|
}
|
|
328
343
|
};
|
|
344
|
+
passageIndex.set(story, /* @__PURE__ */ new Map());
|
|
345
|
+
return story;
|
|
329
346
|
}
|
|
330
347
|
function storyHas(story, name) {
|
|
331
|
-
return story.
|
|
332
|
-
}
|
|
333
|
-
function storyIndex(story, name) {
|
|
334
|
-
return story.passages.findIndex((p) => p.name === name);
|
|
348
|
+
return getIndex(story).has(name);
|
|
335
349
|
}
|
|
336
350
|
function storyAppend(story, p, diagnostics) {
|
|
337
|
-
const
|
|
351
|
+
const index = getIndex(story);
|
|
352
|
+
const i = index.get(p.name) ?? -1;
|
|
338
353
|
if (i === -1) {
|
|
354
|
+
index.set(p.name, story.passages.length);
|
|
339
355
|
story.passages.push(p);
|
|
340
356
|
} else {
|
|
341
357
|
diagnostics.push({
|
|
@@ -346,9 +362,15 @@ function storyAppend(story, p, diagnostics) {
|
|
|
346
362
|
}
|
|
347
363
|
}
|
|
348
364
|
function storyPrepend(story, p, diagnostics) {
|
|
349
|
-
const
|
|
365
|
+
const index = getIndex(story);
|
|
366
|
+
const i = index.get(p.name) ?? -1;
|
|
350
367
|
if (i === -1) {
|
|
351
368
|
story.passages.unshift(p);
|
|
369
|
+
index.clear();
|
|
370
|
+
for (let j = 0; j < story.passages.length; j++) {
|
|
371
|
+
const passage = story.passages[j];
|
|
372
|
+
if (passage) index.set(passage.name, j);
|
|
373
|
+
}
|
|
352
374
|
} else {
|
|
353
375
|
diagnostics.push({
|
|
354
376
|
level: "warning",
|
|
@@ -638,11 +660,15 @@ function watchFilesystem(pathnames, outFilename, callback) {
|
|
|
638
660
|
const watchers = [];
|
|
639
661
|
let buildTimer = null;
|
|
640
662
|
const BUILD_DEBOUNCE = 500;
|
|
641
|
-
|
|
663
|
+
const pendingFiles = /* @__PURE__ */ new Set();
|
|
664
|
+
function scheduleBuild(changedFile) {
|
|
665
|
+
if (changedFile) pendingFiles.add(changedFile);
|
|
642
666
|
if (buildTimer) clearTimeout(buildTimer);
|
|
643
667
|
buildTimer = setTimeout(() => {
|
|
644
668
|
buildTimer = null;
|
|
645
|
-
|
|
669
|
+
const files = pendingFiles.size > 0 ? new Set(pendingFiles) : void 0;
|
|
670
|
+
pendingFiles.clear();
|
|
671
|
+
callback(files);
|
|
646
672
|
}, BUILD_DEBOUNCE);
|
|
647
673
|
}
|
|
648
674
|
for (const pathname of pathnames) {
|
|
@@ -652,7 +678,8 @@ function watchFilesystem(pathnames, outFilename, callback) {
|
|
|
652
678
|
const abs = (0, import_node_path2.resolve)(pathname, filename);
|
|
653
679
|
if (abs === absOutFile) return;
|
|
654
680
|
if (isKnownFileType(filename)) {
|
|
655
|
-
|
|
681
|
+
const rel = (0, import_node_path2.relative)(process.cwd(), abs);
|
|
682
|
+
scheduleBuild(rel || abs);
|
|
656
683
|
}
|
|
657
684
|
});
|
|
658
685
|
watchers.push(watcher);
|
|
@@ -911,6 +938,7 @@ function readFormatSource(format) {
|
|
|
911
938
|
|
|
912
939
|
// src/loader.ts
|
|
913
940
|
var import_node_path5 = require("path");
|
|
941
|
+
var import_node_fs4 = require("fs");
|
|
914
942
|
|
|
915
943
|
// src/lexer.ts
|
|
916
944
|
var EOF = -1;
|
|
@@ -1434,54 +1462,182 @@ function loadInlineSources(story, sources, opts, diagnostics) {
|
|
|
1434
1462
|
}
|
|
1435
1463
|
}
|
|
1436
1464
|
}
|
|
1437
|
-
function
|
|
1465
|
+
function parseTweeFile(filename, opts) {
|
|
1438
1466
|
const source = readUTF8(filename);
|
|
1439
1467
|
const result = parseTwee(source, {
|
|
1440
1468
|
filename,
|
|
1441
1469
|
trim: opts.trim ?? true,
|
|
1442
1470
|
twee2Compat: opts.twee2Compat ?? false
|
|
1443
1471
|
});
|
|
1444
|
-
diagnostics
|
|
1445
|
-
for (const p of result.passages) {
|
|
1446
|
-
storyAdd(story, p, diagnostics);
|
|
1447
|
-
}
|
|
1472
|
+
return { passages: result.passages, diagnostics: [...result.diagnostics] };
|
|
1448
1473
|
}
|
|
1449
|
-
function
|
|
1474
|
+
function parseTaggedFile(tag, filename) {
|
|
1450
1475
|
const source = readUTF8(filename);
|
|
1451
|
-
|
|
1476
|
+
return { passages: [{ name: (0, import_node_path5.basename)(filename), tags: [tag], text: source }], diagnostics: [] };
|
|
1452
1477
|
}
|
|
1453
|
-
function
|
|
1478
|
+
function parseMediaFile(tag, filename) {
|
|
1454
1479
|
const source = readBase64(filename);
|
|
1455
1480
|
const name = baseNameWithoutExt(filename);
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
tags: [tag],
|
|
1461
|
-
text: `data:${mediaTypeFromFilename(filename)};base64,${source}`
|
|
1462
|
-
},
|
|
1463
|
-
diagnostics
|
|
1464
|
-
);
|
|
1481
|
+
return {
|
|
1482
|
+
passages: [{ name, tags: [tag], text: `data:${mediaTypeFromFilename(filename)};base64,${source}` }],
|
|
1483
|
+
diagnostics: []
|
|
1484
|
+
};
|
|
1465
1485
|
}
|
|
1466
|
-
function
|
|
1486
|
+
function parseFontFile(filename) {
|
|
1467
1487
|
const source = readBase64(filename);
|
|
1468
1488
|
const name = (0, import_node_path5.basename)(filename);
|
|
1469
1489
|
const family = baseNameWithoutExt(filename);
|
|
1470
1490
|
const ext = normalizedFileExt(filename);
|
|
1471
1491
|
const mediaType = mediaTypeFromExt(ext);
|
|
1472
1492
|
const hint = fontFormatHint(ext);
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1493
|
+
return {
|
|
1494
|
+
passages: [
|
|
1495
|
+
{
|
|
1496
|
+
name,
|
|
1497
|
+
tags: ["stylesheet"],
|
|
1498
|
+
text: `@font-face {
|
|
1479
1499
|
font-family: "${family}";
|
|
1480
1500
|
src: url("data:${mediaType};base64,${source}") format("${hint}");
|
|
1481
1501
|
}`
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1502
|
+
}
|
|
1503
|
+
],
|
|
1504
|
+
diagnostics: []
|
|
1505
|
+
};
|
|
1506
|
+
}
|
|
1507
|
+
function parseFile(filename, opts) {
|
|
1508
|
+
const ext = normalizedFileExt(filename);
|
|
1509
|
+
switch (ext) {
|
|
1510
|
+
case "tw":
|
|
1511
|
+
case "twee":
|
|
1512
|
+
return parseTweeFile(filename, opts);
|
|
1513
|
+
case "tw2":
|
|
1514
|
+
case "twee2":
|
|
1515
|
+
return parseTweeFile(filename, { ...opts, twee2Compat: true });
|
|
1516
|
+
case "css":
|
|
1517
|
+
return parseTaggedFile("stylesheet", filename);
|
|
1518
|
+
case "js":
|
|
1519
|
+
return parseTaggedFile("script", filename);
|
|
1520
|
+
case "otf":
|
|
1521
|
+
case "ttf":
|
|
1522
|
+
case "woff":
|
|
1523
|
+
case "woff2":
|
|
1524
|
+
return parseFontFile(filename);
|
|
1525
|
+
case "gif":
|
|
1526
|
+
case "jpeg":
|
|
1527
|
+
case "jpg":
|
|
1528
|
+
case "png":
|
|
1529
|
+
case "svg":
|
|
1530
|
+
case "tif":
|
|
1531
|
+
case "tiff":
|
|
1532
|
+
case "webp":
|
|
1533
|
+
return parseMediaFile("Twine.image", filename);
|
|
1534
|
+
case "aac":
|
|
1535
|
+
case "flac":
|
|
1536
|
+
case "m4a":
|
|
1537
|
+
case "mp3":
|
|
1538
|
+
case "oga":
|
|
1539
|
+
case "ogg":
|
|
1540
|
+
case "opus":
|
|
1541
|
+
case "wav":
|
|
1542
|
+
case "wave":
|
|
1543
|
+
case "weba":
|
|
1544
|
+
return parseMediaFile("Twine.audio", filename);
|
|
1545
|
+
case "mp4":
|
|
1546
|
+
case "ogv":
|
|
1547
|
+
case "webm":
|
|
1548
|
+
return parseMediaFile("Twine.video", filename);
|
|
1549
|
+
case "vtt":
|
|
1550
|
+
return parseMediaFile("Twine.vtt", filename);
|
|
1551
|
+
default:
|
|
1552
|
+
return void 0;
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
function loadTwee(story, filename, opts, diagnostics) {
|
|
1556
|
+
const result = parseTweeFile(filename, opts);
|
|
1557
|
+
diagnostics.push(...result.diagnostics);
|
|
1558
|
+
for (const p of result.passages) {
|
|
1559
|
+
storyAdd(story, p, diagnostics);
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
function loadTagged(story, tag, filename, diagnostics) {
|
|
1563
|
+
const result = parseTaggedFile(tag, filename);
|
|
1564
|
+
for (const p of result.passages) {
|
|
1565
|
+
storyAdd(story, p, diagnostics);
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
function loadMedia(story, tag, filename, diagnostics) {
|
|
1569
|
+
const result = parseMediaFile(tag, filename);
|
|
1570
|
+
for (const p of result.passages) {
|
|
1571
|
+
storyAdd(story, p, diagnostics);
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
function loadFont(story, filename, diagnostics) {
|
|
1575
|
+
const result = parseFontFile(filename);
|
|
1576
|
+
for (const p of result.passages) {
|
|
1577
|
+
storyAdd(story, p, diagnostics);
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
function loadSourcesCached(story, filenames, opts, diagnostics, processedFiles, cache, changedFiles) {
|
|
1581
|
+
const currentFiles = /* @__PURE__ */ new Set();
|
|
1582
|
+
for (const filename of filenames) {
|
|
1583
|
+
if (processedFiles.has(filename)) {
|
|
1584
|
+
diagnostics.push({ level: "warning", message: `load ${filename}: Skipping duplicate.` });
|
|
1585
|
+
continue;
|
|
1586
|
+
}
|
|
1587
|
+
currentFiles.add(filename);
|
|
1588
|
+
const cached = cache.get(filename);
|
|
1589
|
+
if (changedFiles && cached && !changedFiles.has(filename)) {
|
|
1590
|
+
diagnostics.push(...cached.diagnostics);
|
|
1591
|
+
for (const p of cached.passages) {
|
|
1592
|
+
storyAdd(story, p, diagnostics);
|
|
1593
|
+
}
|
|
1594
|
+
processedFiles.add(filename);
|
|
1595
|
+
continue;
|
|
1596
|
+
}
|
|
1597
|
+
let mtimeMs;
|
|
1598
|
+
try {
|
|
1599
|
+
mtimeMs = (0, import_node_fs4.statSync)(filename).mtimeMs;
|
|
1600
|
+
} catch {
|
|
1601
|
+
continue;
|
|
1602
|
+
}
|
|
1603
|
+
if (cached && cached.mtimeMs === mtimeMs) {
|
|
1604
|
+
diagnostics.push(...cached.diagnostics);
|
|
1605
|
+
for (const p of cached.passages) {
|
|
1606
|
+
storyAdd(story, p, diagnostics);
|
|
1607
|
+
}
|
|
1608
|
+
processedFiles.add(filename);
|
|
1609
|
+
continue;
|
|
1610
|
+
}
|
|
1611
|
+
try {
|
|
1612
|
+
const result = parseFile(filename, opts);
|
|
1613
|
+
if (!result) continue;
|
|
1614
|
+
cache.set(filename, {
|
|
1615
|
+
mtimeMs,
|
|
1616
|
+
passages: result.passages,
|
|
1617
|
+
diagnostics: result.diagnostics
|
|
1618
|
+
});
|
|
1619
|
+
diagnostics.push(...result.diagnostics);
|
|
1620
|
+
for (const p of result.passages) {
|
|
1621
|
+
storyAdd(story, p, diagnostics);
|
|
1622
|
+
}
|
|
1623
|
+
} catch (e) {
|
|
1624
|
+
diagnostics.push({
|
|
1625
|
+
level: "error",
|
|
1626
|
+
message: `load ${filename}: ${e instanceof Error ? e.message : String(e)}`,
|
|
1627
|
+
file: filename
|
|
1628
|
+
});
|
|
1629
|
+
continue;
|
|
1630
|
+
}
|
|
1631
|
+
processedFiles.add(filename);
|
|
1632
|
+
}
|
|
1633
|
+
for (const key of cache.keys()) {
|
|
1634
|
+
if (!currentFiles.has(key)) {
|
|
1635
|
+
cache.delete(key);
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
if (story.name !== "" && !story.passages.some((p) => p.name === "StoryTitle")) {
|
|
1639
|
+
storyPrepend(story, { name: "StoryTitle", tags: [], text: story.name }, diagnostics);
|
|
1640
|
+
}
|
|
1485
1641
|
}
|
|
1486
1642
|
|
|
1487
1643
|
// src/version.ts
|
|
@@ -1591,7 +1747,7 @@ function ensureIFID(story, diagnostics) {
|
|
|
1591
1747
|
}
|
|
1592
1748
|
|
|
1593
1749
|
// src/output-twine1.ts
|
|
1594
|
-
var
|
|
1750
|
+
var import_node_fs5 = require("fs");
|
|
1595
1751
|
var import_node_path6 = require("path");
|
|
1596
1752
|
var CREATOR_NAME2 = "twee-ts";
|
|
1597
1753
|
function toTwine1Archive(story, _startName) {
|
|
@@ -1624,7 +1780,7 @@ function toTwine1HTML(story, format, startName, _diagnostics) {
|
|
|
1624
1780
|
} else {
|
|
1625
1781
|
let footer;
|
|
1626
1782
|
try {
|
|
1627
|
-
footer = (0,
|
|
1783
|
+
footer = (0, import_node_fs5.readFileSync)((0, import_node_path6.join)(formatDir, "footer.html"), "utf-8");
|
|
1628
1784
|
} catch {
|
|
1629
1785
|
footer = "</div>\n</body>\n</html>\n";
|
|
1630
1786
|
}
|
|
@@ -1654,7 +1810,7 @@ function getTwine1PassageChunk(story) {
|
|
|
1654
1810
|
function tryReplaceComponent(template, placeholder, componentPath, required) {
|
|
1655
1811
|
if (!template.includes(placeholder)) return template;
|
|
1656
1812
|
try {
|
|
1657
|
-
let content = (0,
|
|
1813
|
+
let content = (0, import_node_fs5.readFileSync)(componentPath, "utf-8");
|
|
1658
1814
|
if (content.charCodeAt(0) === 65279) content = content.slice(1);
|
|
1659
1815
|
return template.replace(placeholder, content);
|
|
1660
1816
|
} catch (e) {
|
|
@@ -1750,7 +1906,7 @@ function modifyHead(html, modulePaths, headFile, diagnostics) {
|
|
|
1750
1906
|
}
|
|
1751
1907
|
|
|
1752
1908
|
// src/remote-formats.ts
|
|
1753
|
-
var
|
|
1909
|
+
var import_node_fs6 = require("fs");
|
|
1754
1910
|
var import_node_path7 = require("path");
|
|
1755
1911
|
var import_node_os2 = require("os");
|
|
1756
1912
|
var DEFAULT_SFA_INDICES = [
|
|
@@ -1851,9 +2007,9 @@ async function fetchAndCacheFormat(entry, downloadUrl) {
|
|
|
1851
2007
|
}
|
|
1852
2008
|
const cacheDir = getCacheDir();
|
|
1853
2009
|
const formatDir = (0, import_node_path7.join)(cacheDir, entry.name, entry.version);
|
|
1854
|
-
(0,
|
|
2010
|
+
(0, import_node_fs6.mkdirSync)(formatDir, { recursive: true });
|
|
1855
2011
|
const formatPath = (0, import_node_path7.join)(formatDir, "format.js");
|
|
1856
|
-
(0,
|
|
2012
|
+
(0, import_node_fs6.writeFileSync)(formatPath, text, "utf-8");
|
|
1857
2013
|
return {
|
|
1858
2014
|
id,
|
|
1859
2015
|
filename: formatPath,
|
|
@@ -1877,9 +2033,9 @@ async function fetchDirectFormat(url) {
|
|
|
1877
2033
|
const id = makeFormatId(data.name, data.version);
|
|
1878
2034
|
const cacheDir = getCacheDir();
|
|
1879
2035
|
const formatDir = (0, import_node_path7.join)(cacheDir, data.name, data.version);
|
|
1880
|
-
(0,
|
|
2036
|
+
(0, import_node_fs6.mkdirSync)(formatDir, { recursive: true });
|
|
1881
2037
|
const formatPath = (0, import_node_path7.join)(formatDir, "format.js");
|
|
1882
|
-
(0,
|
|
2038
|
+
(0, import_node_fs6.writeFileSync)(formatPath, text, "utf-8");
|
|
1883
2039
|
return {
|
|
1884
2040
|
id,
|
|
1885
2041
|
filename: formatPath,
|
|
@@ -1928,8 +2084,8 @@ async function resolveRemoteFormat(name, version, indices, urls) {
|
|
|
1928
2084
|
function getCachedFormat(name, version) {
|
|
1929
2085
|
const formatPath = (0, import_node_path7.join)(getCacheDir(), name, version, "format.js");
|
|
1930
2086
|
try {
|
|
1931
|
-
if (!(0,
|
|
1932
|
-
const source = (0,
|
|
2087
|
+
if (!(0, import_node_fs6.existsSync)(formatPath)) return void 0;
|
|
2088
|
+
const source = (0, import_node_fs6.readFileSync)(formatPath, "utf-8");
|
|
1933
2089
|
const id = makeFormatId(name, version);
|
|
1934
2090
|
const data = parseFormatJSON(source, id);
|
|
1935
2091
|
if (!data) return void 0;
|
|
@@ -1949,26 +2105,26 @@ function discoverCachedFormats() {
|
|
|
1949
2105
|
const formats = /* @__PURE__ */ new Map();
|
|
1950
2106
|
const cacheDir = getCacheDir();
|
|
1951
2107
|
try {
|
|
1952
|
-
if (!(0,
|
|
2108
|
+
if (!(0, import_node_fs6.existsSync)(cacheDir)) return formats;
|
|
1953
2109
|
} catch {
|
|
1954
2110
|
return formats;
|
|
1955
2111
|
}
|
|
1956
2112
|
let names;
|
|
1957
2113
|
try {
|
|
1958
|
-
names = (0,
|
|
2114
|
+
names = (0, import_node_fs6.readdirSync)(cacheDir);
|
|
1959
2115
|
} catch {
|
|
1960
2116
|
return formats;
|
|
1961
2117
|
}
|
|
1962
2118
|
for (const name of names) {
|
|
1963
2119
|
const nameDir = (0, import_node_path7.join)(cacheDir, name);
|
|
1964
2120
|
try {
|
|
1965
|
-
if (!(0,
|
|
2121
|
+
if (!(0, import_node_fs6.statSync)(nameDir).isDirectory()) continue;
|
|
1966
2122
|
} catch {
|
|
1967
2123
|
continue;
|
|
1968
2124
|
}
|
|
1969
2125
|
let versions;
|
|
1970
2126
|
try {
|
|
1971
|
-
versions = (0,
|
|
2127
|
+
versions = (0, import_node_fs6.readdirSync)(nameDir);
|
|
1972
2128
|
} catch {
|
|
1973
2129
|
continue;
|
|
1974
2130
|
}
|
|
@@ -1998,17 +2154,18 @@ async function compile(options) {
|
|
|
1998
2154
|
}
|
|
1999
2155
|
async function compileToFile(options) {
|
|
2000
2156
|
const result = await compile(options);
|
|
2001
|
-
(0,
|
|
2157
|
+
(0, import_node_fs7.writeFileSync)(options.outFile, result.output, "utf-8");
|
|
2002
2158
|
return result;
|
|
2003
2159
|
}
|
|
2004
2160
|
async function watch(options) {
|
|
2005
2161
|
const controller = new AbortController();
|
|
2162
|
+
const cache = /* @__PURE__ */ new Map();
|
|
2006
2163
|
const filePaths = options.sources.filter((s) => typeof s === "string");
|
|
2007
2164
|
const modulePaths = options.modules ?? [];
|
|
2008
2165
|
const allPaths = [...filePaths, ...modulePaths];
|
|
2009
|
-
const handle = watchFilesystem(allPaths, options.outFile, () => {
|
|
2010
|
-
buildOutput(options).then((result) => {
|
|
2011
|
-
(0,
|
|
2166
|
+
const handle = watchFilesystem(allPaths, options.outFile, (changedFiles) => {
|
|
2167
|
+
buildOutput(options, cache, changedFiles).then((result) => {
|
|
2168
|
+
(0, import_node_fs7.writeFileSync)(options.outFile, result.output, "utf-8");
|
|
2012
2169
|
options.onBuild?.(result);
|
|
2013
2170
|
}).catch((e) => {
|
|
2014
2171
|
options.onError?.(e instanceof Error ? e : new Error(String(e)));
|
|
@@ -2017,7 +2174,7 @@ async function watch(options) {
|
|
|
2017
2174
|
controller.signal.addEventListener("abort", () => handle.close());
|
|
2018
2175
|
return controller;
|
|
2019
2176
|
}
|
|
2020
|
-
async function buildOutput(options) {
|
|
2177
|
+
async function buildOutput(options, cache, changedFiles) {
|
|
2021
2178
|
const diagnostics = [];
|
|
2022
2179
|
const outputMode = options.outputMode ?? "html";
|
|
2023
2180
|
const trim = options.trim ?? true;
|
|
@@ -2038,7 +2195,11 @@ async function buildOutput(options) {
|
|
|
2038
2195
|
const sourceFilenames = getFilenames(filePaths);
|
|
2039
2196
|
const story = createStory();
|
|
2040
2197
|
const processedFiles = /* @__PURE__ */ new Set();
|
|
2041
|
-
|
|
2198
|
+
if (cache) {
|
|
2199
|
+
loadSourcesCached(story, sourceFilenames, { trim, twee2Compat }, diagnostics, processedFiles, cache, changedFiles);
|
|
2200
|
+
} else {
|
|
2201
|
+
loadSources(story, sourceFilenames, { trim, twee2Compat }, diagnostics, processedFiles);
|
|
2202
|
+
}
|
|
2042
2203
|
loadInlineSources(story, inlineSources, { trim, twee2Compat }, diagnostics);
|
|
2043
2204
|
if (options.tagAliases) {
|
|
2044
2205
|
story.passages = applyTagAliases(story.passages, options.tagAliases);
|
|
@@ -2278,18 +2439,81 @@ function storyInspect(story) {
|
|
|
2278
2439
|
};
|
|
2279
2440
|
}
|
|
2280
2441
|
|
|
2442
|
+
// src/lint.ts
|
|
2443
|
+
async function lint(options) {
|
|
2444
|
+
const result = await compile({ ...options, outputMode: "json" });
|
|
2445
|
+
const map = storyInspect(result.story);
|
|
2446
|
+
return {
|
|
2447
|
+
diagnostics: result.diagnostics,
|
|
2448
|
+
stats: result.stats,
|
|
2449
|
+
formatName: result.story.twine2.format,
|
|
2450
|
+
formatVersion: result.story.twine2.formatVersion,
|
|
2451
|
+
start: map.start,
|
|
2452
|
+
passages: map.passages.length,
|
|
2453
|
+
storyPassages: map.storyPassages.length,
|
|
2454
|
+
infoPassages: map.infoPassages.length,
|
|
2455
|
+
brokenLinks: map.brokenLinks,
|
|
2456
|
+
deadEnds: map.deadEnds,
|
|
2457
|
+
orphans: map.orphans
|
|
2458
|
+
};
|
|
2459
|
+
}
|
|
2460
|
+
function formatLintReport(result) {
|
|
2461
|
+
const lines = [];
|
|
2462
|
+
const formatStr = result.formatName ? `${result.formatName}${result.formatVersion ? " " + result.formatVersion : ""}` : "unknown";
|
|
2463
|
+
lines.push(`Format: ${formatStr}`);
|
|
2464
|
+
lines.push(
|
|
2465
|
+
`Passages: ${result.passages} total (${result.storyPassages} story, ${result.infoPassages} info), ${result.stats.words.toLocaleString()} words, ${result.stats.files.length} files`
|
|
2466
|
+
);
|
|
2467
|
+
lines.push(`Start: ${result.start}`);
|
|
2468
|
+
if (result.brokenLinks.length > 0) {
|
|
2469
|
+
lines.push("");
|
|
2470
|
+
lines.push(`Broken links (${result.brokenLinks.length}):`);
|
|
2471
|
+
for (const link of result.brokenLinks) {
|
|
2472
|
+
lines.push(` ${link.from} -> ${link.to} (passage "${link.to}" does not exist)`);
|
|
2473
|
+
}
|
|
2474
|
+
}
|
|
2475
|
+
if (result.deadEnds.length > 0) {
|
|
2476
|
+
lines.push("");
|
|
2477
|
+
lines.push(`Dead ends (${result.deadEnds.length}): ${result.deadEnds.join(", ")}`);
|
|
2478
|
+
}
|
|
2479
|
+
if (result.orphans.length > 0) {
|
|
2480
|
+
lines.push("");
|
|
2481
|
+
lines.push(`Orphans (${result.orphans.length}): ${result.orphans.join(", ")}`);
|
|
2482
|
+
}
|
|
2483
|
+
const errors = result.diagnostics.filter((d) => d.level === "error");
|
|
2484
|
+
const warnings = result.diagnostics.filter((d) => d.level === "warning");
|
|
2485
|
+
if (errors.length > 0 || warnings.length > 0) {
|
|
2486
|
+
lines.push("");
|
|
2487
|
+
lines.push(`Diagnostics: ${errors.length} error(s), ${warnings.length} warning(s)`);
|
|
2488
|
+
for (const d of errors) {
|
|
2489
|
+
lines.push(` error: ${d.message}`);
|
|
2490
|
+
}
|
|
2491
|
+
for (const d of warnings) {
|
|
2492
|
+
lines.push(` warning: ${d.message}`);
|
|
2493
|
+
}
|
|
2494
|
+
}
|
|
2495
|
+
lines.push("");
|
|
2496
|
+
const hasErrors = errors.length > 0 || result.brokenLinks.length > 0;
|
|
2497
|
+
if (hasErrors) {
|
|
2498
|
+
lines.push("Lint failed.");
|
|
2499
|
+
} else {
|
|
2500
|
+
lines.push("Lint passed.");
|
|
2501
|
+
}
|
|
2502
|
+
return lines.join("\n");
|
|
2503
|
+
}
|
|
2504
|
+
|
|
2281
2505
|
// src/config.ts
|
|
2282
|
-
var
|
|
2506
|
+
var import_node_fs8 = require("fs");
|
|
2283
2507
|
var import_node_path8 = require("path");
|
|
2284
2508
|
var CONFIG_FILENAME = "twee-ts.config.json";
|
|
2285
2509
|
var VALID_OUTPUT_MODES = ["html", "twee3", "twee1", "twine2-archive", "twine1-archive", "json"];
|
|
2286
2510
|
function loadConfig(dir) {
|
|
2287
2511
|
const base = dir ?? process.cwd();
|
|
2288
2512
|
const configPath = (0, import_node_path8.join)(base, CONFIG_FILENAME);
|
|
2289
|
-
if (!(0,
|
|
2513
|
+
if (!(0, import_node_fs8.existsSync)(configPath)) return null;
|
|
2290
2514
|
let raw;
|
|
2291
2515
|
try {
|
|
2292
|
-
raw = (0,
|
|
2516
|
+
raw = (0, import_node_fs8.readFileSync)(configPath, "utf-8");
|
|
2293
2517
|
} catch {
|
|
2294
2518
|
return null;
|
|
2295
2519
|
}
|
|
@@ -2309,7 +2533,7 @@ function loadConfig(dir) {
|
|
|
2309
2533
|
function loadConfigFile(filePath) {
|
|
2310
2534
|
let raw;
|
|
2311
2535
|
try {
|
|
2312
|
-
raw = (0,
|
|
2536
|
+
raw = (0, import_node_fs8.readFileSync)(filePath, "utf-8");
|
|
2313
2537
|
} catch (e) {
|
|
2314
2538
|
throw new Error(`Cannot read config file ${filePath}: ${e instanceof Error ? e.message : String(e)}`);
|
|
2315
2539
|
}
|
|
@@ -2390,9 +2614,11 @@ function scaffoldConfig() {
|
|
|
2390
2614
|
discoverFormats,
|
|
2391
2615
|
fetchAndCacheFormat,
|
|
2392
2616
|
fetchDirectFormat,
|
|
2617
|
+
formatLintReport,
|
|
2393
2618
|
generateIFID,
|
|
2394
2619
|
getCacheDir,
|
|
2395
2620
|
getFormatSearchDirs,
|
|
2621
|
+
lint,
|
|
2396
2622
|
loadConfig,
|
|
2397
2623
|
loadConfigFile,
|
|
2398
2624
|
parseFormatJSON,
|