@rohal12/twee-ts 1.3.0 → 1.5.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 +139 -35
- package/dist/bin/twee-ts.js.map +1 -1
- package/dist/{chunk-OGP2NXLJ.js → chunk-KI4QMLEN.js} +135 -34
- package/dist/chunk-KI4QMLEN.js.map +1 -0
- package/dist/index.cjs +135 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -1
- package/dist/index.d.ts +24 -1
- package/dist/index.js +135 -34
- 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-OGP2NXLJ.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -108,6 +108,10 @@ function attrEscape(s) {
|
|
|
108
108
|
if (s.length === 0) return s;
|
|
109
109
|
return s.replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'");
|
|
110
110
|
}
|
|
111
|
+
function fullAttrEscape(s) {
|
|
112
|
+
if (s.length === 0) return s;
|
|
113
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
114
|
+
}
|
|
111
115
|
function htmlEscape(s) {
|
|
112
116
|
if (s.length === 0) return s;
|
|
113
117
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
@@ -130,6 +134,13 @@ function commentSanitize(s) {
|
|
|
130
134
|
function htmlCommentSanitize(s) {
|
|
131
135
|
return s.replace(/-->/g, "-- >");
|
|
132
136
|
}
|
|
137
|
+
function rot13(s) {
|
|
138
|
+
if (s.length === 0) return s;
|
|
139
|
+
return s.replace(/[A-Za-z]/g, (ch) => {
|
|
140
|
+
const base = ch <= "Z" ? 65 : 97;
|
|
141
|
+
return String.fromCharCode((ch.charCodeAt(0) - base + 13) % 26 + base);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
133
144
|
function tweeUnescape(s) {
|
|
134
145
|
if (s.length === 0) return s;
|
|
135
146
|
let result = "";
|
|
@@ -197,12 +208,14 @@ function hasMetadataSize(p) {
|
|
|
197
208
|
return p.metadata != null && p.metadata.size != null && p.metadata.size !== "";
|
|
198
209
|
}
|
|
199
210
|
function hasAnyMetadata(p) {
|
|
200
|
-
|
|
211
|
+
if (!p.metadata) return false;
|
|
212
|
+
return Object.values(p.metadata).some((v) => v != null && v !== "");
|
|
201
213
|
}
|
|
202
214
|
function marshalMetadata(meta) {
|
|
203
215
|
const obj = {};
|
|
204
|
-
|
|
205
|
-
|
|
216
|
+
for (const [key, value] of Object.entries(meta)) {
|
|
217
|
+
if (typeof value === "string" && value) obj[key] = value;
|
|
218
|
+
}
|
|
206
219
|
return JSON.stringify(obj);
|
|
207
220
|
}
|
|
208
221
|
function passageToTwee(p, outMode) {
|
|
@@ -228,7 +241,7 @@ function passageToTwee(p, outMode) {
|
|
|
228
241
|
output += "\n\n";
|
|
229
242
|
return output;
|
|
230
243
|
}
|
|
231
|
-
function passageToPassagedata(p, pid) {
|
|
244
|
+
function passageToPassagedata(p, pid, options) {
|
|
232
245
|
let position;
|
|
233
246
|
let size;
|
|
234
247
|
if (hasMetadataPosition(p)) {
|
|
@@ -245,9 +258,13 @@ function passageToPassagedata(p, pid) {
|
|
|
245
258
|
} else {
|
|
246
259
|
size = "100,100";
|
|
247
260
|
}
|
|
248
|
-
|
|
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>`;
|
|
249
266
|
}
|
|
250
|
-
function passageToTiddler(p, pid) {
|
|
267
|
+
function passageToTiddler(p, pid, obfuscateRot13 = false) {
|
|
251
268
|
let position;
|
|
252
269
|
if (hasMetadataPosition(p)) {
|
|
253
270
|
position = p.metadata?.position ?? "";
|
|
@@ -258,7 +275,10 @@ function passageToTiddler(p, pid) {
|
|
|
258
275
|
const yp = x === 0 ? y : y + 1;
|
|
259
276
|
position = `${xp * 140 - 130},${yp * 140 - 130}`;
|
|
260
277
|
}
|
|
261
|
-
|
|
278
|
+
const created = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:T]/g, "").slice(0, 12);
|
|
279
|
+
const content = obfuscateRot13 && p.name !== "StorySettings" ? tiddlerEscape(rot13(p.text)) : tiddlerEscape(p.text);
|
|
280
|
+
const nameComment = obfuscateRot13 ? `<!-- ${commentSanitize(p.name)} -->` : "";
|
|
281
|
+
return `<div tiddler=${quote(attrEscape(p.name))} tags=${quote(attrEscape(p.tags.join(" ")))} created=${quote(created)} modifier=${quote("twee")} twine-position=${quote(attrEscape(position))}>${nameComment}${content}</div>`;
|
|
262
282
|
}
|
|
263
283
|
function countWords(p) {
|
|
264
284
|
let text = p.text;
|
|
@@ -301,6 +321,7 @@ function createStory() {
|
|
|
301
321
|
formatVersion: "",
|
|
302
322
|
options: /* @__PURE__ */ new Map(),
|
|
303
323
|
start: "",
|
|
324
|
+
tags: "",
|
|
304
325
|
tagColors: /* @__PURE__ */ new Map(),
|
|
305
326
|
zoom: 1
|
|
306
327
|
}
|
|
@@ -347,6 +368,7 @@ function marshalStoryData(story) {
|
|
|
347
368
|
}
|
|
348
369
|
if (options.length > 0) data.options = options;
|
|
349
370
|
if (story.twine2.start) data.start = story.twine2.start;
|
|
371
|
+
if (story.twine2.tags) data.tags = story.twine2.tags;
|
|
350
372
|
if (story.twine2.tagColors.size > 0) {
|
|
351
373
|
data["tag-colors"] = Object.fromEntries(story.twine2.tagColors);
|
|
352
374
|
}
|
|
@@ -374,6 +396,7 @@ function unmarshalStoryData(story, json) {
|
|
|
374
396
|
}
|
|
375
397
|
}
|
|
376
398
|
if (typeof data.start === "string" && data.start) story.twine2.start = data.start;
|
|
399
|
+
if (typeof data.tags === "string") story.twine2.tags = data.tags;
|
|
377
400
|
if (typeof data["tag-colors"] === "object" && data["tag-colors"] !== null && !Array.isArray(data["tag-colors"])) {
|
|
378
401
|
for (const [tag, color] of Object.entries(data["tag-colors"])) {
|
|
379
402
|
if (typeof color === "string") story.twine2.tagColors.set(tag, color);
|
|
@@ -445,7 +468,7 @@ function storyAdd(story, p, diagnostics) {
|
|
|
445
468
|
processed = { ...p, text: marshalStoryData(story) };
|
|
446
469
|
} else {
|
|
447
470
|
diagnostics.push({
|
|
448
|
-
level: "
|
|
471
|
+
level: "warning",
|
|
449
472
|
message: `Cannot unmarshal "StoryData" compiler special passage; ${err}.`
|
|
450
473
|
});
|
|
451
474
|
}
|
|
@@ -668,17 +691,41 @@ function baseNameWithoutExt(filename) {
|
|
|
668
691
|
}
|
|
669
692
|
|
|
670
693
|
// src/formats.ts
|
|
694
|
+
function relaxedJSONParse(json) {
|
|
695
|
+
try {
|
|
696
|
+
return JSON.parse(json);
|
|
697
|
+
} catch {
|
|
698
|
+
}
|
|
699
|
+
let fixed = json;
|
|
700
|
+
fixed = fixed.replace(/'([^'\\]*(?:\\.[^'\\]*)*)'/g, '"$1"');
|
|
701
|
+
fixed = fixed.replace(/(?<=^|[{,]\s*)([A-Za-z_$][A-Za-z0-9_$]*)\s*:/gm, '"$1":');
|
|
702
|
+
fixed = fixed.replace(/,\s*([}\]])/g, "$1");
|
|
703
|
+
return JSON.parse(fixed);
|
|
704
|
+
}
|
|
671
705
|
function parseFormatJSON(source, formatId) {
|
|
672
706
|
const first = source.indexOf("{");
|
|
673
707
|
const last = source.lastIndexOf("}");
|
|
674
708
|
if (first === -1 || last === -1) return null;
|
|
675
709
|
let chunk = source.slice(first, last + 1);
|
|
676
710
|
const parse = (json) => {
|
|
677
|
-
const raw =
|
|
711
|
+
const raw = relaxedJSONParse(json);
|
|
678
712
|
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return null;
|
|
679
713
|
const obj = raw;
|
|
680
|
-
if (typeof obj.
|
|
681
|
-
|
|
714
|
+
if (typeof obj.version !== "string" || typeof obj.source !== "string") return null;
|
|
715
|
+
if (!parseSemver(obj.version)) return null;
|
|
716
|
+
const name = typeof obj.name === "string" ? obj.name : "Untitled Story Format";
|
|
717
|
+
const result = {
|
|
718
|
+
name,
|
|
719
|
+
version: obj.version,
|
|
720
|
+
source: obj.source,
|
|
721
|
+
proofing: obj.proofing === true
|
|
722
|
+
};
|
|
723
|
+
if (typeof obj.author === "string") result.author = obj.author;
|
|
724
|
+
if (typeof obj.description === "string") result.description = obj.description;
|
|
725
|
+
if (typeof obj.image === "string") result.image = obj.image;
|
|
726
|
+
if (typeof obj.url === "string") result.url = obj.url;
|
|
727
|
+
if (typeof obj.license === "string") result.license = obj.license;
|
|
728
|
+
return result;
|
|
682
729
|
};
|
|
683
730
|
try {
|
|
684
731
|
return parse(chunk);
|
|
@@ -744,17 +791,55 @@ function discoverFormats(searchDirs) {
|
|
|
744
791
|
format.name = data.name;
|
|
745
792
|
format.version = data.version;
|
|
746
793
|
format.proofing = data.proofing ?? false;
|
|
794
|
+
if (data.author) format.author = data.author;
|
|
795
|
+
if (data.description) format.description = data.description;
|
|
796
|
+
if (data.image) format.image = data.image;
|
|
797
|
+
if (data.url) format.url = data.url;
|
|
798
|
+
if (data.license) format.license = data.license;
|
|
747
799
|
} catch {
|
|
748
800
|
continue;
|
|
749
801
|
}
|
|
802
|
+
} else {
|
|
803
|
+
format.name = entry;
|
|
750
804
|
}
|
|
751
805
|
formats.set(entry, format);
|
|
752
806
|
break;
|
|
753
807
|
}
|
|
754
808
|
}
|
|
755
809
|
}
|
|
810
|
+
pruneFormats(formats);
|
|
756
811
|
return formats;
|
|
757
812
|
}
|
|
813
|
+
function pruneFormats(formats) {
|
|
814
|
+
const bestByNameMajor = /* @__PURE__ */ new Map();
|
|
815
|
+
const seenNameVersion = /* @__PURE__ */ new Set();
|
|
816
|
+
for (const [id, f] of formats) {
|
|
817
|
+
if (!f.isTwine2 || !f.name || !f.version) continue;
|
|
818
|
+
const v = parseSemver(f.version);
|
|
819
|
+
if (!v) continue;
|
|
820
|
+
const nameVersionKey = `${f.name}@${f.version}`;
|
|
821
|
+
if (seenNameVersion.has(nameVersionKey)) {
|
|
822
|
+
formats.delete(id);
|
|
823
|
+
continue;
|
|
824
|
+
}
|
|
825
|
+
seenNameVersion.add(nameVersionKey);
|
|
826
|
+
const groupKey = `${f.name}@${v[0]}`;
|
|
827
|
+
const existing = bestByNameMajor.get(groupKey);
|
|
828
|
+
if (!existing || semverCompare(v, existing.version) > 0) {
|
|
829
|
+
bestByNameMajor.set(groupKey, { id, version: v });
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
for (const [id, f] of [...formats]) {
|
|
833
|
+
if (!f.isTwine2 || !f.name || !f.version) continue;
|
|
834
|
+
const v = parseSemver(f.version);
|
|
835
|
+
if (!v) continue;
|
|
836
|
+
const groupKey = `${f.name}@${v[0]}`;
|
|
837
|
+
const best = bestByNameMajor.get(groupKey);
|
|
838
|
+
if (best && best.id !== id) {
|
|
839
|
+
formats.delete(id);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
}
|
|
758
843
|
function getFormatSearchDirs(extraPaths = [], useTweegoPath = true) {
|
|
759
844
|
const subdirNames = ["storyformats", ".storyformats", "story-formats", "storyFormats", "targets"];
|
|
760
845
|
const basePaths = /* @__PURE__ */ new Set();
|
|
@@ -1157,7 +1242,7 @@ function parseTwee(source, options = {}) {
|
|
|
1157
1242
|
if (pCount > 1 && current) {
|
|
1158
1243
|
passages.push(current);
|
|
1159
1244
|
}
|
|
1160
|
-
current = { name: "", tags: [], text: "" };
|
|
1245
|
+
current = { name: "", tags: [], text: "", source: { file: filename, line: item.line } };
|
|
1161
1246
|
break;
|
|
1162
1247
|
case 3 /* Name */: {
|
|
1163
1248
|
if (!current) break;
|
|
@@ -1207,8 +1292,11 @@ function parseTwee(source, options = {}) {
|
|
|
1207
1292
|
}
|
|
1208
1293
|
const parsed = raw;
|
|
1209
1294
|
const meta = {};
|
|
1210
|
-
|
|
1211
|
-
|
|
1295
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
1296
|
+
if (typeof value === "string") {
|
|
1297
|
+
meta[key] = value;
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1212
1300
|
current.metadata = meta;
|
|
1213
1301
|
} catch (e) {
|
|
1214
1302
|
diagnostics.push({
|
|
@@ -1222,7 +1310,11 @@ function parseTwee(source, options = {}) {
|
|
|
1222
1310
|
}
|
|
1223
1311
|
case 6 /* Content */: {
|
|
1224
1312
|
if (!current) break;
|
|
1225
|
-
|
|
1313
|
+
if (trim) {
|
|
1314
|
+
current.text = item.val.trim();
|
|
1315
|
+
} else {
|
|
1316
|
+
current.text = item.val.replace(/\n\s*$/, "");
|
|
1317
|
+
}
|
|
1226
1318
|
break;
|
|
1227
1319
|
}
|
|
1228
1320
|
default: {
|
|
@@ -1397,20 +1489,20 @@ var VERSION = "1.2.0";
|
|
|
1397
1489
|
|
|
1398
1490
|
// src/output-twine2.ts
|
|
1399
1491
|
var CREATOR_NAME = "Twee-ts";
|
|
1400
|
-
function toTwine2Archive(story, startName, diagnostics) {
|
|
1401
|
-
return getTwine2DataChunk(story, startName, diagnostics) + "\n";
|
|
1492
|
+
function toTwine2Archive(story, startName, diagnostics, options) {
|
|
1493
|
+
return getTwine2DataChunk(story, startName, diagnostics, options) + "\n";
|
|
1402
1494
|
}
|
|
1403
|
-
function toTwine2HTML(story, format, startName, diagnostics) {
|
|
1495
|
+
function toTwine2HTML(story, format, startName, diagnostics, options) {
|
|
1404
1496
|
let template = readFormatSource(format);
|
|
1405
1497
|
if (template.includes("{{STORY_NAME}}")) {
|
|
1406
1498
|
template = template.replaceAll("{{STORY_NAME}}", htmlEscape(story.name));
|
|
1407
1499
|
}
|
|
1408
1500
|
if (template.includes("{{STORY_DATA}}")) {
|
|
1409
|
-
template = template.replace("{{STORY_DATA}}", getTwine2DataChunk(story, startName, diagnostics));
|
|
1501
|
+
template = template.replace("{{STORY_DATA}}", getTwine2DataChunk(story, startName, diagnostics, options));
|
|
1410
1502
|
}
|
|
1411
1503
|
return template;
|
|
1412
1504
|
}
|
|
1413
|
-
function getTwine2DataChunk(story, startName, diagnostics) {
|
|
1505
|
+
function getTwine2DataChunk(story, startName, diagnostics, options) {
|
|
1414
1506
|
ensureIFID(story, diagnostics);
|
|
1415
1507
|
const parts = [];
|
|
1416
1508
|
let startID = "";
|
|
@@ -1450,8 +1542,12 @@ function getTwine2DataChunk(story, startName, diagnostics) {
|
|
|
1450
1542
|
}
|
|
1451
1543
|
}
|
|
1452
1544
|
parts.push(`<script role="script" id="twine-user-script" type="text/twine-javascript">${scriptContent}</script>`);
|
|
1545
|
+
const validTagColors = /* @__PURE__ */ new Set(["gray", "red", "orange", "yellow", "green", "blue", "purple"]);
|
|
1546
|
+
const hexColorPattern = /^#[0-9a-fA-F]{3,8}$/;
|
|
1453
1547
|
for (const [tag, color] of story.twine2.tagColors) {
|
|
1454
|
-
|
|
1548
|
+
if (validTagColors.has(color) || hexColorPattern.test(color)) {
|
|
1549
|
+
parts.push(`<tw-tag name="${attrEscape(tag)}" color="${attrEscape(color)}"></tw-tag>`);
|
|
1550
|
+
}
|
|
1455
1551
|
}
|
|
1456
1552
|
pid = 1;
|
|
1457
1553
|
for (const p of story.passages) {
|
|
@@ -1461,7 +1557,7 @@ function getTwine2DataChunk(story, startName, diagnostics) {
|
|
|
1461
1557
|
if (p.name === "StorySettings" && story.twine1.settings.size === 0) {
|
|
1462
1558
|
continue;
|
|
1463
1559
|
}
|
|
1464
|
-
parts.push(passageToPassagedata(p, pid));
|
|
1560
|
+
parts.push(passageToPassagedata(p, pid, options));
|
|
1465
1561
|
if (startName === p.name) {
|
|
1466
1562
|
startID = String(pid);
|
|
1467
1563
|
}
|
|
@@ -1471,9 +1567,9 @@ function getTwine2DataChunk(story, startName, diagnostics) {
|
|
|
1471
1567
|
for (const [opt, val] of story.twine2.options) {
|
|
1472
1568
|
if (val) opts.push(opt);
|
|
1473
1569
|
}
|
|
1474
|
-
const
|
|
1570
|
+
const optionsStr = opts.join(" ");
|
|
1475
1571
|
const zoom = String(story.twine2.zoom);
|
|
1476
|
-
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(
|
|
1572
|
+
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>`;
|
|
1477
1573
|
return wrapper + parts.join("") + "</tw-storydata>";
|
|
1478
1574
|
}
|
|
1479
1575
|
function ensureIFID(story, diagnostics) {
|
|
@@ -1489,7 +1585,7 @@ function ensureIFID(story, diagnostics) {
|
|
|
1489
1585
|
story.ifid = ifid;
|
|
1490
1586
|
diagnostics.push({
|
|
1491
1587
|
level: "error",
|
|
1492
|
-
message: `Story IFID not found. Add
|
|
1588
|
+
message: `Story IFID not found. Add an IFID to your story: {"ifid":"${ifid}"}`
|
|
1493
1589
|
});
|
|
1494
1590
|
}
|
|
1495
1591
|
}
|
|
@@ -1500,7 +1596,7 @@ var import_node_path6 = require("path");
|
|
|
1500
1596
|
var CREATOR_NAME2 = "twee-ts";
|
|
1501
1597
|
function toTwine1Archive(story, _startName) {
|
|
1502
1598
|
const { data, count } = getTwine1PassageChunk(story);
|
|
1503
|
-
return `<div id="storeArea" data-size="${count}"
|
|
1599
|
+
return `<div id="storeArea" data-size="${count}">${data}</div>
|
|
1504
1600
|
`;
|
|
1505
1601
|
}
|
|
1506
1602
|
function toTwine1HTML(story, format, startName, _diagnostics) {
|
|
@@ -1545,12 +1641,13 @@ function toTwine1HTML(story, format, startName, _diagnostics) {
|
|
|
1545
1641
|
return template;
|
|
1546
1642
|
}
|
|
1547
1643
|
function getTwine1PassageChunk(story) {
|
|
1644
|
+
const obfuscateRot13 = story.twine1.settings.get("obfuscate") === "rot13";
|
|
1548
1645
|
let data = "";
|
|
1549
1646
|
let count = 0;
|
|
1550
1647
|
for (const p of story.passages) {
|
|
1551
1648
|
if (hasTag(p, "Twine.private")) continue;
|
|
1552
1649
|
count++;
|
|
1553
|
-
data += passageToTiddler(p, count);
|
|
1650
|
+
data += passageToTiddler(p, count, obfuscateRot13);
|
|
1554
1651
|
}
|
|
1555
1652
|
return { data, count };
|
|
1556
1653
|
}
|
|
@@ -1927,6 +2024,7 @@ async function buildOutput(options) {
|
|
|
1927
2024
|
const twee2Compat = options.twee2Compat ?? false;
|
|
1928
2025
|
const testMode = options.testMode ?? false;
|
|
1929
2026
|
const noRemote = options.noRemote ?? false;
|
|
2027
|
+
const sourceInfo = options.sourceInfo ?? false;
|
|
1930
2028
|
clearIndexCache();
|
|
1931
2029
|
const filePaths = [];
|
|
1932
2030
|
const inlineSources = [];
|
|
@@ -1988,7 +2086,7 @@ async function buildOutput(options) {
|
|
|
1988
2086
|
output = toTwee(story, outputMode);
|
|
1989
2087
|
break;
|
|
1990
2088
|
case "twine2-archive":
|
|
1991
|
-
output = toTwine2Archive(story, startName, diagnostics);
|
|
2089
|
+
output = toTwine2Archive(story, startName, diagnostics, { sourceInfo });
|
|
1992
2090
|
break;
|
|
1993
2091
|
case "twine1-archive":
|
|
1994
2092
|
output = toTwine1Archive(story, startName);
|
|
@@ -2007,7 +2105,7 @@ async function buildOutput(options) {
|
|
|
2007
2105
|
throw new TweeTsError("No story format available for HTML output.", diagnostics);
|
|
2008
2106
|
}
|
|
2009
2107
|
if (format.isTwine2) {
|
|
2010
|
-
output = toTwine2HTML(story, format, startName, diagnostics);
|
|
2108
|
+
output = toTwine2HTML(story, format, startName, diagnostics, { sourceInfo });
|
|
2011
2109
|
} else {
|
|
2012
2110
|
if (story.name === "" && !storyHas(story, "StoryTitle")) {
|
|
2013
2111
|
diagnostics.push({
|
|
@@ -2049,11 +2147,14 @@ function storyToJSON(story) {
|
|
|
2049
2147
|
tags: p.tags,
|
|
2050
2148
|
text: p.text
|
|
2051
2149
|
};
|
|
2052
|
-
if (p.metadata
|
|
2150
|
+
if (p.metadata) {
|
|
2053
2151
|
const meta = {};
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2152
|
+
for (const [key, value] of Object.entries(p.metadata)) {
|
|
2153
|
+
if (typeof value === "string") meta[key] = value;
|
|
2154
|
+
}
|
|
2155
|
+
if (Object.keys(meta).length > 0) {
|
|
2156
|
+
entry.metadata = meta;
|
|
2157
|
+
}
|
|
2057
2158
|
}
|
|
2058
2159
|
storyPassages.push(entry);
|
|
2059
2160
|
}
|
|
@@ -2237,7 +2338,7 @@ function validateConfig(data) {
|
|
|
2237
2338
|
errors.push(`"${key}" must be a string.`);
|
|
2238
2339
|
}
|
|
2239
2340
|
}
|
|
2240
|
-
for (const key of ["useTweegoPath", "trim", "twee2Compat", "testMode", "noRemote"]) {
|
|
2341
|
+
for (const key of ["useTweegoPath", "trim", "twee2Compat", "testMode", "noRemote", "sourceInfo"]) {
|
|
2241
2342
|
if (key in obj && typeof obj[key] !== "boolean") {
|
|
2242
2343
|
errors.push(`"${key}" must be a boolean.`);
|
|
2243
2344
|
}
|