@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/bin/twee-ts.js
CHANGED
|
@@ -194,7 +194,7 @@ function passageToTwee(p, outMode) {
|
|
|
194
194
|
output += "\n\n";
|
|
195
195
|
return output;
|
|
196
196
|
}
|
|
197
|
-
function passageToPassagedata(p, pid) {
|
|
197
|
+
function passageToPassagedata(p, pid, options) {
|
|
198
198
|
let position;
|
|
199
199
|
let size;
|
|
200
200
|
if (hasMetadataPosition(p)) {
|
|
@@ -211,7 +211,11 @@ function passageToPassagedata(p, pid) {
|
|
|
211
211
|
} else {
|
|
212
212
|
size = "100,100";
|
|
213
213
|
}
|
|
214
|
-
|
|
214
|
+
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))}`;
|
|
215
|
+
if (options?.sourceInfo && p.source) {
|
|
216
|
+
attrs += ` data-source-file=${quote(attrEscape(p.source.file))} data-source-line="${p.source.line}"`;
|
|
217
|
+
}
|
|
218
|
+
return `${attrs}>${htmlEscape(p.text)}</tw-passagedata>`;
|
|
215
219
|
}
|
|
216
220
|
function passageToTiddler(p, pid, obfuscateRot13 = false) {
|
|
217
221
|
let position;
|
|
@@ -258,8 +262,21 @@ function quote(s) {
|
|
|
258
262
|
}
|
|
259
263
|
|
|
260
264
|
// src/story.ts
|
|
265
|
+
var passageIndex = /* @__PURE__ */ new WeakMap();
|
|
266
|
+
function getIndex(story) {
|
|
267
|
+
let index = passageIndex.get(story);
|
|
268
|
+
if (!index) {
|
|
269
|
+
index = /* @__PURE__ */ new Map();
|
|
270
|
+
for (let i = 0; i < story.passages.length; i++) {
|
|
271
|
+
const passage = story.passages[i];
|
|
272
|
+
if (passage) index.set(passage.name, i);
|
|
273
|
+
}
|
|
274
|
+
passageIndex.set(story, index);
|
|
275
|
+
}
|
|
276
|
+
return index;
|
|
277
|
+
}
|
|
261
278
|
function createStory() {
|
|
262
|
-
|
|
279
|
+
const story = {
|
|
263
280
|
name: "",
|
|
264
281
|
ifid: "",
|
|
265
282
|
passages: [],
|
|
@@ -275,16 +292,17 @@ function createStory() {
|
|
|
275
292
|
zoom: 1
|
|
276
293
|
}
|
|
277
294
|
};
|
|
295
|
+
passageIndex.set(story, /* @__PURE__ */ new Map());
|
|
296
|
+
return story;
|
|
278
297
|
}
|
|
279
298
|
function storyHas(story, name) {
|
|
280
|
-
return story.
|
|
281
|
-
}
|
|
282
|
-
function storyIndex(story, name) {
|
|
283
|
-
return story.passages.findIndex((p) => p.name === name);
|
|
299
|
+
return getIndex(story).has(name);
|
|
284
300
|
}
|
|
285
301
|
function storyAppend(story, p, diagnostics) {
|
|
286
|
-
const
|
|
302
|
+
const index = getIndex(story);
|
|
303
|
+
const i = index.get(p.name) ?? -1;
|
|
287
304
|
if (i === -1) {
|
|
305
|
+
index.set(p.name, story.passages.length);
|
|
288
306
|
story.passages.push(p);
|
|
289
307
|
} else {
|
|
290
308
|
diagnostics.push({
|
|
@@ -295,9 +313,15 @@ function storyAppend(story, p, diagnostics) {
|
|
|
295
313
|
}
|
|
296
314
|
}
|
|
297
315
|
function storyPrepend(story, p, diagnostics) {
|
|
298
|
-
const
|
|
316
|
+
const index = getIndex(story);
|
|
317
|
+
const i = index.get(p.name) ?? -1;
|
|
299
318
|
if (i === -1) {
|
|
300
319
|
story.passages.unshift(p);
|
|
320
|
+
index.clear();
|
|
321
|
+
for (let j = 0; j < story.passages.length; j++) {
|
|
322
|
+
const passage = story.passages[j];
|
|
323
|
+
if (passage) index.set(passage.name, j);
|
|
324
|
+
}
|
|
301
325
|
} else {
|
|
302
326
|
diagnostics.push({
|
|
303
327
|
level: "warning",
|
|
@@ -587,11 +611,15 @@ function watchFilesystem(pathnames, outFilename, callback) {
|
|
|
587
611
|
const watchers = [];
|
|
588
612
|
let buildTimer = null;
|
|
589
613
|
const BUILD_DEBOUNCE = 500;
|
|
590
|
-
|
|
614
|
+
const pendingFiles = /* @__PURE__ */ new Set();
|
|
615
|
+
function scheduleBuild(changedFile) {
|
|
616
|
+
if (changedFile) pendingFiles.add(changedFile);
|
|
591
617
|
if (buildTimer) clearTimeout(buildTimer);
|
|
592
618
|
buildTimer = setTimeout(() => {
|
|
593
619
|
buildTimer = null;
|
|
594
|
-
|
|
620
|
+
const files = pendingFiles.size > 0 ? new Set(pendingFiles) : void 0;
|
|
621
|
+
pendingFiles.clear();
|
|
622
|
+
callback(files);
|
|
595
623
|
}, BUILD_DEBOUNCE);
|
|
596
624
|
}
|
|
597
625
|
for (const pathname of pathnames) {
|
|
@@ -601,7 +629,8 @@ function watchFilesystem(pathnames, outFilename, callback) {
|
|
|
601
629
|
const abs = resolve(pathname, filename);
|
|
602
630
|
if (abs === absOutFile) return;
|
|
603
631
|
if (isKnownFileType(filename)) {
|
|
604
|
-
|
|
632
|
+
const rel = relative(process.cwd(), abs);
|
|
633
|
+
scheduleBuild(rel || abs);
|
|
605
634
|
}
|
|
606
635
|
});
|
|
607
636
|
watchers.push(watcher);
|
|
@@ -860,6 +889,7 @@ function readFormatSource(format) {
|
|
|
860
889
|
|
|
861
890
|
// src/loader.ts
|
|
862
891
|
import { basename } from "path";
|
|
892
|
+
import { statSync as statSync3 } from "fs";
|
|
863
893
|
|
|
864
894
|
// src/lexer.ts
|
|
865
895
|
var EOF = -1;
|
|
@@ -1175,7 +1205,7 @@ function parseTwee(source, options = {}) {
|
|
|
1175
1205
|
if (pCount > 1 && current) {
|
|
1176
1206
|
passages.push(current);
|
|
1177
1207
|
}
|
|
1178
|
-
current = { name: "", tags: [], text: "" };
|
|
1208
|
+
current = { name: "", tags: [], text: "", source: { file: filename, line: item.line } };
|
|
1179
1209
|
break;
|
|
1180
1210
|
case 3 /* Name */: {
|
|
1181
1211
|
if (!current) break;
|
|
@@ -1367,54 +1397,182 @@ function loadInlineSources(story, sources, opts, diagnostics) {
|
|
|
1367
1397
|
}
|
|
1368
1398
|
}
|
|
1369
1399
|
}
|
|
1370
|
-
function
|
|
1400
|
+
function parseTweeFile(filename, opts) {
|
|
1371
1401
|
const source = readUTF8(filename);
|
|
1372
1402
|
const result = parseTwee(source, {
|
|
1373
1403
|
filename,
|
|
1374
1404
|
trim: opts.trim ?? true,
|
|
1375
1405
|
twee2Compat: opts.twee2Compat ?? false
|
|
1376
1406
|
});
|
|
1377
|
-
diagnostics
|
|
1378
|
-
for (const p of result.passages) {
|
|
1379
|
-
storyAdd(story, p, diagnostics);
|
|
1380
|
-
}
|
|
1407
|
+
return { passages: result.passages, diagnostics: [...result.diagnostics] };
|
|
1381
1408
|
}
|
|
1382
|
-
function
|
|
1409
|
+
function parseTaggedFile(tag, filename) {
|
|
1383
1410
|
const source = readUTF8(filename);
|
|
1384
|
-
|
|
1411
|
+
return { passages: [{ name: basename(filename), tags: [tag], text: source }], diagnostics: [] };
|
|
1385
1412
|
}
|
|
1386
|
-
function
|
|
1413
|
+
function parseMediaFile(tag, filename) {
|
|
1387
1414
|
const source = readBase64(filename);
|
|
1388
1415
|
const name = baseNameWithoutExt(filename);
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
tags: [tag],
|
|
1394
|
-
text: `data:${mediaTypeFromFilename(filename)};base64,${source}`
|
|
1395
|
-
},
|
|
1396
|
-
diagnostics
|
|
1397
|
-
);
|
|
1416
|
+
return {
|
|
1417
|
+
passages: [{ name, tags: [tag], text: `data:${mediaTypeFromFilename(filename)};base64,${source}` }],
|
|
1418
|
+
diagnostics: []
|
|
1419
|
+
};
|
|
1398
1420
|
}
|
|
1399
|
-
function
|
|
1421
|
+
function parseFontFile(filename) {
|
|
1400
1422
|
const source = readBase64(filename);
|
|
1401
1423
|
const name = basename(filename);
|
|
1402
1424
|
const family = baseNameWithoutExt(filename);
|
|
1403
1425
|
const ext = normalizedFileExt(filename);
|
|
1404
1426
|
const mediaType = mediaTypeFromExt(ext);
|
|
1405
1427
|
const hint = fontFormatHint(ext);
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1428
|
+
return {
|
|
1429
|
+
passages: [
|
|
1430
|
+
{
|
|
1431
|
+
name,
|
|
1432
|
+
tags: ["stylesheet"],
|
|
1433
|
+
text: `@font-face {
|
|
1412
1434
|
font-family: "${family}";
|
|
1413
1435
|
src: url("data:${mediaType};base64,${source}") format("${hint}");
|
|
1414
1436
|
}`
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1437
|
+
}
|
|
1438
|
+
],
|
|
1439
|
+
diagnostics: []
|
|
1440
|
+
};
|
|
1441
|
+
}
|
|
1442
|
+
function parseFile(filename, opts) {
|
|
1443
|
+
const ext = normalizedFileExt(filename);
|
|
1444
|
+
switch (ext) {
|
|
1445
|
+
case "tw":
|
|
1446
|
+
case "twee":
|
|
1447
|
+
return parseTweeFile(filename, opts);
|
|
1448
|
+
case "tw2":
|
|
1449
|
+
case "twee2":
|
|
1450
|
+
return parseTweeFile(filename, { ...opts, twee2Compat: true });
|
|
1451
|
+
case "css":
|
|
1452
|
+
return parseTaggedFile("stylesheet", filename);
|
|
1453
|
+
case "js":
|
|
1454
|
+
return parseTaggedFile("script", filename);
|
|
1455
|
+
case "otf":
|
|
1456
|
+
case "ttf":
|
|
1457
|
+
case "woff":
|
|
1458
|
+
case "woff2":
|
|
1459
|
+
return parseFontFile(filename);
|
|
1460
|
+
case "gif":
|
|
1461
|
+
case "jpeg":
|
|
1462
|
+
case "jpg":
|
|
1463
|
+
case "png":
|
|
1464
|
+
case "svg":
|
|
1465
|
+
case "tif":
|
|
1466
|
+
case "tiff":
|
|
1467
|
+
case "webp":
|
|
1468
|
+
return parseMediaFile("Twine.image", filename);
|
|
1469
|
+
case "aac":
|
|
1470
|
+
case "flac":
|
|
1471
|
+
case "m4a":
|
|
1472
|
+
case "mp3":
|
|
1473
|
+
case "oga":
|
|
1474
|
+
case "ogg":
|
|
1475
|
+
case "opus":
|
|
1476
|
+
case "wav":
|
|
1477
|
+
case "wave":
|
|
1478
|
+
case "weba":
|
|
1479
|
+
return parseMediaFile("Twine.audio", filename);
|
|
1480
|
+
case "mp4":
|
|
1481
|
+
case "ogv":
|
|
1482
|
+
case "webm":
|
|
1483
|
+
return parseMediaFile("Twine.video", filename);
|
|
1484
|
+
case "vtt":
|
|
1485
|
+
return parseMediaFile("Twine.vtt", filename);
|
|
1486
|
+
default:
|
|
1487
|
+
return void 0;
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
function loadTwee(story, filename, opts, diagnostics) {
|
|
1491
|
+
const result = parseTweeFile(filename, opts);
|
|
1492
|
+
diagnostics.push(...result.diagnostics);
|
|
1493
|
+
for (const p of result.passages) {
|
|
1494
|
+
storyAdd(story, p, diagnostics);
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
function loadTagged(story, tag, filename, diagnostics) {
|
|
1498
|
+
const result = parseTaggedFile(tag, filename);
|
|
1499
|
+
for (const p of result.passages) {
|
|
1500
|
+
storyAdd(story, p, diagnostics);
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
function loadMedia(story, tag, filename, diagnostics) {
|
|
1504
|
+
const result = parseMediaFile(tag, filename);
|
|
1505
|
+
for (const p of result.passages) {
|
|
1506
|
+
storyAdd(story, p, diagnostics);
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
function loadFont(story, filename, diagnostics) {
|
|
1510
|
+
const result = parseFontFile(filename);
|
|
1511
|
+
for (const p of result.passages) {
|
|
1512
|
+
storyAdd(story, p, diagnostics);
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
function loadSourcesCached(story, filenames, opts, diagnostics, processedFiles, cache, changedFiles) {
|
|
1516
|
+
const currentFiles = /* @__PURE__ */ new Set();
|
|
1517
|
+
for (const filename of filenames) {
|
|
1518
|
+
if (processedFiles.has(filename)) {
|
|
1519
|
+
diagnostics.push({ level: "warning", message: `load ${filename}: Skipping duplicate.` });
|
|
1520
|
+
continue;
|
|
1521
|
+
}
|
|
1522
|
+
currentFiles.add(filename);
|
|
1523
|
+
const cached = cache.get(filename);
|
|
1524
|
+
if (changedFiles && cached && !changedFiles.has(filename)) {
|
|
1525
|
+
diagnostics.push(...cached.diagnostics);
|
|
1526
|
+
for (const p of cached.passages) {
|
|
1527
|
+
storyAdd(story, p, diagnostics);
|
|
1528
|
+
}
|
|
1529
|
+
processedFiles.add(filename);
|
|
1530
|
+
continue;
|
|
1531
|
+
}
|
|
1532
|
+
let mtimeMs;
|
|
1533
|
+
try {
|
|
1534
|
+
mtimeMs = statSync3(filename).mtimeMs;
|
|
1535
|
+
} catch {
|
|
1536
|
+
continue;
|
|
1537
|
+
}
|
|
1538
|
+
if (cached && cached.mtimeMs === mtimeMs) {
|
|
1539
|
+
diagnostics.push(...cached.diagnostics);
|
|
1540
|
+
for (const p of cached.passages) {
|
|
1541
|
+
storyAdd(story, p, diagnostics);
|
|
1542
|
+
}
|
|
1543
|
+
processedFiles.add(filename);
|
|
1544
|
+
continue;
|
|
1545
|
+
}
|
|
1546
|
+
try {
|
|
1547
|
+
const result = parseFile(filename, opts);
|
|
1548
|
+
if (!result) continue;
|
|
1549
|
+
cache.set(filename, {
|
|
1550
|
+
mtimeMs,
|
|
1551
|
+
passages: result.passages,
|
|
1552
|
+
diagnostics: result.diagnostics
|
|
1553
|
+
});
|
|
1554
|
+
diagnostics.push(...result.diagnostics);
|
|
1555
|
+
for (const p of result.passages) {
|
|
1556
|
+
storyAdd(story, p, diagnostics);
|
|
1557
|
+
}
|
|
1558
|
+
} catch (e) {
|
|
1559
|
+
diagnostics.push({
|
|
1560
|
+
level: "error",
|
|
1561
|
+
message: `load ${filename}: ${e instanceof Error ? e.message : String(e)}`,
|
|
1562
|
+
file: filename
|
|
1563
|
+
});
|
|
1564
|
+
continue;
|
|
1565
|
+
}
|
|
1566
|
+
processedFiles.add(filename);
|
|
1567
|
+
}
|
|
1568
|
+
for (const key of cache.keys()) {
|
|
1569
|
+
if (!currentFiles.has(key)) {
|
|
1570
|
+
cache.delete(key);
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
if (story.name !== "" && !story.passages.some((p) => p.name === "StoryTitle")) {
|
|
1574
|
+
storyPrepend(story, { name: "StoryTitle", tags: [], text: story.name }, diagnostics);
|
|
1575
|
+
}
|
|
1418
1576
|
}
|
|
1419
1577
|
|
|
1420
1578
|
// src/version.ts
|
|
@@ -1422,20 +1580,20 @@ var VERSION = "1.2.0";
|
|
|
1422
1580
|
|
|
1423
1581
|
// src/output-twine2.ts
|
|
1424
1582
|
var CREATOR_NAME = "Twee-ts";
|
|
1425
|
-
function toTwine2Archive(story, startName, diagnostics) {
|
|
1426
|
-
return getTwine2DataChunk(story, startName, diagnostics) + "\n";
|
|
1583
|
+
function toTwine2Archive(story, startName, diagnostics, options) {
|
|
1584
|
+
return getTwine2DataChunk(story, startName, diagnostics, options) + "\n";
|
|
1427
1585
|
}
|
|
1428
|
-
function toTwine2HTML(story, format, startName, diagnostics) {
|
|
1586
|
+
function toTwine2HTML(story, format, startName, diagnostics, options) {
|
|
1429
1587
|
let template = readFormatSource(format);
|
|
1430
1588
|
if (template.includes("{{STORY_NAME}}")) {
|
|
1431
1589
|
template = template.replaceAll("{{STORY_NAME}}", htmlEscape(story.name));
|
|
1432
1590
|
}
|
|
1433
1591
|
if (template.includes("{{STORY_DATA}}")) {
|
|
1434
|
-
template = template.replace("{{STORY_DATA}}", getTwine2DataChunk(story, startName, diagnostics));
|
|
1592
|
+
template = template.replace("{{STORY_DATA}}", getTwine2DataChunk(story, startName, diagnostics, options));
|
|
1435
1593
|
}
|
|
1436
1594
|
return template;
|
|
1437
1595
|
}
|
|
1438
|
-
function getTwine2DataChunk(story, startName, diagnostics) {
|
|
1596
|
+
function getTwine2DataChunk(story, startName, diagnostics, options) {
|
|
1439
1597
|
ensureIFID(story, diagnostics);
|
|
1440
1598
|
const parts = [];
|
|
1441
1599
|
let startID = "";
|
|
@@ -1490,7 +1648,7 @@ function getTwine2DataChunk(story, startName, diagnostics) {
|
|
|
1490
1648
|
if (p.name === "StorySettings" && story.twine1.settings.size === 0) {
|
|
1491
1649
|
continue;
|
|
1492
1650
|
}
|
|
1493
|
-
parts.push(passageToPassagedata(p, pid));
|
|
1651
|
+
parts.push(passageToPassagedata(p, pid, options));
|
|
1494
1652
|
if (startName === p.name) {
|
|
1495
1653
|
startID = String(pid);
|
|
1496
1654
|
}
|
|
@@ -1500,9 +1658,9 @@ function getTwine2DataChunk(story, startName, diagnostics) {
|
|
|
1500
1658
|
for (const [opt, val] of story.twine2.options) {
|
|
1501
1659
|
if (val) opts.push(opt);
|
|
1502
1660
|
}
|
|
1503
|
-
const
|
|
1661
|
+
const optionsStr = opts.join(" ");
|
|
1504
1662
|
const zoom = String(story.twine2.zoom);
|
|
1505
|
-
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(
|
|
1663
|
+
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>`;
|
|
1506
1664
|
return wrapper + parts.join("") + "</tw-storydata>";
|
|
1507
1665
|
}
|
|
1508
1666
|
function ensureIFID(story, diagnostics) {
|
|
@@ -1683,7 +1841,7 @@ function modifyHead(html, modulePaths, headFile, diagnostics) {
|
|
|
1683
1841
|
}
|
|
1684
1842
|
|
|
1685
1843
|
// src/remote-formats.ts
|
|
1686
|
-
import { mkdirSync, readFileSync as readFileSync3, writeFileSync, existsSync, readdirSync as readdirSync3, statSync as
|
|
1844
|
+
import { mkdirSync, readFileSync as readFileSync3, writeFileSync, existsSync, readdirSync as readdirSync3, statSync as statSync4 } from "fs";
|
|
1687
1845
|
import { join as join4 } from "path";
|
|
1688
1846
|
import { homedir as homedir2 } from "os";
|
|
1689
1847
|
var DEFAULT_SFA_INDICES = [
|
|
@@ -1895,7 +2053,7 @@ function discoverCachedFormats() {
|
|
|
1895
2053
|
for (const name of names) {
|
|
1896
2054
|
const nameDir = join4(cacheDir, name);
|
|
1897
2055
|
try {
|
|
1898
|
-
if (!
|
|
2056
|
+
if (!statSync4(nameDir).isDirectory()) continue;
|
|
1899
2057
|
} catch {
|
|
1900
2058
|
continue;
|
|
1901
2059
|
}
|
|
@@ -1936,11 +2094,12 @@ async function compileToFile(options) {
|
|
|
1936
2094
|
}
|
|
1937
2095
|
async function watch(options) {
|
|
1938
2096
|
const controller = new AbortController();
|
|
2097
|
+
const cache = /* @__PURE__ */ new Map();
|
|
1939
2098
|
const filePaths = options.sources.filter((s) => typeof s === "string");
|
|
1940
2099
|
const modulePaths = options.modules ?? [];
|
|
1941
2100
|
const allPaths = [...filePaths, ...modulePaths];
|
|
1942
|
-
const handle = watchFilesystem(allPaths, options.outFile, () => {
|
|
1943
|
-
buildOutput(options).then((result) => {
|
|
2101
|
+
const handle = watchFilesystem(allPaths, options.outFile, (changedFiles) => {
|
|
2102
|
+
buildOutput(options, cache, changedFiles).then((result) => {
|
|
1944
2103
|
writeFileSync2(options.outFile, result.output, "utf-8");
|
|
1945
2104
|
options.onBuild?.(result);
|
|
1946
2105
|
}).catch((e) => {
|
|
@@ -1950,13 +2109,14 @@ async function watch(options) {
|
|
|
1950
2109
|
controller.signal.addEventListener("abort", () => handle.close());
|
|
1951
2110
|
return controller;
|
|
1952
2111
|
}
|
|
1953
|
-
async function buildOutput(options) {
|
|
2112
|
+
async function buildOutput(options, cache, changedFiles) {
|
|
1954
2113
|
const diagnostics = [];
|
|
1955
2114
|
const outputMode = options.outputMode ?? "html";
|
|
1956
2115
|
const trim = options.trim ?? true;
|
|
1957
2116
|
const twee2Compat = options.twee2Compat ?? false;
|
|
1958
2117
|
const testMode = options.testMode ?? false;
|
|
1959
2118
|
const noRemote = options.noRemote ?? false;
|
|
2119
|
+
const sourceInfo = options.sourceInfo ?? false;
|
|
1960
2120
|
clearIndexCache();
|
|
1961
2121
|
const filePaths = [];
|
|
1962
2122
|
const inlineSources = [];
|
|
@@ -1970,7 +2130,11 @@ async function buildOutput(options) {
|
|
|
1970
2130
|
const sourceFilenames = getFilenames(filePaths);
|
|
1971
2131
|
const story = createStory();
|
|
1972
2132
|
const processedFiles = /* @__PURE__ */ new Set();
|
|
1973
|
-
|
|
2133
|
+
if (cache) {
|
|
2134
|
+
loadSourcesCached(story, sourceFilenames, { trim, twee2Compat }, diagnostics, processedFiles, cache, changedFiles);
|
|
2135
|
+
} else {
|
|
2136
|
+
loadSources(story, sourceFilenames, { trim, twee2Compat }, diagnostics, processedFiles);
|
|
2137
|
+
}
|
|
1974
2138
|
loadInlineSources(story, inlineSources, { trim, twee2Compat }, diagnostics);
|
|
1975
2139
|
if (options.tagAliases) {
|
|
1976
2140
|
story.passages = applyTagAliases(story.passages, options.tagAliases);
|
|
@@ -2018,7 +2182,7 @@ async function buildOutput(options) {
|
|
|
2018
2182
|
output = toTwee(story, outputMode);
|
|
2019
2183
|
break;
|
|
2020
2184
|
case "twine2-archive":
|
|
2021
|
-
output = toTwine2Archive(story, startName, diagnostics);
|
|
2185
|
+
output = toTwine2Archive(story, startName, diagnostics, { sourceInfo });
|
|
2022
2186
|
break;
|
|
2023
2187
|
case "twine1-archive":
|
|
2024
2188
|
output = toTwine1Archive(story, startName);
|
|
@@ -2037,7 +2201,7 @@ async function buildOutput(options) {
|
|
|
2037
2201
|
throw new TweeTsError("No story format available for HTML output.", diagnostics);
|
|
2038
2202
|
}
|
|
2039
2203
|
if (format.isTwine2) {
|
|
2040
|
-
output = toTwine2HTML(story, format, startName, diagnostics);
|
|
2204
|
+
output = toTwine2HTML(story, format, startName, diagnostics, { sourceInfo });
|
|
2041
2205
|
} else {
|
|
2042
2206
|
if (story.name === "" && !storyHas(story, "StoryTitle")) {
|
|
2043
2207
|
diagnostics.push({
|
|
@@ -2168,7 +2332,7 @@ function validateConfig(data) {
|
|
|
2168
2332
|
errors.push(`"${key}" must be a string.`);
|
|
2169
2333
|
}
|
|
2170
2334
|
}
|
|
2171
|
-
for (const key of ["useTweegoPath", "trim", "twee2Compat", "testMode", "noRemote"]) {
|
|
2335
|
+
for (const key of ["useTweegoPath", "trim", "twee2Compat", "testMode", "noRemote", "sourceInfo"]) {
|
|
2172
2336
|
if (key in obj && typeof obj[key] !== "boolean") {
|
|
2173
2337
|
errors.push(`"${key}" must be a boolean.`);
|
|
2174
2338
|
}
|
|
@@ -2238,6 +2402,7 @@ var { values, positionals } = parseArgs({
|
|
|
2238
2402
|
"format-url": { type: "string", multiple: true },
|
|
2239
2403
|
"no-remote": { type: "boolean" },
|
|
2240
2404
|
"tag-alias": { type: "string", multiple: true },
|
|
2405
|
+
"source-info": { type: "boolean" },
|
|
2241
2406
|
config: { type: "string", short: "c" },
|
|
2242
2407
|
"no-config": { type: "boolean" }
|
|
2243
2408
|
}
|
|
@@ -2306,7 +2471,8 @@ async function main() {
|
|
|
2306
2471
|
formatIndices: values["format-index"] ?? config?.formatIndices,
|
|
2307
2472
|
formatUrls: values["format-url"] ?? config?.formatUrls,
|
|
2308
2473
|
noRemote: values["no-remote"] ?? config?.noRemote ?? false,
|
|
2309
|
-
tagAliases
|
|
2474
|
+
tagAliases,
|
|
2475
|
+
sourceInfo: values["source-info"] ?? config?.sourceInfo ?? false
|
|
2310
2476
|
};
|
|
2311
2477
|
const outFile = values.output ?? config?.output ?? "-";
|
|
2312
2478
|
if (values.watch) {
|
|
@@ -2432,6 +2598,7 @@ Options:
|
|
|
2432
2598
|
--format-index <url> SFA-compatible format index URL (repeatable)
|
|
2433
2599
|
--format-url <url> Direct format.js URL (repeatable)
|
|
2434
2600
|
--tag-alias <alias=target> Map a tag to a special tag (repeatable)
|
|
2601
|
+
--source-info Emit source file/line as data- attributes on passages
|
|
2435
2602
|
--no-remote Disable remote format fetching
|
|
2436
2603
|
-c, --config <file> Config file path (default: ${CONFIG_FILENAME})
|
|
2437
2604
|
--no-config Skip config file loading
|