@rohal12/twee-ts 1.12.0 → 1.13.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 +66 -49
- package/dist/bin/twee-ts.js.map +1 -1
- package/dist/{chunk-TYLUAJTM.js → chunk-ORMESTR7.js} +67 -50
- package/dist/chunk-ORMESTR7.js.map +1 -0
- package/dist/index.cjs +97 -50
- 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 +94 -50
- 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,20 @@ 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
|
template = template.replaceAll("{{STORY_NAME}}", htmlEscape(story.name));
|
|
4437
4454
|
}
|
|
4438
4455
|
if (template.includes("{{STORY_DATA}}")) {
|
|
4439
|
-
template = template.replace("{{STORY_DATA}}", getTwine2DataChunk(story, startName,
|
|
4456
|
+
template = template.replace("{{STORY_DATA}}", getTwine2DataChunk(story, startName, options));
|
|
4440
4457
|
}
|
|
4441
4458
|
return template;
|
|
4442
4459
|
}
|
|
4443
|
-
function getTwine2DataChunk(story, startName,
|
|
4444
|
-
ensureIFID(story, diagnostics);
|
|
4460
|
+
function getTwine2DataChunk(story, startName, options) {
|
|
4445
4461
|
const parts = [];
|
|
4446
4462
|
let startID = "";
|
|
4447
4463
|
let pid = 0;
|
|
@@ -4510,23 +4526,6 @@ function getTwine2DataChunk(story, startName, diagnostics, options) {
|
|
|
4510
4526
|
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
4527
|
return wrapper + parts.join("") + "</tw-storydata>";
|
|
4512
4528
|
}
|
|
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
4529
|
|
|
4531
4530
|
// src/output-twine1.ts
|
|
4532
4531
|
import { readFileSync as readFileSync2 } from "fs";
|
|
@@ -4537,7 +4536,7 @@ function toTwine1Archive(story, _startName) {
|
|
|
4537
4536
|
return `<div id="storeArea" data-size="${count}">${data}</div>
|
|
4538
4537
|
`;
|
|
4539
4538
|
}
|
|
4540
|
-
function toTwine1HTML(story, format, startName
|
|
4539
|
+
function toTwine1HTML(story, format, startName) {
|
|
4541
4540
|
const formatDir = dirname(format.filename);
|
|
4542
4541
|
const parentDir = dirname(formatDir);
|
|
4543
4542
|
let template = readFormatSource(format);
|
|
@@ -5091,6 +5090,7 @@ async function buildOutput(options, cache, changedFiles) {
|
|
|
5091
5090
|
if (testMode) {
|
|
5092
5091
|
story.twine2.options.set("debug", true);
|
|
5093
5092
|
}
|
|
5093
|
+
ensureIFID(story, diagnostics);
|
|
5094
5094
|
let output;
|
|
5095
5095
|
switch (outputMode) {
|
|
5096
5096
|
case "twee3":
|
|
@@ -5098,7 +5098,7 @@ async function buildOutput(options, cache, changedFiles) {
|
|
|
5098
5098
|
output = toTwee(story, outputMode);
|
|
5099
5099
|
break;
|
|
5100
5100
|
case "twine2-archive":
|
|
5101
|
-
output = toTwine2Archive(story, startName,
|
|
5101
|
+
output = toTwine2Archive(story, startName, { sourceInfo });
|
|
5102
5102
|
break;
|
|
5103
5103
|
case "twine1-archive":
|
|
5104
5104
|
output = toTwine1Archive(story, startName);
|
|
@@ -5117,7 +5117,7 @@ async function buildOutput(options, cache, changedFiles) {
|
|
|
5117
5117
|
throw new TweeTsError("No story format available for HTML output.", diagnostics);
|
|
5118
5118
|
}
|
|
5119
5119
|
if (format.isTwine2) {
|
|
5120
|
-
output = toTwine2HTML(story, format, startName,
|
|
5120
|
+
output = toTwine2HTML(story, format, startName, { sourceInfo });
|
|
5121
5121
|
} else {
|
|
5122
5122
|
if (story.name === "" && !storyHas(story, "StoryTitle")) {
|
|
5123
5123
|
diagnostics.push({
|
|
@@ -5125,7 +5125,7 @@ async function buildOutput(options, cache, changedFiles) {
|
|
|
5125
5125
|
message: 'Special passage "StoryTitle" not found.'
|
|
5126
5126
|
});
|
|
5127
5127
|
}
|
|
5128
|
-
output = toTwine1HTML(story, format, startName
|
|
5128
|
+
output = toTwine1HTML(story, format, startName);
|
|
5129
5129
|
}
|
|
5130
5130
|
const modulePaths = options.modules ? getFilenames(options.modules) : [];
|
|
5131
5131
|
output = modifyHead(output, modulePaths, options.headFile, diagnostics);
|
|
@@ -5142,6 +5142,23 @@ async function buildOutput(options, cache, changedFiles) {
|
|
|
5142
5142
|
};
|
|
5143
5143
|
return { output, story, format, diagnostics, stats };
|
|
5144
5144
|
}
|
|
5145
|
+
function ensureIFID(story, diagnostics) {
|
|
5146
|
+
if (story.ifid !== "") return;
|
|
5147
|
+
if (story.legacyIFID !== "") {
|
|
5148
|
+
story.ifid = story.legacyIFID;
|
|
5149
|
+
diagnostics.push({
|
|
5150
|
+
level: "warning",
|
|
5151
|
+
message: 'Story IFID not found; reusing "ifid" entry from the "StorySettings" special passage.'
|
|
5152
|
+
});
|
|
5153
|
+
} else {
|
|
5154
|
+
const ifid = generateIFID();
|
|
5155
|
+
story.ifid = ifid;
|
|
5156
|
+
diagnostics.push({
|
|
5157
|
+
level: "error",
|
|
5158
|
+
message: `Story IFID not found. Add an IFID to your story: {"ifid":"${ifid}"}`
|
|
5159
|
+
});
|
|
5160
|
+
}
|
|
5161
|
+
}
|
|
5145
5162
|
function storyToJSON(story) {
|
|
5146
5163
|
const scripts = [];
|
|
5147
5164
|
const stylesheets = [];
|