@rohal12/twee-ts 1.5.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 +202 -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 +221 -62
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +202 -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.js
CHANGED
|
@@ -258,8 +258,21 @@ function quote(s) {
|
|
|
258
258
|
}
|
|
259
259
|
|
|
260
260
|
// src/story.ts
|
|
261
|
+
var passageIndex = /* @__PURE__ */ new WeakMap();
|
|
262
|
+
function getIndex(story) {
|
|
263
|
+
let index = passageIndex.get(story);
|
|
264
|
+
if (!index) {
|
|
265
|
+
index = /* @__PURE__ */ new Map();
|
|
266
|
+
for (let i = 0; i < story.passages.length; i++) {
|
|
267
|
+
const passage = story.passages[i];
|
|
268
|
+
if (passage) index.set(passage.name, i);
|
|
269
|
+
}
|
|
270
|
+
passageIndex.set(story, index);
|
|
271
|
+
}
|
|
272
|
+
return index;
|
|
273
|
+
}
|
|
261
274
|
function createStory() {
|
|
262
|
-
|
|
275
|
+
const story = {
|
|
263
276
|
name: "",
|
|
264
277
|
ifid: "",
|
|
265
278
|
passages: [],
|
|
@@ -275,16 +288,17 @@ function createStory() {
|
|
|
275
288
|
zoom: 1
|
|
276
289
|
}
|
|
277
290
|
};
|
|
291
|
+
passageIndex.set(story, /* @__PURE__ */ new Map());
|
|
292
|
+
return story;
|
|
278
293
|
}
|
|
279
294
|
function storyHas(story, name) {
|
|
280
|
-
return story.
|
|
281
|
-
}
|
|
282
|
-
function storyIndex(story, name) {
|
|
283
|
-
return story.passages.findIndex((p) => p.name === name);
|
|
295
|
+
return getIndex(story).has(name);
|
|
284
296
|
}
|
|
285
297
|
function storyAppend(story, p, diagnostics) {
|
|
286
|
-
const
|
|
298
|
+
const index = getIndex(story);
|
|
299
|
+
const i = index.get(p.name) ?? -1;
|
|
287
300
|
if (i === -1) {
|
|
301
|
+
index.set(p.name, story.passages.length);
|
|
288
302
|
story.passages.push(p);
|
|
289
303
|
} else {
|
|
290
304
|
diagnostics.push({
|
|
@@ -295,9 +309,15 @@ function storyAppend(story, p, diagnostics) {
|
|
|
295
309
|
}
|
|
296
310
|
}
|
|
297
311
|
function storyPrepend(story, p, diagnostics) {
|
|
298
|
-
const
|
|
312
|
+
const index = getIndex(story);
|
|
313
|
+
const i = index.get(p.name) ?? -1;
|
|
299
314
|
if (i === -1) {
|
|
300
315
|
story.passages.unshift(p);
|
|
316
|
+
index.clear();
|
|
317
|
+
for (let j = 0; j < story.passages.length; j++) {
|
|
318
|
+
const passage = story.passages[j];
|
|
319
|
+
if (passage) index.set(passage.name, j);
|
|
320
|
+
}
|
|
301
321
|
} else {
|
|
302
322
|
diagnostics.push({
|
|
303
323
|
level: "warning",
|
|
@@ -587,11 +607,15 @@ function watchFilesystem(pathnames, outFilename, callback) {
|
|
|
587
607
|
const watchers = [];
|
|
588
608
|
let buildTimer = null;
|
|
589
609
|
const BUILD_DEBOUNCE = 500;
|
|
590
|
-
|
|
610
|
+
const pendingFiles = /* @__PURE__ */ new Set();
|
|
611
|
+
function scheduleBuild(changedFile) {
|
|
612
|
+
if (changedFile) pendingFiles.add(changedFile);
|
|
591
613
|
if (buildTimer) clearTimeout(buildTimer);
|
|
592
614
|
buildTimer = setTimeout(() => {
|
|
593
615
|
buildTimer = null;
|
|
594
|
-
|
|
616
|
+
const files = pendingFiles.size > 0 ? new Set(pendingFiles) : void 0;
|
|
617
|
+
pendingFiles.clear();
|
|
618
|
+
callback(files);
|
|
595
619
|
}, BUILD_DEBOUNCE);
|
|
596
620
|
}
|
|
597
621
|
for (const pathname of pathnames) {
|
|
@@ -601,7 +625,8 @@ function watchFilesystem(pathnames, outFilename, callback) {
|
|
|
601
625
|
const abs = resolve(pathname, filename);
|
|
602
626
|
if (abs === absOutFile) return;
|
|
603
627
|
if (isKnownFileType(filename)) {
|
|
604
|
-
|
|
628
|
+
const rel = relative(process.cwd(), abs);
|
|
629
|
+
scheduleBuild(rel || abs);
|
|
605
630
|
}
|
|
606
631
|
});
|
|
607
632
|
watchers.push(watcher);
|
|
@@ -860,6 +885,7 @@ function readFormatSource(format) {
|
|
|
860
885
|
|
|
861
886
|
// src/loader.ts
|
|
862
887
|
import { basename } from "path";
|
|
888
|
+
import { statSync as statSync3 } from "fs";
|
|
863
889
|
|
|
864
890
|
// src/lexer.ts
|
|
865
891
|
var EOF = -1;
|
|
@@ -1383,54 +1409,182 @@ function loadInlineSources(story, sources, opts, diagnostics) {
|
|
|
1383
1409
|
}
|
|
1384
1410
|
}
|
|
1385
1411
|
}
|
|
1386
|
-
function
|
|
1412
|
+
function parseTweeFile(filename, opts) {
|
|
1387
1413
|
const source = readUTF8(filename);
|
|
1388
1414
|
const result = parseTwee(source, {
|
|
1389
1415
|
filename,
|
|
1390
1416
|
trim: opts.trim ?? true,
|
|
1391
1417
|
twee2Compat: opts.twee2Compat ?? false
|
|
1392
1418
|
});
|
|
1393
|
-
diagnostics
|
|
1394
|
-
for (const p of result.passages) {
|
|
1395
|
-
storyAdd(story, p, diagnostics);
|
|
1396
|
-
}
|
|
1419
|
+
return { passages: result.passages, diagnostics: [...result.diagnostics] };
|
|
1397
1420
|
}
|
|
1398
|
-
function
|
|
1421
|
+
function parseTaggedFile(tag, filename) {
|
|
1399
1422
|
const source = readUTF8(filename);
|
|
1400
|
-
|
|
1423
|
+
return { passages: [{ name: basename(filename), tags: [tag], text: source }], diagnostics: [] };
|
|
1401
1424
|
}
|
|
1402
|
-
function
|
|
1425
|
+
function parseMediaFile(tag, filename) {
|
|
1403
1426
|
const source = readBase64(filename);
|
|
1404
1427
|
const name = baseNameWithoutExt(filename);
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
tags: [tag],
|
|
1410
|
-
text: `data:${mediaTypeFromFilename(filename)};base64,${source}`
|
|
1411
|
-
},
|
|
1412
|
-
diagnostics
|
|
1413
|
-
);
|
|
1428
|
+
return {
|
|
1429
|
+
passages: [{ name, tags: [tag], text: `data:${mediaTypeFromFilename(filename)};base64,${source}` }],
|
|
1430
|
+
diagnostics: []
|
|
1431
|
+
};
|
|
1414
1432
|
}
|
|
1415
|
-
function
|
|
1433
|
+
function parseFontFile(filename) {
|
|
1416
1434
|
const source = readBase64(filename);
|
|
1417
1435
|
const name = basename(filename);
|
|
1418
1436
|
const family = baseNameWithoutExt(filename);
|
|
1419
1437
|
const ext = normalizedFileExt(filename);
|
|
1420
1438
|
const mediaType = mediaTypeFromExt(ext);
|
|
1421
1439
|
const hint = fontFormatHint(ext);
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1440
|
+
return {
|
|
1441
|
+
passages: [
|
|
1442
|
+
{
|
|
1443
|
+
name,
|
|
1444
|
+
tags: ["stylesheet"],
|
|
1445
|
+
text: `@font-face {
|
|
1428
1446
|
font-family: "${family}";
|
|
1429
1447
|
src: url("data:${mediaType};base64,${source}") format("${hint}");
|
|
1430
1448
|
}`
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1449
|
+
}
|
|
1450
|
+
],
|
|
1451
|
+
diagnostics: []
|
|
1452
|
+
};
|
|
1453
|
+
}
|
|
1454
|
+
function parseFile(filename, opts) {
|
|
1455
|
+
const ext = normalizedFileExt(filename);
|
|
1456
|
+
switch (ext) {
|
|
1457
|
+
case "tw":
|
|
1458
|
+
case "twee":
|
|
1459
|
+
return parseTweeFile(filename, opts);
|
|
1460
|
+
case "tw2":
|
|
1461
|
+
case "twee2":
|
|
1462
|
+
return parseTweeFile(filename, { ...opts, twee2Compat: true });
|
|
1463
|
+
case "css":
|
|
1464
|
+
return parseTaggedFile("stylesheet", filename);
|
|
1465
|
+
case "js":
|
|
1466
|
+
return parseTaggedFile("script", filename);
|
|
1467
|
+
case "otf":
|
|
1468
|
+
case "ttf":
|
|
1469
|
+
case "woff":
|
|
1470
|
+
case "woff2":
|
|
1471
|
+
return parseFontFile(filename);
|
|
1472
|
+
case "gif":
|
|
1473
|
+
case "jpeg":
|
|
1474
|
+
case "jpg":
|
|
1475
|
+
case "png":
|
|
1476
|
+
case "svg":
|
|
1477
|
+
case "tif":
|
|
1478
|
+
case "tiff":
|
|
1479
|
+
case "webp":
|
|
1480
|
+
return parseMediaFile("Twine.image", filename);
|
|
1481
|
+
case "aac":
|
|
1482
|
+
case "flac":
|
|
1483
|
+
case "m4a":
|
|
1484
|
+
case "mp3":
|
|
1485
|
+
case "oga":
|
|
1486
|
+
case "ogg":
|
|
1487
|
+
case "opus":
|
|
1488
|
+
case "wav":
|
|
1489
|
+
case "wave":
|
|
1490
|
+
case "weba":
|
|
1491
|
+
return parseMediaFile("Twine.audio", filename);
|
|
1492
|
+
case "mp4":
|
|
1493
|
+
case "ogv":
|
|
1494
|
+
case "webm":
|
|
1495
|
+
return parseMediaFile("Twine.video", filename);
|
|
1496
|
+
case "vtt":
|
|
1497
|
+
return parseMediaFile("Twine.vtt", filename);
|
|
1498
|
+
default:
|
|
1499
|
+
return void 0;
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
function loadTwee(story, filename, opts, diagnostics) {
|
|
1503
|
+
const result = parseTweeFile(filename, opts);
|
|
1504
|
+
diagnostics.push(...result.diagnostics);
|
|
1505
|
+
for (const p of result.passages) {
|
|
1506
|
+
storyAdd(story, p, diagnostics);
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
function loadTagged(story, tag, filename, diagnostics) {
|
|
1510
|
+
const result = parseTaggedFile(tag, filename);
|
|
1511
|
+
for (const p of result.passages) {
|
|
1512
|
+
storyAdd(story, p, diagnostics);
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
function loadMedia(story, tag, filename, diagnostics) {
|
|
1516
|
+
const result = parseMediaFile(tag, filename);
|
|
1517
|
+
for (const p of result.passages) {
|
|
1518
|
+
storyAdd(story, p, diagnostics);
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
function loadFont(story, filename, diagnostics) {
|
|
1522
|
+
const result = parseFontFile(filename);
|
|
1523
|
+
for (const p of result.passages) {
|
|
1524
|
+
storyAdd(story, p, diagnostics);
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
function loadSourcesCached(story, filenames, opts, diagnostics, processedFiles, cache, changedFiles) {
|
|
1528
|
+
const currentFiles = /* @__PURE__ */ new Set();
|
|
1529
|
+
for (const filename of filenames) {
|
|
1530
|
+
if (processedFiles.has(filename)) {
|
|
1531
|
+
diagnostics.push({ level: "warning", message: `load ${filename}: Skipping duplicate.` });
|
|
1532
|
+
continue;
|
|
1533
|
+
}
|
|
1534
|
+
currentFiles.add(filename);
|
|
1535
|
+
const cached = cache.get(filename);
|
|
1536
|
+
if (changedFiles && cached && !changedFiles.has(filename)) {
|
|
1537
|
+
diagnostics.push(...cached.diagnostics);
|
|
1538
|
+
for (const p of cached.passages) {
|
|
1539
|
+
storyAdd(story, p, diagnostics);
|
|
1540
|
+
}
|
|
1541
|
+
processedFiles.add(filename);
|
|
1542
|
+
continue;
|
|
1543
|
+
}
|
|
1544
|
+
let mtimeMs;
|
|
1545
|
+
try {
|
|
1546
|
+
mtimeMs = statSync3(filename).mtimeMs;
|
|
1547
|
+
} catch {
|
|
1548
|
+
continue;
|
|
1549
|
+
}
|
|
1550
|
+
if (cached && cached.mtimeMs === mtimeMs) {
|
|
1551
|
+
diagnostics.push(...cached.diagnostics);
|
|
1552
|
+
for (const p of cached.passages) {
|
|
1553
|
+
storyAdd(story, p, diagnostics);
|
|
1554
|
+
}
|
|
1555
|
+
processedFiles.add(filename);
|
|
1556
|
+
continue;
|
|
1557
|
+
}
|
|
1558
|
+
try {
|
|
1559
|
+
const result = parseFile(filename, opts);
|
|
1560
|
+
if (!result) continue;
|
|
1561
|
+
cache.set(filename, {
|
|
1562
|
+
mtimeMs,
|
|
1563
|
+
passages: result.passages,
|
|
1564
|
+
diagnostics: result.diagnostics
|
|
1565
|
+
});
|
|
1566
|
+
diagnostics.push(...result.diagnostics);
|
|
1567
|
+
for (const p of result.passages) {
|
|
1568
|
+
storyAdd(story, p, diagnostics);
|
|
1569
|
+
}
|
|
1570
|
+
} catch (e) {
|
|
1571
|
+
diagnostics.push({
|
|
1572
|
+
level: "error",
|
|
1573
|
+
message: `load ${filename}: ${e instanceof Error ? e.message : String(e)}`,
|
|
1574
|
+
file: filename
|
|
1575
|
+
});
|
|
1576
|
+
continue;
|
|
1577
|
+
}
|
|
1578
|
+
processedFiles.add(filename);
|
|
1579
|
+
}
|
|
1580
|
+
for (const key of cache.keys()) {
|
|
1581
|
+
if (!currentFiles.has(key)) {
|
|
1582
|
+
cache.delete(key);
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
if (story.name !== "" && !story.passages.some((p) => p.name === "StoryTitle")) {
|
|
1586
|
+
storyPrepend(story, { name: "StoryTitle", tags: [], text: story.name }, diagnostics);
|
|
1587
|
+
}
|
|
1434
1588
|
}
|
|
1435
1589
|
|
|
1436
1590
|
// src/version.ts
|
|
@@ -1699,7 +1853,7 @@ function modifyHead(html, modulePaths, headFile, diagnostics) {
|
|
|
1699
1853
|
}
|
|
1700
1854
|
|
|
1701
1855
|
// src/remote-formats.ts
|
|
1702
|
-
import { mkdirSync, readFileSync as readFileSync3, writeFileSync, existsSync, readdirSync as readdirSync3, statSync as
|
|
1856
|
+
import { mkdirSync, readFileSync as readFileSync3, writeFileSync, existsSync, readdirSync as readdirSync3, statSync as statSync4 } from "fs";
|
|
1703
1857
|
import { join as join4 } from "path";
|
|
1704
1858
|
import { homedir as homedir2 } from "os";
|
|
1705
1859
|
var DEFAULT_SFA_INDICES = [
|
|
@@ -1911,7 +2065,7 @@ function discoverCachedFormats() {
|
|
|
1911
2065
|
for (const name of names) {
|
|
1912
2066
|
const nameDir = join4(cacheDir, name);
|
|
1913
2067
|
try {
|
|
1914
|
-
if (!
|
|
2068
|
+
if (!statSync4(nameDir).isDirectory()) continue;
|
|
1915
2069
|
} catch {
|
|
1916
2070
|
continue;
|
|
1917
2071
|
}
|
|
@@ -1952,11 +2106,12 @@ async function compileToFile(options) {
|
|
|
1952
2106
|
}
|
|
1953
2107
|
async function watch(options) {
|
|
1954
2108
|
const controller = new AbortController();
|
|
2109
|
+
const cache = /* @__PURE__ */ new Map();
|
|
1955
2110
|
const filePaths = options.sources.filter((s) => typeof s === "string");
|
|
1956
2111
|
const modulePaths = options.modules ?? [];
|
|
1957
2112
|
const allPaths = [...filePaths, ...modulePaths];
|
|
1958
|
-
const handle = watchFilesystem(allPaths, options.outFile, () => {
|
|
1959
|
-
buildOutput(options).then((result) => {
|
|
2113
|
+
const handle = watchFilesystem(allPaths, options.outFile, (changedFiles) => {
|
|
2114
|
+
buildOutput(options, cache, changedFiles).then((result) => {
|
|
1960
2115
|
writeFileSync2(options.outFile, result.output, "utf-8");
|
|
1961
2116
|
options.onBuild?.(result);
|
|
1962
2117
|
}).catch((e) => {
|
|
@@ -1966,7 +2121,7 @@ async function watch(options) {
|
|
|
1966
2121
|
controller.signal.addEventListener("abort", () => handle.close());
|
|
1967
2122
|
return controller;
|
|
1968
2123
|
}
|
|
1969
|
-
async function buildOutput(options) {
|
|
2124
|
+
async function buildOutput(options, cache, changedFiles) {
|
|
1970
2125
|
const diagnostics = [];
|
|
1971
2126
|
const outputMode = options.outputMode ?? "html";
|
|
1972
2127
|
const trim = options.trim ?? true;
|
|
@@ -1987,7 +2142,11 @@ async function buildOutput(options) {
|
|
|
1987
2142
|
const sourceFilenames = getFilenames(filePaths);
|
|
1988
2143
|
const story = createStory();
|
|
1989
2144
|
const processedFiles = /* @__PURE__ */ new Set();
|
|
1990
|
-
|
|
2145
|
+
if (cache) {
|
|
2146
|
+
loadSourcesCached(story, sourceFilenames, { trim, twee2Compat }, diagnostics, processedFiles, cache, changedFiles);
|
|
2147
|
+
} else {
|
|
2148
|
+
loadSources(story, sourceFilenames, { trim, twee2Compat }, diagnostics, processedFiles);
|
|
2149
|
+
}
|
|
1991
2150
|
loadInlineSources(story, inlineSources, { trim, twee2Compat }, diagnostics);
|
|
1992
2151
|
if (options.tagAliases) {
|
|
1993
2152
|
story.passages = applyTagAliases(story.passages, options.tagAliases);
|