@rohal12/twee-ts 1.12.0 → 1.13.1
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 +75 -54
- package/dist/bin/twee-ts.js.map +1 -1
- package/dist/{chunk-TYLUAJTM.js → chunk-EQAUFATA.js} +76 -55
- package/dist/chunk-EQAUFATA.js.map +1 -0
- package/dist/index.cjs +106 -55
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +66 -19
- package/dist/index.d.ts +66 -19
- package/dist/index.js +103 -55
- 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-TYLUAJTM.js.map +0 -1
package/dist/bin/twee-ts.js
CHANGED
|
@@ -917,6 +917,17 @@ function readFormatSource(format) {
|
|
|
917
917
|
import { basename } from "path";
|
|
918
918
|
import { statSync as statSync3 } from "fs";
|
|
919
919
|
|
|
920
|
+
// src/types.ts
|
|
921
|
+
var ItemType = {
|
|
922
|
+
Error: 0,
|
|
923
|
+
EOF: 1,
|
|
924
|
+
Header: 2,
|
|
925
|
+
Name: 3,
|
|
926
|
+
Tags: 4,
|
|
927
|
+
Metadata: 5,
|
|
928
|
+
Content: 6
|
|
929
|
+
};
|
|
930
|
+
|
|
920
931
|
// src/lexer.ts
|
|
921
932
|
var EOF = -1;
|
|
922
933
|
var HEADER_DELIM = "::";
|
|
@@ -949,10 +960,16 @@ var LexerContext = class {
|
|
|
949
960
|
throw new Error("backup would leave pos < start");
|
|
950
961
|
}
|
|
951
962
|
}
|
|
963
|
+
// Line-counting invariant: next() increments this.line for each newline during
|
|
964
|
+
// character-by-character scanning. However, Content items are produced by jumping
|
|
965
|
+
// this.pos directly (e.g. via indexOf) without calling next(), so those newlines
|
|
966
|
+
// haven't been counted yet. emit() re-counts newlines in [start, pos) for Content
|
|
967
|
+
// items to compensate. This is safe because this.start is reset to this.pos after
|
|
968
|
+
// every emit(), so no range is ever counted twice.
|
|
952
969
|
emit(type) {
|
|
953
970
|
const val = this.input.slice(this.start, this.pos);
|
|
954
971
|
this.items.push({ type, line: this.line, pos: this.start, val });
|
|
955
|
-
if (type ===
|
|
972
|
+
if (type === ItemType.Content) {
|
|
956
973
|
for (let i = this.start; i < this.pos; i++) {
|
|
957
974
|
if (this.input.charCodeAt(i) === 10) this.line++;
|
|
958
975
|
}
|
|
@@ -973,7 +990,7 @@ var LexerContext = class {
|
|
|
973
990
|
}
|
|
974
991
|
errorf(message) {
|
|
975
992
|
this.items.push({
|
|
976
|
-
type:
|
|
993
|
+
type: ItemType.Error,
|
|
977
994
|
line: this.line,
|
|
978
995
|
pos: this.start,
|
|
979
996
|
val: message
|
|
@@ -1015,7 +1032,7 @@ function lexProlog(ctx) {
|
|
|
1015
1032
|
ctx.ignore();
|
|
1016
1033
|
return lexHeaderDelim;
|
|
1017
1034
|
}
|
|
1018
|
-
ctx.emit(
|
|
1035
|
+
ctx.emit(ItemType.EOF);
|
|
1019
1036
|
return null;
|
|
1020
1037
|
}
|
|
1021
1038
|
function lexContent(ctx) {
|
|
@@ -1025,19 +1042,19 @@ function lexContent(ctx) {
|
|
|
1025
1042
|
const i = ctx.input.indexOf(NEWLINE_HEADER_DELIM, ctx.pos);
|
|
1026
1043
|
if (i > -1) {
|
|
1027
1044
|
ctx.pos = i + 1;
|
|
1028
|
-
ctx.emit(
|
|
1045
|
+
ctx.emit(ItemType.Content);
|
|
1029
1046
|
return lexHeaderDelim;
|
|
1030
1047
|
}
|
|
1031
1048
|
ctx.pos = ctx.input.length;
|
|
1032
1049
|
if (ctx.pos > ctx.start) {
|
|
1033
|
-
ctx.emit(
|
|
1050
|
+
ctx.emit(ItemType.Content);
|
|
1034
1051
|
}
|
|
1035
|
-
ctx.emit(
|
|
1052
|
+
ctx.emit(ItemType.EOF);
|
|
1036
1053
|
return null;
|
|
1037
1054
|
}
|
|
1038
1055
|
function lexHeaderDelim(ctx) {
|
|
1039
1056
|
ctx.pos += HEADER_DELIM.length;
|
|
1040
|
-
ctx.emit(
|
|
1057
|
+
ctx.emit(ItemType.Header);
|
|
1041
1058
|
return lexName;
|
|
1042
1059
|
}
|
|
1043
1060
|
function lexName(ctx) {
|
|
@@ -1066,7 +1083,7 @@ function lexName(ctx) {
|
|
|
1066
1083
|
break outer;
|
|
1067
1084
|
}
|
|
1068
1085
|
}
|
|
1069
|
-
ctx.emit(
|
|
1086
|
+
ctx.emit(ItemType.Name);
|
|
1070
1087
|
switch (r) {
|
|
1071
1088
|
case 91:
|
|
1072
1089
|
return lexTags;
|
|
@@ -1083,7 +1100,7 @@ function lexName(ctx) {
|
|
|
1083
1100
|
ctx.ignore();
|
|
1084
1101
|
return lexContent;
|
|
1085
1102
|
}
|
|
1086
|
-
ctx.emit(
|
|
1103
|
+
ctx.emit(ItemType.EOF);
|
|
1087
1104
|
return null;
|
|
1088
1105
|
}
|
|
1089
1106
|
function lexNextOptionalBlock(ctx) {
|
|
@@ -1106,7 +1123,7 @@ function lexNextOptionalBlock(ctx) {
|
|
|
1106
1123
|
ctx.ignore();
|
|
1107
1124
|
return lexContent;
|
|
1108
1125
|
case EOF:
|
|
1109
|
-
ctx.emit(
|
|
1126
|
+
ctx.emit(ItemType.EOF);
|
|
1110
1127
|
return null;
|
|
1111
1128
|
}
|
|
1112
1129
|
return ctx.errorf(`illegal character '${String.fromCharCode(r)}' amid the optional blocks`);
|
|
@@ -1126,7 +1143,7 @@ function lexTags(ctx) {
|
|
|
1126
1143
|
if (r === 10) ctx.backup();
|
|
1127
1144
|
return ctx.errorf("unterminated tag block");
|
|
1128
1145
|
case 93:
|
|
1129
|
-
if (ctx.pos > ctx.start) ctx.emit(
|
|
1146
|
+
if (ctx.pos > ctx.start) ctx.emit(ItemType.Tags);
|
|
1130
1147
|
return lexNextOptionalBlock;
|
|
1131
1148
|
case 91:
|
|
1132
1149
|
return ctx.errorf(`unexpected left square bracket '['`);
|
|
@@ -1159,7 +1176,7 @@ function lexMetadata(ctx) {
|
|
|
1159
1176
|
case 125:
|
|
1160
1177
|
depth--;
|
|
1161
1178
|
if (depth === 0) {
|
|
1162
|
-
if (ctx.pos > ctx.start) ctx.emit(
|
|
1179
|
+
if (ctx.pos > ctx.start) ctx.emit(ItemType.Metadata);
|
|
1163
1180
|
return lexNextOptionalBlock;
|
|
1164
1181
|
}
|
|
1165
1182
|
break;
|
|
@@ -1210,10 +1227,10 @@ function parseTwee(source, options = {}) {
|
|
|
1210
1227
|
const passages = [];
|
|
1211
1228
|
let current = null;
|
|
1212
1229
|
let pCount = 0;
|
|
1213
|
-
let lastType =
|
|
1230
|
+
let lastType = ItemType.EOF;
|
|
1214
1231
|
for (const item of tweeLexer(source)) {
|
|
1215
1232
|
switch (item.type) {
|
|
1216
|
-
case
|
|
1233
|
+
case ItemType.Error:
|
|
1217
1234
|
diagnostics.push({
|
|
1218
1235
|
level: "error",
|
|
1219
1236
|
message: `line ${item.line}: Malformed twee source; ${item.val}.`,
|
|
@@ -1221,19 +1238,19 @@ function parseTwee(source, options = {}) {
|
|
|
1221
1238
|
line: item.line
|
|
1222
1239
|
});
|
|
1223
1240
|
return { passages, diagnostics };
|
|
1224
|
-
case
|
|
1241
|
+
case ItemType.EOF:
|
|
1225
1242
|
if (pCount > 0 && current) {
|
|
1226
1243
|
passages.push(current);
|
|
1227
1244
|
}
|
|
1228
1245
|
return { passages, diagnostics };
|
|
1229
|
-
case
|
|
1246
|
+
case ItemType.Header:
|
|
1230
1247
|
pCount++;
|
|
1231
1248
|
if (pCount > 1 && current) {
|
|
1232
1249
|
passages.push(current);
|
|
1233
1250
|
}
|
|
1234
1251
|
current = { name: "", tags: [], text: "", source: { file: filename, line: item.line } };
|
|
1235
1252
|
break;
|
|
1236
|
-
case
|
|
1253
|
+
case ItemType.Name: {
|
|
1237
1254
|
if (!current) break;
|
|
1238
1255
|
const name = tweeUnescape(item.val).trim();
|
|
1239
1256
|
if (name.length === 0) {
|
|
@@ -1248,9 +1265,9 @@ function parseTwee(source, options = {}) {
|
|
|
1248
1265
|
current.name = name;
|
|
1249
1266
|
break;
|
|
1250
1267
|
}
|
|
1251
|
-
case
|
|
1268
|
+
case ItemType.Tags: {
|
|
1252
1269
|
if (!current) break;
|
|
1253
|
-
if (lastType !==
|
|
1270
|
+
if (lastType !== ItemType.Name) {
|
|
1254
1271
|
diagnostics.push({
|
|
1255
1272
|
level: "error",
|
|
1256
1273
|
message: `line ${item.line}: Malformed twee source; optional tags block must immediately follow the passage name.`,
|
|
@@ -1263,9 +1280,9 @@ function parseTwee(source, options = {}) {
|
|
|
1263
1280
|
current.tags = tweeUnescape(inner).split(/\s+/).filter(Boolean);
|
|
1264
1281
|
break;
|
|
1265
1282
|
}
|
|
1266
|
-
case
|
|
1283
|
+
case ItemType.Metadata: {
|
|
1267
1284
|
if (!current) break;
|
|
1268
|
-
if (lastType !==
|
|
1285
|
+
if (lastType !== ItemType.Name && lastType !== ItemType.Tags) {
|
|
1269
1286
|
diagnostics.push({
|
|
1270
1287
|
level: "error",
|
|
1271
1288
|
message: `line ${item.line}: Malformed twee source; optional metadata block must immediately follow the passage name or tags block.`,
|
|
@@ -1297,7 +1314,7 @@ function parseTwee(source, options = {}) {
|
|
|
1297
1314
|
}
|
|
1298
1315
|
break;
|
|
1299
1316
|
}
|
|
1300
|
-
case
|
|
1317
|
+
case ItemType.Content: {
|
|
1301
1318
|
if (!current) break;
|
|
1302
1319
|
if (trim) {
|
|
1303
1320
|
current.text = item.val.trim();
|
|
@@ -4427,21 +4444,22 @@ var VERSION = "1.2.0";
|
|
|
4427
4444
|
|
|
4428
4445
|
// src/output-twine2.ts
|
|
4429
4446
|
var CREATOR_NAME = "Twee-ts";
|
|
4430
|
-
function toTwine2Archive(story, startName,
|
|
4431
|
-
return getTwine2DataChunk(story, startName,
|
|
4447
|
+
function toTwine2Archive(story, startName, options) {
|
|
4448
|
+
return getTwine2DataChunk(story, startName, options) + "\n";
|
|
4432
4449
|
}
|
|
4433
|
-
function toTwine2HTML(story, format, startName,
|
|
4450
|
+
function toTwine2HTML(story, format, startName, options) {
|
|
4434
4451
|
let template = readFormatSource(format);
|
|
4435
4452
|
if (template.includes("{{STORY_NAME}}")) {
|
|
4436
|
-
|
|
4453
|
+
const name = htmlEscape(story.name);
|
|
4454
|
+
template = template.replaceAll("{{STORY_NAME}}", () => name);
|
|
4437
4455
|
}
|
|
4438
4456
|
if (template.includes("{{STORY_DATA}}")) {
|
|
4439
|
-
|
|
4457
|
+
const data = getTwine2DataChunk(story, startName, options);
|
|
4458
|
+
template = template.replace("{{STORY_DATA}}", () => data);
|
|
4440
4459
|
}
|
|
4441
4460
|
return template;
|
|
4442
4461
|
}
|
|
4443
|
-
function getTwine2DataChunk(story, startName,
|
|
4444
|
-
ensureIFID(story, diagnostics);
|
|
4462
|
+
function getTwine2DataChunk(story, startName, options) {
|
|
4445
4463
|
const parts = [];
|
|
4446
4464
|
let startID = "";
|
|
4447
4465
|
let pid = 0;
|
|
@@ -4510,23 +4528,6 @@ function getTwine2DataChunk(story, startName, diagnostics, options) {
|
|
|
4510
4528
|
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>`;
|
|
4511
4529
|
return wrapper + parts.join("") + "</tw-storydata>";
|
|
4512
4530
|
}
|
|
4513
|
-
function ensureIFID(story, diagnostics) {
|
|
4514
|
-
if (story.ifid !== "") return;
|
|
4515
|
-
if (story.legacyIFID !== "") {
|
|
4516
|
-
story.ifid = story.legacyIFID;
|
|
4517
|
-
diagnostics.push({
|
|
4518
|
-
level: "warning",
|
|
4519
|
-
message: 'Story IFID not found; reusing "ifid" entry from the "StorySettings" special passage.'
|
|
4520
|
-
});
|
|
4521
|
-
} else {
|
|
4522
|
-
const ifid = generateIFID();
|
|
4523
|
-
story.ifid = ifid;
|
|
4524
|
-
diagnostics.push({
|
|
4525
|
-
level: "error",
|
|
4526
|
-
message: `Story IFID not found. Add an IFID to your story: {"ifid":"${ifid}"}`
|
|
4527
|
-
});
|
|
4528
|
-
}
|
|
4529
|
-
}
|
|
4530
4531
|
|
|
4531
4532
|
// src/output-twine1.ts
|
|
4532
4533
|
import { readFileSync as readFileSync2 } from "fs";
|
|
@@ -4537,7 +4538,7 @@ function toTwine1Archive(story, _startName) {
|
|
|
4537
4538
|
return `<div id="storeArea" data-size="${count}">${data}</div>
|
|
4538
4539
|
`;
|
|
4539
4540
|
}
|
|
4540
|
-
function toTwine1HTML(story, format, startName
|
|
4541
|
+
function toTwine1HTML(story, format, startName) {
|
|
4541
4542
|
const formatDir = dirname(format.filename);
|
|
4542
4543
|
const parentDir = dirname(formatDir);
|
|
4543
4544
|
let template = readFormatSource(format);
|
|
@@ -4555,10 +4556,11 @@ function toTwine1HTML(story, format, startName, _diagnostics) {
|
|
|
4555
4556
|
const displayStart = startName === "Start" ? "" : startName;
|
|
4556
4557
|
template = template.replace('"VERSION"', `Compiled with ${CREATOR_NAME2}, ${VERSION}`);
|
|
4557
4558
|
template = template.replace('"TIME"', `Built on ${(/* @__PURE__ */ new Date()).toUTCString()}`);
|
|
4558
|
-
|
|
4559
|
+
const startAtValue = `"${jsStringEscape(displayStart)}"`;
|
|
4560
|
+
template = template.replace('"START_AT"', () => startAtValue);
|
|
4559
4561
|
template = template.replace('"STORY_SIZE"', `"${count}"`);
|
|
4560
4562
|
if (template.includes('"STORY"')) {
|
|
4561
|
-
template = template.replace('"STORY"', data);
|
|
4563
|
+
template = template.replace('"STORY"', () => data);
|
|
4562
4564
|
} else {
|
|
4563
4565
|
let footer;
|
|
4564
4566
|
try {
|
|
@@ -4594,7 +4596,7 @@ function tryReplaceComponent(template, placeholder, componentPath, required) {
|
|
|
4594
4596
|
try {
|
|
4595
4597
|
let content = readFileSync2(componentPath, "utf-8");
|
|
4596
4598
|
if (content.charCodeAt(0) === 65279) content = content.slice(1);
|
|
4597
|
-
return template.replace(placeholder, content);
|
|
4599
|
+
return template.replace(placeholder, () => content);
|
|
4598
4600
|
} catch (e) {
|
|
4599
4601
|
if (required) {
|
|
4600
4602
|
throw new Error(
|
|
@@ -4682,7 +4684,8 @@ function modifyHead(html, modulePaths, headFile, diagnostics) {
|
|
|
4682
4684
|
}
|
|
4683
4685
|
if (parts.length > 0) {
|
|
4684
4686
|
parts.push("</head>");
|
|
4685
|
-
|
|
4687
|
+
const replacement = parts.join("\n");
|
|
4688
|
+
return html.replace("</head>", () => replacement);
|
|
4686
4689
|
}
|
|
4687
4690
|
return html;
|
|
4688
4691
|
}
|
|
@@ -5091,6 +5094,7 @@ async function buildOutput(options, cache, changedFiles) {
|
|
|
5091
5094
|
if (testMode) {
|
|
5092
5095
|
story.twine2.options.set("debug", true);
|
|
5093
5096
|
}
|
|
5097
|
+
ensureIFID(story, diagnostics);
|
|
5094
5098
|
let output;
|
|
5095
5099
|
switch (outputMode) {
|
|
5096
5100
|
case "twee3":
|
|
@@ -5098,7 +5102,7 @@ async function buildOutput(options, cache, changedFiles) {
|
|
|
5098
5102
|
output = toTwee(story, outputMode);
|
|
5099
5103
|
break;
|
|
5100
5104
|
case "twine2-archive":
|
|
5101
|
-
output = toTwine2Archive(story, startName,
|
|
5105
|
+
output = toTwine2Archive(story, startName, { sourceInfo });
|
|
5102
5106
|
break;
|
|
5103
5107
|
case "twine1-archive":
|
|
5104
5108
|
output = toTwine1Archive(story, startName);
|
|
@@ -5117,7 +5121,7 @@ async function buildOutput(options, cache, changedFiles) {
|
|
|
5117
5121
|
throw new TweeTsError("No story format available for HTML output.", diagnostics);
|
|
5118
5122
|
}
|
|
5119
5123
|
if (format.isTwine2) {
|
|
5120
|
-
output = toTwine2HTML(story, format, startName,
|
|
5124
|
+
output = toTwine2HTML(story, format, startName, { sourceInfo });
|
|
5121
5125
|
} else {
|
|
5122
5126
|
if (story.name === "" && !storyHas(story, "StoryTitle")) {
|
|
5123
5127
|
diagnostics.push({
|
|
@@ -5125,7 +5129,7 @@ async function buildOutput(options, cache, changedFiles) {
|
|
|
5125
5129
|
message: 'Special passage "StoryTitle" not found.'
|
|
5126
5130
|
});
|
|
5127
5131
|
}
|
|
5128
|
-
output = toTwine1HTML(story, format, startName
|
|
5132
|
+
output = toTwine1HTML(story, format, startName);
|
|
5129
5133
|
}
|
|
5130
5134
|
const modulePaths = options.modules ? getFilenames(options.modules) : [];
|
|
5131
5135
|
output = modifyHead(output, modulePaths, options.headFile, diagnostics);
|
|
@@ -5142,6 +5146,23 @@ async function buildOutput(options, cache, changedFiles) {
|
|
|
5142
5146
|
};
|
|
5143
5147
|
return { output, story, format, diagnostics, stats };
|
|
5144
5148
|
}
|
|
5149
|
+
function ensureIFID(story, diagnostics) {
|
|
5150
|
+
if (story.ifid !== "") return;
|
|
5151
|
+
if (story.legacyIFID !== "") {
|
|
5152
|
+
story.ifid = story.legacyIFID;
|
|
5153
|
+
diagnostics.push({
|
|
5154
|
+
level: "warning",
|
|
5155
|
+
message: 'Story IFID not found; reusing "ifid" entry from the "StorySettings" special passage.'
|
|
5156
|
+
});
|
|
5157
|
+
} else {
|
|
5158
|
+
const ifid = generateIFID();
|
|
5159
|
+
story.ifid = ifid;
|
|
5160
|
+
diagnostics.push({
|
|
5161
|
+
level: "error",
|
|
5162
|
+
message: `Story IFID not found. Add an IFID to your story: {"ifid":"${ifid}"}`
|
|
5163
|
+
});
|
|
5164
|
+
}
|
|
5165
|
+
}
|
|
5145
5166
|
function storyToJSON(story) {
|
|
5146
5167
|
const scripts = [];
|
|
5147
5168
|
const stylesheets = [];
|