@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/bin/twee-ts.js
CHANGED
|
@@ -262,8 +262,21 @@ function quote(s) {
|
|
|
262
262
|
}
|
|
263
263
|
|
|
264
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
|
+
}
|
|
265
278
|
function createStory() {
|
|
266
|
-
|
|
279
|
+
const story = {
|
|
267
280
|
name: "",
|
|
268
281
|
ifid: "",
|
|
269
282
|
passages: [],
|
|
@@ -279,16 +292,17 @@ function createStory() {
|
|
|
279
292
|
zoom: 1
|
|
280
293
|
}
|
|
281
294
|
};
|
|
295
|
+
passageIndex.set(story, /* @__PURE__ */ new Map());
|
|
296
|
+
return story;
|
|
282
297
|
}
|
|
283
298
|
function storyHas(story, name) {
|
|
284
|
-
return story.
|
|
285
|
-
}
|
|
286
|
-
function storyIndex(story, name) {
|
|
287
|
-
return story.passages.findIndex((p) => p.name === name);
|
|
299
|
+
return getIndex(story).has(name);
|
|
288
300
|
}
|
|
289
301
|
function storyAppend(story, p, diagnostics) {
|
|
290
|
-
const
|
|
302
|
+
const index = getIndex(story);
|
|
303
|
+
const i = index.get(p.name) ?? -1;
|
|
291
304
|
if (i === -1) {
|
|
305
|
+
index.set(p.name, story.passages.length);
|
|
292
306
|
story.passages.push(p);
|
|
293
307
|
} else {
|
|
294
308
|
diagnostics.push({
|
|
@@ -299,9 +313,15 @@ function storyAppend(story, p, diagnostics) {
|
|
|
299
313
|
}
|
|
300
314
|
}
|
|
301
315
|
function storyPrepend(story, p, diagnostics) {
|
|
302
|
-
const
|
|
316
|
+
const index = getIndex(story);
|
|
317
|
+
const i = index.get(p.name) ?? -1;
|
|
303
318
|
if (i === -1) {
|
|
304
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
|
+
}
|
|
305
325
|
} else {
|
|
306
326
|
diagnostics.push({
|
|
307
327
|
level: "warning",
|
|
@@ -591,11 +611,15 @@ function watchFilesystem(pathnames, outFilename, callback) {
|
|
|
591
611
|
const watchers = [];
|
|
592
612
|
let buildTimer = null;
|
|
593
613
|
const BUILD_DEBOUNCE = 500;
|
|
594
|
-
|
|
614
|
+
const pendingFiles = /* @__PURE__ */ new Set();
|
|
615
|
+
function scheduleBuild(changedFile) {
|
|
616
|
+
if (changedFile) pendingFiles.add(changedFile);
|
|
595
617
|
if (buildTimer) clearTimeout(buildTimer);
|
|
596
618
|
buildTimer = setTimeout(() => {
|
|
597
619
|
buildTimer = null;
|
|
598
|
-
|
|
620
|
+
const files = pendingFiles.size > 0 ? new Set(pendingFiles) : void 0;
|
|
621
|
+
pendingFiles.clear();
|
|
622
|
+
callback(files);
|
|
599
623
|
}, BUILD_DEBOUNCE);
|
|
600
624
|
}
|
|
601
625
|
for (const pathname of pathnames) {
|
|
@@ -605,7 +629,8 @@ function watchFilesystem(pathnames, outFilename, callback) {
|
|
|
605
629
|
const abs = resolve(pathname, filename);
|
|
606
630
|
if (abs === absOutFile) return;
|
|
607
631
|
if (isKnownFileType(filename)) {
|
|
608
|
-
|
|
632
|
+
const rel = relative(process.cwd(), abs);
|
|
633
|
+
scheduleBuild(rel || abs);
|
|
609
634
|
}
|
|
610
635
|
});
|
|
611
636
|
watchers.push(watcher);
|
|
@@ -864,6 +889,7 @@ function readFormatSource(format) {
|
|
|
864
889
|
|
|
865
890
|
// src/loader.ts
|
|
866
891
|
import { basename } from "path";
|
|
892
|
+
import { statSync as statSync3 } from "fs";
|
|
867
893
|
|
|
868
894
|
// src/lexer.ts
|
|
869
895
|
var EOF = -1;
|
|
@@ -1371,54 +1397,182 @@ function loadInlineSources(story, sources, opts, diagnostics) {
|
|
|
1371
1397
|
}
|
|
1372
1398
|
}
|
|
1373
1399
|
}
|
|
1374
|
-
function
|
|
1400
|
+
function parseTweeFile(filename, opts) {
|
|
1375
1401
|
const source = readUTF8(filename);
|
|
1376
1402
|
const result = parseTwee(source, {
|
|
1377
1403
|
filename,
|
|
1378
1404
|
trim: opts.trim ?? true,
|
|
1379
1405
|
twee2Compat: opts.twee2Compat ?? false
|
|
1380
1406
|
});
|
|
1381
|
-
diagnostics
|
|
1382
|
-
for (const p of result.passages) {
|
|
1383
|
-
storyAdd(story, p, diagnostics);
|
|
1384
|
-
}
|
|
1407
|
+
return { passages: result.passages, diagnostics: [...result.diagnostics] };
|
|
1385
1408
|
}
|
|
1386
|
-
function
|
|
1409
|
+
function parseTaggedFile(tag, filename) {
|
|
1387
1410
|
const source = readUTF8(filename);
|
|
1388
|
-
|
|
1411
|
+
return { passages: [{ name: basename(filename), tags: [tag], text: source }], diagnostics: [] };
|
|
1389
1412
|
}
|
|
1390
|
-
function
|
|
1413
|
+
function parseMediaFile(tag, filename) {
|
|
1391
1414
|
const source = readBase64(filename);
|
|
1392
1415
|
const name = baseNameWithoutExt(filename);
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
tags: [tag],
|
|
1398
|
-
text: `data:${mediaTypeFromFilename(filename)};base64,${source}`
|
|
1399
|
-
},
|
|
1400
|
-
diagnostics
|
|
1401
|
-
);
|
|
1416
|
+
return {
|
|
1417
|
+
passages: [{ name, tags: [tag], text: `data:${mediaTypeFromFilename(filename)};base64,${source}` }],
|
|
1418
|
+
diagnostics: []
|
|
1419
|
+
};
|
|
1402
1420
|
}
|
|
1403
|
-
function
|
|
1421
|
+
function parseFontFile(filename) {
|
|
1404
1422
|
const source = readBase64(filename);
|
|
1405
1423
|
const name = basename(filename);
|
|
1406
1424
|
const family = baseNameWithoutExt(filename);
|
|
1407
1425
|
const ext = normalizedFileExt(filename);
|
|
1408
1426
|
const mediaType = mediaTypeFromExt(ext);
|
|
1409
1427
|
const hint = fontFormatHint(ext);
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1428
|
+
return {
|
|
1429
|
+
passages: [
|
|
1430
|
+
{
|
|
1431
|
+
name,
|
|
1432
|
+
tags: ["stylesheet"],
|
|
1433
|
+
text: `@font-face {
|
|
1416
1434
|
font-family: "${family}";
|
|
1417
1435
|
src: url("data:${mediaType};base64,${source}") format("${hint}");
|
|
1418
1436
|
}`
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
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
|
+
}
|
|
1422
1576
|
}
|
|
1423
1577
|
|
|
1424
1578
|
// src/version.ts
|
|
@@ -1687,7 +1841,7 @@ function modifyHead(html, modulePaths, headFile, diagnostics) {
|
|
|
1687
1841
|
}
|
|
1688
1842
|
|
|
1689
1843
|
// src/remote-formats.ts
|
|
1690
|
-
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";
|
|
1691
1845
|
import { join as join4 } from "path";
|
|
1692
1846
|
import { homedir as homedir2 } from "os";
|
|
1693
1847
|
var DEFAULT_SFA_INDICES = [
|
|
@@ -1899,7 +2053,7 @@ function discoverCachedFormats() {
|
|
|
1899
2053
|
for (const name of names) {
|
|
1900
2054
|
const nameDir = join4(cacheDir, name);
|
|
1901
2055
|
try {
|
|
1902
|
-
if (!
|
|
2056
|
+
if (!statSync4(nameDir).isDirectory()) continue;
|
|
1903
2057
|
} catch {
|
|
1904
2058
|
continue;
|
|
1905
2059
|
}
|
|
@@ -1940,11 +2094,12 @@ async function compileToFile(options) {
|
|
|
1940
2094
|
}
|
|
1941
2095
|
async function watch(options) {
|
|
1942
2096
|
const controller = new AbortController();
|
|
2097
|
+
const cache = /* @__PURE__ */ new Map();
|
|
1943
2098
|
const filePaths = options.sources.filter((s) => typeof s === "string");
|
|
1944
2099
|
const modulePaths = options.modules ?? [];
|
|
1945
2100
|
const allPaths = [...filePaths, ...modulePaths];
|
|
1946
|
-
const handle = watchFilesystem(allPaths, options.outFile, () => {
|
|
1947
|
-
buildOutput(options).then((result) => {
|
|
2101
|
+
const handle = watchFilesystem(allPaths, options.outFile, (changedFiles) => {
|
|
2102
|
+
buildOutput(options, cache, changedFiles).then((result) => {
|
|
1948
2103
|
writeFileSync2(options.outFile, result.output, "utf-8");
|
|
1949
2104
|
options.onBuild?.(result);
|
|
1950
2105
|
}).catch((e) => {
|
|
@@ -1954,7 +2109,7 @@ async function watch(options) {
|
|
|
1954
2109
|
controller.signal.addEventListener("abort", () => handle.close());
|
|
1955
2110
|
return controller;
|
|
1956
2111
|
}
|
|
1957
|
-
async function buildOutput(options) {
|
|
2112
|
+
async function buildOutput(options, cache, changedFiles) {
|
|
1958
2113
|
const diagnostics = [];
|
|
1959
2114
|
const outputMode = options.outputMode ?? "html";
|
|
1960
2115
|
const trim = options.trim ?? true;
|
|
@@ -1975,7 +2130,11 @@ async function buildOutput(options) {
|
|
|
1975
2130
|
const sourceFilenames = getFilenames(filePaths);
|
|
1976
2131
|
const story = createStory();
|
|
1977
2132
|
const processedFiles = /* @__PURE__ */ new Set();
|
|
1978
|
-
|
|
2133
|
+
if (cache) {
|
|
2134
|
+
loadSourcesCached(story, sourceFilenames, { trim, twee2Compat }, diagnostics, processedFiles, cache, changedFiles);
|
|
2135
|
+
} else {
|
|
2136
|
+
loadSources(story, sourceFilenames, { trim, twee2Compat }, diagnostics, processedFiles);
|
|
2137
|
+
}
|
|
1979
2138
|
loadInlineSources(story, inlineSources, { trim, twee2Compat }, diagnostics);
|
|
1980
2139
|
if (options.tagAliases) {
|
|
1981
2140
|
story.passages = applyTagAliases(story.passages, options.tagAliases);
|