@drghaliasri/butex 6.0.0 → 6.1.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/README.md +8 -2
- package/dist/document2-cli.js +984 -280
- package/dist/document2-cli.js.map +1 -1
- package/dist/document2.d.mts +156 -8
- package/dist/document2.d.ts +156 -8
- package/dist/document2.js +1054 -240
- package/dist/document2.js.map +1 -1
- package/dist/document2.mjs +1054 -240
- package/dist/document2.mjs.map +1 -1
- package/dist/react-document2.d.mts +31 -0
- package/dist/react-document2.d.ts +31 -0
- package/dist/react-document2.js +201 -86
- package/dist/react-document2.js.map +1 -1
- package/dist/react-document2.mjs +201 -86
- package/dist/react-document2.mjs.map +1 -1
- package/package.json +1 -1
package/dist/document2.mjs
CHANGED
|
@@ -978,6 +978,76 @@ function applyFloatMetaPatch(block, patch) {
|
|
|
978
978
|
}
|
|
979
979
|
}
|
|
980
980
|
|
|
981
|
+
// src/document2/inlineIdentity.ts
|
|
982
|
+
function createDocument2IdentityState() {
|
|
983
|
+
return {
|
|
984
|
+
blockIds: /* @__PURE__ */ new Set(),
|
|
985
|
+
itemIds: /* @__PURE__ */ new Set(),
|
|
986
|
+
fieldIds: /* @__PURE__ */ new Set(),
|
|
987
|
+
tokenIds: /* @__PURE__ */ new Set()
|
|
988
|
+
};
|
|
989
|
+
}
|
|
990
|
+
function importedOrGeneratedId(value, prefix, used) {
|
|
991
|
+
const imported = typeof value === "string" ? value.trim() : "";
|
|
992
|
+
if (imported.length > 0 && !used.has(imported)) {
|
|
993
|
+
used.add(imported);
|
|
994
|
+
return imported;
|
|
995
|
+
}
|
|
996
|
+
let generated = document2Id(prefix);
|
|
997
|
+
while (used.has(generated)) {
|
|
998
|
+
generated = document2Id(prefix);
|
|
999
|
+
}
|
|
1000
|
+
used.add(generated);
|
|
1001
|
+
return generated;
|
|
1002
|
+
}
|
|
1003
|
+
function inlineTokenSource(token) {
|
|
1004
|
+
if (token.kind === "text") {
|
|
1005
|
+
return token.text;
|
|
1006
|
+
}
|
|
1007
|
+
if (token.kind === "math") {
|
|
1008
|
+
return token.source;
|
|
1009
|
+
}
|
|
1010
|
+
if (token.kind === "cite") {
|
|
1011
|
+
return citeTokenLatex(token.keys);
|
|
1012
|
+
}
|
|
1013
|
+
return refTokenLatex(token.keys, token.refCommand);
|
|
1014
|
+
}
|
|
1015
|
+
function inlineIdsFromField(field) {
|
|
1016
|
+
let offset = 0;
|
|
1017
|
+
const tokens = field.tokens.map((token) => {
|
|
1018
|
+
const start = offset;
|
|
1019
|
+
offset += inlineTokenSource(token).length;
|
|
1020
|
+
return { id: token.id, kind: token.kind, start, end: offset };
|
|
1021
|
+
});
|
|
1022
|
+
return { field_id: field.id, tokens };
|
|
1023
|
+
}
|
|
1024
|
+
function isAlignedSidecar(value, field) {
|
|
1025
|
+
if (typeof value !== "object" || value === null || !Array.isArray(value.tokens)) {
|
|
1026
|
+
return false;
|
|
1027
|
+
}
|
|
1028
|
+
const tokens = value.tokens;
|
|
1029
|
+
const expected = inlineIdsFromField(field).tokens;
|
|
1030
|
+
if (tokens.length !== expected.length) {
|
|
1031
|
+
return false;
|
|
1032
|
+
}
|
|
1033
|
+
return tokens.every((token, index) => {
|
|
1034
|
+
const expectedToken = expected[index];
|
|
1035
|
+
return typeof token === "object" && token !== null && expectedToken !== void 0 && token.kind === expectedToken.kind && token.start === expectedToken.start && token.end === expectedToken.end;
|
|
1036
|
+
});
|
|
1037
|
+
}
|
|
1038
|
+
function applyImportedInlineIds(field, sidecar, state) {
|
|
1039
|
+
field.id = importedOrGeneratedId(
|
|
1040
|
+
typeof sidecar === "object" && sidecar !== null ? sidecar.field_id : void 0,
|
|
1041
|
+
"field",
|
|
1042
|
+
state.fieldIds
|
|
1043
|
+
);
|
|
1044
|
+
const aligned = isAlignedSidecar(sidecar, field);
|
|
1045
|
+
field.tokens.forEach((token, index) => {
|
|
1046
|
+
token.id = importedOrGeneratedId(aligned ? sidecar.tokens[index]?.id : void 0, token.kind, state.tokenIds);
|
|
1047
|
+
});
|
|
1048
|
+
return field;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
981
1051
|
// src/document2/inlineScanner.ts
|
|
982
1052
|
var MATH_ENVIRONMENTS = /* @__PURE__ */ new Set([
|
|
983
1053
|
"equation",
|
|
@@ -1056,17 +1126,13 @@ function citeSpan(value, start) {
|
|
|
1056
1126
|
function refSpan(value, start) {
|
|
1057
1127
|
const eqrefPrefix = "\\eqref{";
|
|
1058
1128
|
const refPrefix = "\\ref{";
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
if (
|
|
1062
|
-
refCommand = "eqref";
|
|
1063
|
-
prefix = eqrefPrefix;
|
|
1064
|
-
} else if (value.startsWith(refPrefix, start) && !isEscaped(value, start)) {
|
|
1065
|
-
refCommand = "ref";
|
|
1066
|
-
prefix = refPrefix;
|
|
1067
|
-
} else {
|
|
1129
|
+
const isEqref = value.startsWith(eqrefPrefix, start) && !isEscaped(value, start);
|
|
1130
|
+
const isRef = value.startsWith(refPrefix, start) && !isEscaped(value, start);
|
|
1131
|
+
if (!isEqref && !isRef) {
|
|
1068
1132
|
return null;
|
|
1069
1133
|
}
|
|
1134
|
+
const refCommand = isEqref ? "eqref" : "ref";
|
|
1135
|
+
const prefix = isEqref ? eqrefPrefix : refPrefix;
|
|
1070
1136
|
const openBrace = start + prefix.length - 1;
|
|
1071
1137
|
if (value[openBrace] !== "{") {
|
|
1072
1138
|
return null;
|
|
@@ -1125,7 +1191,14 @@ function mathSpanAt(value, i) {
|
|
|
1125
1191
|
return null;
|
|
1126
1192
|
}
|
|
1127
1193
|
function detectMathSpans2(value) {
|
|
1128
|
-
return detectInlineSpans2(value).filter((span) => span.kind === "math").map((
|
|
1194
|
+
return detectInlineSpans2(value).filter((span) => span.kind === "math").map((span) => ({
|
|
1195
|
+
start: span.start,
|
|
1196
|
+
end: span.end,
|
|
1197
|
+
source: span.source,
|
|
1198
|
+
opening: span.opening,
|
|
1199
|
+
closing: span.closing,
|
|
1200
|
+
display: span.display
|
|
1201
|
+
}));
|
|
1129
1202
|
}
|
|
1130
1203
|
function detectInlineSpans2(value) {
|
|
1131
1204
|
const spans = [];
|
|
@@ -1179,17 +1252,13 @@ function asBlockJson(value) {
|
|
|
1179
1252
|
return value;
|
|
1180
1253
|
}
|
|
1181
1254
|
function blockIdFromJson(json, state) {
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
let generated = document2Id("block");
|
|
1188
|
-
while (state.used.has(generated)) {
|
|
1189
|
-
generated = document2Id("block");
|
|
1255
|
+
return importedOrGeneratedId(json.id, "block", state.blockIds);
|
|
1256
|
+
}
|
|
1257
|
+
function metadataFromJson(value) {
|
|
1258
|
+
if (!isObject2(value) || value.source !== "agent" && value.source !== "user") {
|
|
1259
|
+
return {};
|
|
1190
1260
|
}
|
|
1191
|
-
|
|
1192
|
-
return generated;
|
|
1261
|
+
return { metadata: { source: value.source } };
|
|
1193
1262
|
}
|
|
1194
1263
|
function pushDiagnostic(diagnostics, options, path, message) {
|
|
1195
1264
|
if (options.strict) {
|
|
@@ -1372,44 +1441,54 @@ function pushFormattedTextTokens(tokens, text, sourceStart, formats) {
|
|
|
1372
1441
|
function closingForList(command) {
|
|
1373
1442
|
return command === "\\begin{itemize}" ? "\\end{itemize}" : "\\end{enumerate}";
|
|
1374
1443
|
}
|
|
1375
|
-
function parseTextBlock(json, options, path, diagnostics,
|
|
1444
|
+
function parseTextBlock(json, options, path, diagnostics, identities) {
|
|
1376
1445
|
const value = requireString(json.value, `${json.command} requires string value`);
|
|
1377
1446
|
return {
|
|
1378
|
-
id: blockIdFromJson(json,
|
|
1447
|
+
id: blockIdFromJson(json, identities),
|
|
1379
1448
|
kind: "textBlock",
|
|
1380
1449
|
command: json.command,
|
|
1381
|
-
field:
|
|
1450
|
+
field: applyImportedInlineIds(
|
|
1451
|
+
createInlineField2(value, json.math_objects ?? [], options, `${path}.value`, diagnostics, json.command === "\\paragraph" ? json.formats ?? [] : []),
|
|
1452
|
+
json.inline_ids,
|
|
1453
|
+
identities
|
|
1454
|
+
),
|
|
1455
|
+
...metadataFromJson(json.metadata),
|
|
1382
1456
|
...json.centered === true ? { centered: true } : {}
|
|
1383
1457
|
};
|
|
1384
1458
|
}
|
|
1385
|
-
function parseListItem(json, options, path, diagnostics,
|
|
1459
|
+
function parseListItem(json, options, path, diagnostics, identities) {
|
|
1386
1460
|
const value = requireString(json.value, "Document list item requires string value");
|
|
1387
1461
|
const blocksJson = Array.isArray(json.blocks) ? json.blocks : [];
|
|
1388
1462
|
return {
|
|
1389
|
-
id:
|
|
1390
|
-
field:
|
|
1463
|
+
id: importedOrGeneratedId(json.id, "item", identities.itemIds),
|
|
1464
|
+
field: applyImportedInlineIds(
|
|
1465
|
+
createInlineField2(value, json.math_objects ?? [], options, `${path}.value`, diagnostics, json.formats ?? []),
|
|
1466
|
+
json.inline_ids,
|
|
1467
|
+
identities
|
|
1468
|
+
),
|
|
1391
1469
|
blocks: blocksJson.map(
|
|
1392
|
-
(block, index) => parseBlock(asBlockJson(block), options, `${path}.blocks[${String(index)}]`, diagnostics,
|
|
1470
|
+
(block, index) => parseBlock(asBlockJson(block), options, `${path}.blocks[${String(index)}]`, diagnostics, identities)
|
|
1393
1471
|
)
|
|
1394
1472
|
};
|
|
1395
1473
|
}
|
|
1396
|
-
function parseListBlock(json, options, path, diagnostics,
|
|
1474
|
+
function parseListBlock(json, options, path, diagnostics, identities) {
|
|
1397
1475
|
if (!Array.isArray(json.items)) {
|
|
1398
1476
|
throw new Error(`${json.command} requires items array`);
|
|
1399
1477
|
}
|
|
1400
1478
|
const command = json.command;
|
|
1401
1479
|
const closing = closingForList(command);
|
|
1402
1480
|
return {
|
|
1403
|
-
id: blockIdFromJson(json,
|
|
1481
|
+
id: blockIdFromJson(json, identities),
|
|
1404
1482
|
kind: "list",
|
|
1405
1483
|
command,
|
|
1406
1484
|
closing,
|
|
1407
1485
|
items: json.items.map(
|
|
1408
|
-
(item, index) => parseListItem(item, options, `${path}.items[${String(index)}]`, diagnostics,
|
|
1409
|
-
)
|
|
1486
|
+
(item, index) => parseListItem(item, options, `${path}.items[${String(index)}]`, diagnostics, identities)
|
|
1487
|
+
),
|
|
1488
|
+
...metadataFromJson(json.metadata)
|
|
1410
1489
|
};
|
|
1411
1490
|
}
|
|
1412
|
-
function parseTableBlock(json, options, path, diagnostics,
|
|
1491
|
+
function parseTableBlock(json, options, path, diagnostics, identities) {
|
|
1413
1492
|
if (!Array.isArray(json.rows)) {
|
|
1414
1493
|
throw new Error("\\begin{tabular} requires rows array");
|
|
1415
1494
|
}
|
|
@@ -1425,75 +1504,84 @@ function parseTableBlock(json, options, path, diagnostics, blockIds) {
|
|
|
1425
1504
|
const cellMathObjects = mathObjects.slice(mathObjectIndex, mathObjectIndex + spanCount);
|
|
1426
1505
|
mathObjectIndex += spanCount;
|
|
1427
1506
|
const cellFormats = json.cell_formats?.[rowIndex]?.[columnIndex] ?? [];
|
|
1428
|
-
return
|
|
1507
|
+
return applyImportedInlineIds(
|
|
1508
|
+
createInlineField2(value, cellMathObjects, options, `${path}.rows[${String(rowIndex)}][${String(columnIndex)}]`, diagnostics, cellFormats),
|
|
1509
|
+
json.cell_inline_ids?.[rowIndex]?.[columnIndex],
|
|
1510
|
+
identities
|
|
1511
|
+
);
|
|
1429
1512
|
});
|
|
1430
1513
|
});
|
|
1431
1514
|
if (mathObjects.length > 0 && mathObjects.length !== mathObjectIndex) {
|
|
1432
1515
|
pushDiagnostic(diagnostics, options, path, `math_objects count mismatch: detected ${String(mathObjectIndex)}, got ${String(mathObjects.length)}`);
|
|
1433
1516
|
}
|
|
1434
1517
|
return {
|
|
1435
|
-
id: blockIdFromJson(json,
|
|
1518
|
+
id: blockIdFromJson(json, identities),
|
|
1436
1519
|
kind: "table",
|
|
1437
1520
|
command: "\\begin{tabular}",
|
|
1438
1521
|
closing: "\\end{tabular}",
|
|
1439
1522
|
columns: typeof json.columns === "string" ? json.columns : "",
|
|
1440
1523
|
rows,
|
|
1441
|
-
...parseFloatMetaFromJson(json)
|
|
1524
|
+
...parseFloatMetaFromJson(json),
|
|
1525
|
+
...metadataFromJson(json.metadata)
|
|
1442
1526
|
};
|
|
1443
1527
|
}
|
|
1444
|
-
function parseImageBlock(json,
|
|
1528
|
+
function parseImageBlock(json, identities) {
|
|
1445
1529
|
const assetId = typeof json.asset_id === "string" && json.asset_id.length > 0 ? json.asset_id : void 0;
|
|
1446
1530
|
const value = assetId !== void 0 ? typeof json.value === "string" ? json.value : "" : requireString(json.value, "\\includegraphics requires string value");
|
|
1447
1531
|
return {
|
|
1448
|
-
id: blockIdFromJson(json,
|
|
1532
|
+
id: blockIdFromJson(json, identities),
|
|
1449
1533
|
kind: "image",
|
|
1450
1534
|
command: "\\includegraphics",
|
|
1451
1535
|
value,
|
|
1452
1536
|
...assetId !== void 0 ? { assetId } : {},
|
|
1453
1537
|
options: isRecordOfStrings(json.options) ? json.options : {},
|
|
1454
|
-
...parseFloatMetaFromJson(json)
|
|
1538
|
+
...parseFloatMetaFromJson(json),
|
|
1539
|
+
...metadataFromJson(json.metadata)
|
|
1455
1540
|
};
|
|
1456
1541
|
}
|
|
1457
|
-
function parseRawBlock(json,
|
|
1542
|
+
function parseRawBlock(json, identities) {
|
|
1458
1543
|
return {
|
|
1459
|
-
id: blockIdFromJson(json,
|
|
1544
|
+
id: blockIdFromJson(json, identities),
|
|
1460
1545
|
kind: "raw",
|
|
1461
1546
|
command: "\\raw",
|
|
1462
|
-
value: typeof json.value === "string" ? json.value : ""
|
|
1547
|
+
value: typeof json.value === "string" ? json.value : "",
|
|
1548
|
+
...metadataFromJson(json.metadata)
|
|
1463
1549
|
};
|
|
1464
1550
|
}
|
|
1465
|
-
function parseBibliographyBlock(json,
|
|
1551
|
+
function parseBibliographyBlock(json, identities) {
|
|
1466
1552
|
return {
|
|
1467
|
-
id: blockIdFromJson(json,
|
|
1553
|
+
id: blockIdFromJson(json, identities),
|
|
1468
1554
|
kind: "bibliography",
|
|
1469
1555
|
command: "\\begin{thebibliography}",
|
|
1470
|
-
closing: "\\end{thebibliography}"
|
|
1556
|
+
closing: "\\end{thebibliography}",
|
|
1557
|
+
...metadataFromJson(json.metadata)
|
|
1471
1558
|
};
|
|
1472
1559
|
}
|
|
1473
|
-
function parseBlock(json, options, path, diagnostics,
|
|
1560
|
+
function parseBlock(json, options, path, diagnostics, identities) {
|
|
1474
1561
|
if (TEXT_COMMANDS.has(json.command)) {
|
|
1475
|
-
return parseTextBlock(json, options, path, diagnostics,
|
|
1562
|
+
return parseTextBlock(json, options, path, diagnostics, identities);
|
|
1476
1563
|
}
|
|
1477
1564
|
if (LIST_COMMANDS.has(json.command)) {
|
|
1478
|
-
return parseListBlock(json, options, path, diagnostics,
|
|
1565
|
+
return parseListBlock(json, options, path, diagnostics, identities);
|
|
1479
1566
|
}
|
|
1480
1567
|
if (json.command === "\\begin{tabular}") {
|
|
1481
|
-
return parseTableBlock(json, options, path, diagnostics,
|
|
1568
|
+
return parseTableBlock(json, options, path, diagnostics, identities);
|
|
1482
1569
|
}
|
|
1483
1570
|
if (json.command === "\\includegraphics") {
|
|
1484
|
-
return parseImageBlock(json,
|
|
1571
|
+
return parseImageBlock(json, identities);
|
|
1485
1572
|
}
|
|
1486
1573
|
if (json.command === "\\begin{thebibliography}" || json.command === "\\bibliography") {
|
|
1487
|
-
return parseBibliographyBlock(json,
|
|
1574
|
+
return parseBibliographyBlock(json, identities);
|
|
1488
1575
|
}
|
|
1489
1576
|
if (json.command === "\\raw") {
|
|
1490
|
-
return parseRawBlock(json,
|
|
1577
|
+
return parseRawBlock(json, identities);
|
|
1491
1578
|
}
|
|
1492
1579
|
return {
|
|
1493
|
-
id: blockIdFromJson(json,
|
|
1580
|
+
id: blockIdFromJson(json, identities),
|
|
1494
1581
|
kind: "raw",
|
|
1495
1582
|
command: "\\raw",
|
|
1496
|
-
value: typeof json.value === "string" ? json.value : json.command
|
|
1583
|
+
value: typeof json.value === "string" ? json.value : json.command,
|
|
1584
|
+
...metadataFromJson(json.metadata)
|
|
1497
1585
|
};
|
|
1498
1586
|
}
|
|
1499
1587
|
function fromDocumentJson2(json, options = {}) {
|
|
@@ -1504,13 +1592,13 @@ function fromDocumentJson2(json, options = {}) {
|
|
|
1504
1592
|
throw new Error("DocumentObject requires blocks array");
|
|
1505
1593
|
}
|
|
1506
1594
|
const diagnostics = [];
|
|
1507
|
-
const
|
|
1595
|
+
const identities = createDocument2IdentityState();
|
|
1508
1596
|
return {
|
|
1509
1597
|
nodeType: "DocumentObject",
|
|
1510
1598
|
meta: normalizeDocument2Meta(json.meta),
|
|
1511
1599
|
references: parseReferences(json.references),
|
|
1512
1600
|
blocks: json.blocks.map(
|
|
1513
|
-
(block, index) => parseBlock(asBlockJson(block), options, `$.blocks[${String(index)}]`, diagnostics,
|
|
1601
|
+
(block, index) => parseBlock(asBlockJson(block), options, `$.blocks[${String(index)}]`, diagnostics, identities)
|
|
1514
1602
|
),
|
|
1515
1603
|
diagnostics
|
|
1516
1604
|
};
|
|
@@ -2728,9 +2816,9 @@ function createAccentNode(accentId) {
|
|
|
2728
2816
|
baseExpr: createEditorChain()
|
|
2729
2817
|
};
|
|
2730
2818
|
}
|
|
2731
|
-
function createGridEnvNode(envName, rows,
|
|
2819
|
+
function createGridEnvNode(envName, rows, columns2, columnAlignments) {
|
|
2732
2820
|
const safeRows = Math.max(1, Math.min(12, Math.trunc(rows)));
|
|
2733
|
-
const safeColumns = Math.max(1, Math.min(12, Math.trunc(
|
|
2821
|
+
const safeColumns = Math.max(1, Math.min(12, Math.trunc(columns2)));
|
|
2734
2822
|
const matrixStyles = /* @__PURE__ */ new Set(["matrix", "pmatrix", "bmatrix", "Bmatrix", "vmatrix", "Vmatrix"]);
|
|
2735
2823
|
const isMatrix = matrixStyles.has(envName) && envName !== "array" && envName !== "aligned";
|
|
2736
2824
|
return {
|
|
@@ -3999,11 +4087,11 @@ function envToEditorNode(node) {
|
|
|
3999
4087
|
}
|
|
4000
4088
|
const rowCells = node.lines.map(splitEnvLine);
|
|
4001
4089
|
const rows = Math.max(1, rowCells.length);
|
|
4002
|
-
const
|
|
4003
|
-
const env = createGridEnvNode(parsed.envName, rows,
|
|
4090
|
+
const columns2 = Math.max(1, ...rowCells.map((row) => row.length));
|
|
4091
|
+
const env = createGridEnvNode(parsed.envName, rows, columns2, parsed.alignments);
|
|
4004
4092
|
for (let rowIndex = 0; rowIndex < rows; rowIndex += 1) {
|
|
4005
4093
|
const row = rowCells[rowIndex] ?? [];
|
|
4006
|
-
for (let columnIndex = 0; columnIndex <
|
|
4094
|
+
for (let columnIndex = 0; columnIndex < columns2; columnIndex += 1) {
|
|
4007
4095
|
const cell = chainToEditorChain(row[columnIndex] ?? new ChainNode());
|
|
4008
4096
|
if (!cell.editable) {
|
|
4009
4097
|
return cell;
|
|
@@ -4013,7 +4101,7 @@ function envToEditorNode(node) {
|
|
|
4013
4101
|
}
|
|
4014
4102
|
if (parsed.envName === "array") {
|
|
4015
4103
|
env.columnAlignments = Array.from(
|
|
4016
|
-
{ length:
|
|
4104
|
+
{ length: columns2 },
|
|
4017
4105
|
(_, index) => parsed.alignments?.[index] ?? "c"
|
|
4018
4106
|
);
|
|
4019
4107
|
}
|
|
@@ -4491,12 +4579,14 @@ function cloneField(field) {
|
|
|
4491
4579
|
return { id: field.id, tokens: field.tokens.map(cloneToken) };
|
|
4492
4580
|
}
|
|
4493
4581
|
function cloneBlock(block) {
|
|
4582
|
+
const metadata = block.metadata ? { metadata: { ...block.metadata } } : {};
|
|
4494
4583
|
if (block.kind === "textBlock") {
|
|
4495
|
-
return { ...block, field: cloneField(block.field) };
|
|
4584
|
+
return { ...block, ...metadata, field: cloneField(block.field) };
|
|
4496
4585
|
}
|
|
4497
4586
|
if (block.kind === "list") {
|
|
4498
4587
|
return {
|
|
4499
4588
|
...block,
|
|
4589
|
+
...metadata,
|
|
4500
4590
|
items: block.items.map((item) => ({
|
|
4501
4591
|
...item,
|
|
4502
4592
|
field: cloneField(item.field),
|
|
@@ -4505,12 +4595,12 @@ function cloneBlock(block) {
|
|
|
4505
4595
|
};
|
|
4506
4596
|
}
|
|
4507
4597
|
if (block.kind === "table") {
|
|
4508
|
-
return { ...block, rows: block.rows.map((row) => row.map(cloneField)) };
|
|
4598
|
+
return { ...block, ...metadata, rows: block.rows.map((row) => row.map(cloneField)) };
|
|
4509
4599
|
}
|
|
4510
4600
|
if (block.kind === "image") {
|
|
4511
|
-
return { ...block, options: { ...block.options } };
|
|
4601
|
+
return { ...block, ...metadata, options: { ...block.options } };
|
|
4512
4602
|
}
|
|
4513
|
-
return { ...block };
|
|
4603
|
+
return { ...block, ...metadata };
|
|
4514
4604
|
}
|
|
4515
4605
|
function cloneDocument(document2) {
|
|
4516
4606
|
return {
|
|
@@ -4595,21 +4685,21 @@ function splitTextForInsertion(token) {
|
|
|
4595
4685
|
function cloneDocument2Node(document2) {
|
|
4596
4686
|
return cloneDocument(document2);
|
|
4597
4687
|
}
|
|
4598
|
-
function insertBlockAfter(blocks,
|
|
4599
|
-
if (!
|
|
4688
|
+
function insertBlockAfter(blocks, afterBlockId, block) {
|
|
4689
|
+
if (!afterBlockId) {
|
|
4600
4690
|
blocks.push(block);
|
|
4601
4691
|
return;
|
|
4602
4692
|
}
|
|
4603
|
-
const index = blocks.findIndex((entry) => entry.id ===
|
|
4693
|
+
const index = blocks.findIndex((entry) => entry.id === afterBlockId);
|
|
4604
4694
|
if (index < 0) {
|
|
4605
4695
|
blocks.push(block);
|
|
4606
4696
|
return;
|
|
4607
4697
|
}
|
|
4608
4698
|
blocks.splice(index + 1, 0, block);
|
|
4609
4699
|
}
|
|
4610
|
-
function insertDocument2BlockAfter(document2,
|
|
4700
|
+
function insertDocument2BlockAfter(document2, afterBlockId, block) {
|
|
4611
4701
|
const next = cloneDocument(document2);
|
|
4612
|
-
insertBlockAfter(next.blocks,
|
|
4702
|
+
insertBlockAfter(next.blocks, afterBlockId, block);
|
|
4613
4703
|
return next;
|
|
4614
4704
|
}
|
|
4615
4705
|
function moveDocument2BlockById(document2, blockId, direction) {
|
|
@@ -4829,7 +4919,7 @@ function replaceMathTokenFromSession(document2, tokenId, session, opening, closi
|
|
|
4829
4919
|
});
|
|
4830
4920
|
return next;
|
|
4831
4921
|
}
|
|
4832
|
-
function addDocument2TextBlock(document2, command = "\\paragraph",
|
|
4922
|
+
function addDocument2TextBlock(document2, command = "\\paragraph", afterBlockId) {
|
|
4833
4923
|
const block = {
|
|
4834
4924
|
id: document2Id("block"),
|
|
4835
4925
|
kind: "textBlock",
|
|
@@ -4837,7 +4927,7 @@ function addDocument2TextBlock(document2, command = "\\paragraph", afterBlockId2
|
|
|
4837
4927
|
field: createInlineField2(""),
|
|
4838
4928
|
...command === "\\paragraph" ? { centered: false } : {}
|
|
4839
4929
|
};
|
|
4840
|
-
return insertDocument2BlockAfter(document2,
|
|
4930
|
+
return insertDocument2BlockAfter(document2, afterBlockId, block);
|
|
4841
4931
|
}
|
|
4842
4932
|
function updateDocument2TextBlockCentered(document2, blockId, centered) {
|
|
4843
4933
|
const next = cloneDocument(document2);
|
|
@@ -4876,10 +4966,10 @@ function newListBlock(ordered) {
|
|
|
4876
4966
|
items: [{ id: document2Id("item"), field: createInlineField2(""), blocks: [] }]
|
|
4877
4967
|
};
|
|
4878
4968
|
}
|
|
4879
|
-
function addDocument2ListBlock(document2, ordered,
|
|
4880
|
-
return insertDocument2BlockAfter(document2,
|
|
4969
|
+
function addDocument2ListBlock(document2, ordered, afterBlockId) {
|
|
4970
|
+
return insertDocument2BlockAfter(document2, afterBlockId, newListBlock(ordered));
|
|
4881
4971
|
}
|
|
4882
|
-
function addDocument2TableBlock(document2,
|
|
4972
|
+
function addDocument2TableBlock(document2, columns2 = "lll", rowCount = 3, colCount = 3, afterBlockId) {
|
|
4883
4973
|
const rows = Math.max(1, rowCount);
|
|
4884
4974
|
const cols = Math.max(1, colCount);
|
|
4885
4975
|
const tableRows = [];
|
|
@@ -4895,11 +4985,11 @@ function addDocument2TableBlock(document2, columns = "lll", rowCount = 3, colCou
|
|
|
4895
4985
|
kind: "table",
|
|
4896
4986
|
command: "\\begin{tabular}",
|
|
4897
4987
|
closing: "\\end{tabular}",
|
|
4898
|
-
columns:
|
|
4988
|
+
columns: columns2 || "l".repeat(cols),
|
|
4899
4989
|
rows: tableRows,
|
|
4900
4990
|
...defaultFloatMeta()
|
|
4901
4991
|
};
|
|
4902
|
-
return insertDocument2BlockAfter(document2,
|
|
4992
|
+
return insertDocument2BlockAfter(document2, afterBlockId, block);
|
|
4903
4993
|
}
|
|
4904
4994
|
function normalizeImageInput(srcOrAsset) {
|
|
4905
4995
|
if (typeof srcOrAsset === "string") {
|
|
@@ -4910,7 +5000,7 @@ function normalizeImageInput(srcOrAsset) {
|
|
|
4910
5000
|
}
|
|
4911
5001
|
return { value: "" };
|
|
4912
5002
|
}
|
|
4913
|
-
function addDocument2ImageBlock(document2, srcOrAsset,
|
|
5003
|
+
function addDocument2ImageBlock(document2, srcOrAsset, afterBlockId) {
|
|
4914
5004
|
const image = normalizeImageInput(srcOrAsset);
|
|
4915
5005
|
const block = {
|
|
4916
5006
|
id: document2Id("block"),
|
|
@@ -4921,7 +5011,7 @@ function addDocument2ImageBlock(document2, srcOrAsset, afterBlockId2) {
|
|
|
4921
5011
|
options: { width: "0.8\\columnwidth" },
|
|
4922
5012
|
...defaultFloatMeta()
|
|
4923
5013
|
};
|
|
4924
|
-
return insertDocument2BlockAfter(document2,
|
|
5014
|
+
return insertDocument2BlockAfter(document2, afterBlockId, block);
|
|
4925
5015
|
}
|
|
4926
5016
|
function updateDocument2ImageValue(document2, blockId, value) {
|
|
4927
5017
|
const next = cloneDocument(document2);
|
|
@@ -5211,7 +5301,7 @@ function removeCiteTokenById(document2, tokenId) {
|
|
|
5211
5301
|
});
|
|
5212
5302
|
return next;
|
|
5213
5303
|
}
|
|
5214
|
-
function ensureDocument2BibliographyBlock(document2,
|
|
5304
|
+
function ensureDocument2BibliographyBlock(document2, afterBlockId) {
|
|
5215
5305
|
if (document2.blocks.some((block2) => block2.kind === "bibliography")) {
|
|
5216
5306
|
return document2;
|
|
5217
5307
|
}
|
|
@@ -5221,7 +5311,7 @@ function ensureDocument2BibliographyBlock(document2, afterBlockId2) {
|
|
|
5221
5311
|
command: "\\begin{thebibliography}",
|
|
5222
5312
|
closing: "\\end{thebibliography}"
|
|
5223
5313
|
};
|
|
5224
|
-
return insertDocument2BlockAfter(document2,
|
|
5314
|
+
return insertDocument2BlockAfter(document2, afterBlockId ?? null, block);
|
|
5225
5315
|
}
|
|
5226
5316
|
function addDocument2Reference(document2, partial = {}) {
|
|
5227
5317
|
const next = cloneDocument(document2);
|
|
@@ -5293,6 +5383,764 @@ function updateDocument2Meta(document2, patch) {
|
|
|
5293
5383
|
return next;
|
|
5294
5384
|
}
|
|
5295
5385
|
|
|
5386
|
+
// src/document2/jsonCommandTypes.ts
|
|
5387
|
+
var Document2CommandError = class extends Error {
|
|
5388
|
+
code;
|
|
5389
|
+
constructor(code, message) {
|
|
5390
|
+
super(message);
|
|
5391
|
+
this.name = "Document2CommandError";
|
|
5392
|
+
this.code = code;
|
|
5393
|
+
}
|
|
5394
|
+
};
|
|
5395
|
+
|
|
5396
|
+
// src/document2/jsonCommandHelpers.ts
|
|
5397
|
+
function isObject3(value) {
|
|
5398
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5399
|
+
}
|
|
5400
|
+
function requireString2(value, field, allowEmpty = true) {
|
|
5401
|
+
if (typeof value !== "string" || !allowEmpty && value.trim().length === 0) {
|
|
5402
|
+
throw new Document2CommandError("invalid_command", `${field} must be a${allowEmpty ? "" : " non-empty"} string`);
|
|
5403
|
+
}
|
|
5404
|
+
return value;
|
|
5405
|
+
}
|
|
5406
|
+
function optionalString(value, field) {
|
|
5407
|
+
if (!(field in value)) {
|
|
5408
|
+
return void 0;
|
|
5409
|
+
}
|
|
5410
|
+
if (typeof value[field] !== "string") {
|
|
5411
|
+
throw new Document2CommandError("invalid_command", `${field} must be a string when provided`);
|
|
5412
|
+
}
|
|
5413
|
+
return value[field];
|
|
5414
|
+
}
|
|
5415
|
+
function requireBoolean(value, field) {
|
|
5416
|
+
if (typeof value !== "boolean") {
|
|
5417
|
+
throw new Document2CommandError("invalid_command", `${field} must be a boolean`);
|
|
5418
|
+
}
|
|
5419
|
+
return value;
|
|
5420
|
+
}
|
|
5421
|
+
function requireIndex(value, field) {
|
|
5422
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
|
|
5423
|
+
throw new Document2CommandError("invalid_command", `${field} must be a non-negative integer`);
|
|
5424
|
+
}
|
|
5425
|
+
return value;
|
|
5426
|
+
}
|
|
5427
|
+
function parseMetadata(value) {
|
|
5428
|
+
if (value === void 0) {
|
|
5429
|
+
return void 0;
|
|
5430
|
+
}
|
|
5431
|
+
if (!isObject3(value)) {
|
|
5432
|
+
throw new Document2CommandError("invalid_command", "metadata must be an object");
|
|
5433
|
+
}
|
|
5434
|
+
if (value.source === void 0) {
|
|
5435
|
+
return void 0;
|
|
5436
|
+
}
|
|
5437
|
+
if (value.source !== "agent" && value.source !== "user") {
|
|
5438
|
+
throw new Document2CommandError("invalid_command", "metadata.source must be agent or user");
|
|
5439
|
+
}
|
|
5440
|
+
return { source: value.source };
|
|
5441
|
+
}
|
|
5442
|
+
function parseBlockAnchor(value) {
|
|
5443
|
+
if (!isObject3(value)) {
|
|
5444
|
+
throw new Document2CommandError("invalid_anchor", "anchor must be an object");
|
|
5445
|
+
}
|
|
5446
|
+
const before = typeof value.before_block_id === "string" ? value.before_block_id.trim() : "";
|
|
5447
|
+
const after = typeof value.after_block_id === "string" ? value.after_block_id.trim() : "";
|
|
5448
|
+
const choices = Number(before.length > 0) + Number(after.length > 0) + Number(value.end === true);
|
|
5449
|
+
if (choices !== 1) {
|
|
5450
|
+
throw new Document2CommandError("invalid_anchor", "anchor requires exactly one block position");
|
|
5451
|
+
}
|
|
5452
|
+
if (before) {
|
|
5453
|
+
return { before_block_id: before };
|
|
5454
|
+
}
|
|
5455
|
+
if (after) {
|
|
5456
|
+
return { after_block_id: after };
|
|
5457
|
+
}
|
|
5458
|
+
return { end: true };
|
|
5459
|
+
}
|
|
5460
|
+
function parseListItemAnchor(value) {
|
|
5461
|
+
if (!isObject3(value)) {
|
|
5462
|
+
throw new Document2CommandError("invalid_anchor", "anchor must be an object");
|
|
5463
|
+
}
|
|
5464
|
+
const before = typeof value.before_item_id === "string" ? value.before_item_id.trim() : "";
|
|
5465
|
+
const after = typeof value.after_item_id === "string" ? value.after_item_id.trim() : "";
|
|
5466
|
+
const choices = Number(before.length > 0) + Number(after.length > 0) + Number(value.end === true);
|
|
5467
|
+
if (choices !== 1) {
|
|
5468
|
+
throw new Document2CommandError("invalid_anchor", "anchor requires exactly one list-item position");
|
|
5469
|
+
}
|
|
5470
|
+
if (before) {
|
|
5471
|
+
return { before_item_id: before };
|
|
5472
|
+
}
|
|
5473
|
+
if (after) {
|
|
5474
|
+
return { after_item_id: after };
|
|
5475
|
+
}
|
|
5476
|
+
return { end: true };
|
|
5477
|
+
}
|
|
5478
|
+
function blockInsertionIndex(document2, anchor) {
|
|
5479
|
+
if ("end" in anchor) {
|
|
5480
|
+
return document2.blocks.length;
|
|
5481
|
+
}
|
|
5482
|
+
const id = "before_block_id" in anchor ? anchor.before_block_id : anchor.after_block_id;
|
|
5483
|
+
const index = document2.blocks.findIndex((block) => block.id === id);
|
|
5484
|
+
if (index < 0) {
|
|
5485
|
+
throw new Document2CommandError("anchor_not_found", "Anchor block was not found");
|
|
5486
|
+
}
|
|
5487
|
+
return "before_block_id" in anchor ? index : index + 1;
|
|
5488
|
+
}
|
|
5489
|
+
function itemInsertionIndex(list, anchor) {
|
|
5490
|
+
if ("end" in anchor) {
|
|
5491
|
+
return list.items.length;
|
|
5492
|
+
}
|
|
5493
|
+
const id = "before_item_id" in anchor ? anchor.before_item_id : anchor.after_item_id;
|
|
5494
|
+
const index = list.items.findIndex((item) => item.id === id);
|
|
5495
|
+
if (index < 0) {
|
|
5496
|
+
throw new Document2CommandError("anchor_not_found", "Anchor list item was not found");
|
|
5497
|
+
}
|
|
5498
|
+
return "before_item_id" in anchor ? index : index + 1;
|
|
5499
|
+
}
|
|
5500
|
+
function findField(blocks, fieldId) {
|
|
5501
|
+
for (const block of blocks) {
|
|
5502
|
+
if (block.kind === "textBlock" && block.field.id === fieldId) {
|
|
5503
|
+
return block.field;
|
|
5504
|
+
}
|
|
5505
|
+
if (block.kind === "list") {
|
|
5506
|
+
for (const item of block.items) {
|
|
5507
|
+
if (item.field.id === fieldId) {
|
|
5508
|
+
return item.field;
|
|
5509
|
+
}
|
|
5510
|
+
const nested = findField(item.blocks, fieldId);
|
|
5511
|
+
if (nested) {
|
|
5512
|
+
return nested;
|
|
5513
|
+
}
|
|
5514
|
+
}
|
|
5515
|
+
}
|
|
5516
|
+
if (block.kind === "table") {
|
|
5517
|
+
for (const row of block.rows) {
|
|
5518
|
+
const cell = row.find((field) => field.id === fieldId);
|
|
5519
|
+
if (cell) {
|
|
5520
|
+
return cell;
|
|
5521
|
+
}
|
|
5522
|
+
}
|
|
5523
|
+
}
|
|
5524
|
+
}
|
|
5525
|
+
return null;
|
|
5526
|
+
}
|
|
5527
|
+
function findBlock(blocks, blockId) {
|
|
5528
|
+
for (const block of blocks) {
|
|
5529
|
+
if (block.id === blockId) {
|
|
5530
|
+
return block;
|
|
5531
|
+
}
|
|
5532
|
+
if (block.kind === "list") {
|
|
5533
|
+
for (const item of block.items) {
|
|
5534
|
+
const nested = findBlock(item.blocks, blockId);
|
|
5535
|
+
if (nested) {
|
|
5536
|
+
return nested;
|
|
5537
|
+
}
|
|
5538
|
+
}
|
|
5539
|
+
}
|
|
5540
|
+
}
|
|
5541
|
+
return null;
|
|
5542
|
+
}
|
|
5543
|
+
function collectIdentitySets(blocks, sets) {
|
|
5544
|
+
for (const block of blocks) {
|
|
5545
|
+
sets.blocks.add(block.id);
|
|
5546
|
+
if (block.kind === "textBlock") {
|
|
5547
|
+
sets.fields.add(block.field.id);
|
|
5548
|
+
block.field.tokens.forEach((token) => sets.tokens.add(token.id));
|
|
5549
|
+
} else if (block.kind === "list") {
|
|
5550
|
+
for (const item of block.items) {
|
|
5551
|
+
sets.items.add(item.id);
|
|
5552
|
+
sets.fields.add(item.field.id);
|
|
5553
|
+
item.field.tokens.forEach((token) => sets.tokens.add(token.id));
|
|
5554
|
+
collectIdentitySets(item.blocks, sets);
|
|
5555
|
+
}
|
|
5556
|
+
} else if (block.kind === "table") {
|
|
5557
|
+
for (const row of block.rows) {
|
|
5558
|
+
for (const field of row) {
|
|
5559
|
+
sets.fields.add(field.id);
|
|
5560
|
+
field.tokens.forEach((token) => sets.tokens.add(token.id));
|
|
5561
|
+
}
|
|
5562
|
+
}
|
|
5563
|
+
}
|
|
5564
|
+
}
|
|
5565
|
+
}
|
|
5566
|
+
function documentIdentitySets(document2) {
|
|
5567
|
+
const sets = {
|
|
5568
|
+
blocks: /* @__PURE__ */ new Set(),
|
|
5569
|
+
items: /* @__PURE__ */ new Set(),
|
|
5570
|
+
fields: /* @__PURE__ */ new Set(),
|
|
5571
|
+
tokens: /* @__PURE__ */ new Set()
|
|
5572
|
+
};
|
|
5573
|
+
collectIdentitySets(document2.blocks, sets);
|
|
5574
|
+
return sets;
|
|
5575
|
+
}
|
|
5576
|
+
function unusedGeneratedId(prefix, used) {
|
|
5577
|
+
let id = document2Id(prefix);
|
|
5578
|
+
while (used.has(id)) {
|
|
5579
|
+
id = document2Id(prefix);
|
|
5580
|
+
}
|
|
5581
|
+
return id;
|
|
5582
|
+
}
|
|
5583
|
+
function newBlockId(document2) {
|
|
5584
|
+
return unusedGeneratedId("block", documentIdentitySets(document2).blocks);
|
|
5585
|
+
}
|
|
5586
|
+
function newItemId(document2) {
|
|
5587
|
+
return unusedGeneratedId("item", documentIdentitySets(document2).items);
|
|
5588
|
+
}
|
|
5589
|
+
function newTokenId(document2, prefix) {
|
|
5590
|
+
return unusedGeneratedId(prefix, documentIdentitySets(document2).tokens);
|
|
5591
|
+
}
|
|
5592
|
+
function createCommandInlineField(document2, text) {
|
|
5593
|
+
const field = createInlineField2(text);
|
|
5594
|
+
const used = documentIdentitySets(document2);
|
|
5595
|
+
field.id = unusedGeneratedId("field", used.fields);
|
|
5596
|
+
field.tokens.forEach((token) => {
|
|
5597
|
+
token.id = unusedGeneratedId(token.kind, used.tokens);
|
|
5598
|
+
used.tokens.add(token.id);
|
|
5599
|
+
});
|
|
5600
|
+
return field;
|
|
5601
|
+
}
|
|
5602
|
+
function requireList(document2, listId) {
|
|
5603
|
+
const block = findBlock(document2.blocks, listId);
|
|
5604
|
+
if (!block) {
|
|
5605
|
+
throw new Document2CommandError("list_not_found", "Document list was not found");
|
|
5606
|
+
}
|
|
5607
|
+
if (block.kind !== "list") {
|
|
5608
|
+
throw new Document2CommandError("block_kind_mismatch", "Target block is not a list");
|
|
5609
|
+
}
|
|
5610
|
+
return block;
|
|
5611
|
+
}
|
|
5612
|
+
function requireTable(document2, tableId) {
|
|
5613
|
+
const block = findBlock(document2.blocks, tableId);
|
|
5614
|
+
if (!block) {
|
|
5615
|
+
throw new Document2CommandError("table_not_found", "Document table was not found");
|
|
5616
|
+
}
|
|
5617
|
+
if (block.kind !== "table") {
|
|
5618
|
+
throw new Document2CommandError("block_kind_mismatch", "Target block is not a table");
|
|
5619
|
+
}
|
|
5620
|
+
return block;
|
|
5621
|
+
}
|
|
5622
|
+
function fieldHasStructuredContent(field) {
|
|
5623
|
+
return field.tokens.some((token) => token.kind !== "text" || token.style !== void 0);
|
|
5624
|
+
}
|
|
5625
|
+
function replacePlainField(document2, field, text) {
|
|
5626
|
+
if (fieldHasStructuredContent(field)) {
|
|
5627
|
+
throw new Document2CommandError(
|
|
5628
|
+
"unsupported_inline_content",
|
|
5629
|
+
"Whole-field replacement is not supported for formatted or structured inline content"
|
|
5630
|
+
);
|
|
5631
|
+
}
|
|
5632
|
+
const next = createCommandInlineField(document2, text);
|
|
5633
|
+
field.tokens = next.tokens;
|
|
5634
|
+
}
|
|
5635
|
+
function textStylesEqual3(a, b) {
|
|
5636
|
+
return Boolean(a?.bold) === Boolean(b?.bold) && Boolean(a?.italic) === Boolean(b?.italic) && Boolean(a?.underline) === Boolean(b?.underline);
|
|
5637
|
+
}
|
|
5638
|
+
function compactTextTokens2(tokens, emptyTokenId = document2Id("text")) {
|
|
5639
|
+
const compacted = [];
|
|
5640
|
+
for (const token of tokens) {
|
|
5641
|
+
const previous = compacted[compacted.length - 1];
|
|
5642
|
+
if (previous?.kind === "text" && token.kind === "text" && textStylesEqual3(previous.style, token.style)) {
|
|
5643
|
+
previous.text += token.text;
|
|
5644
|
+
} else {
|
|
5645
|
+
compacted.push(token);
|
|
5646
|
+
}
|
|
5647
|
+
}
|
|
5648
|
+
return compacted.length > 0 ? compacted : [{ id: emptyTokenId, kind: "text", text: "" }];
|
|
5649
|
+
}
|
|
5650
|
+
|
|
5651
|
+
// src/document2/inlineJsonCommands.ts
|
|
5652
|
+
function parseInlineAnchor(value) {
|
|
5653
|
+
if (!isObject3(value)) {
|
|
5654
|
+
throw new Document2CommandError("invalid_anchor", "anchor must be an object");
|
|
5655
|
+
}
|
|
5656
|
+
const before = typeof value.before_token_id === "string" ? value.before_token_id.trim() : "";
|
|
5657
|
+
const after = typeof value.after_token_id === "string" ? value.after_token_id.trim() : "";
|
|
5658
|
+
const choices = Number(before.length > 0) + Number(after.length > 0) + Number(value.start === true) + Number(value.end === true);
|
|
5659
|
+
if (choices !== 1) {
|
|
5660
|
+
throw new Document2CommandError("invalid_anchor", "anchor requires exactly one inline-token position");
|
|
5661
|
+
}
|
|
5662
|
+
if (before) {
|
|
5663
|
+
return { before_token_id: before };
|
|
5664
|
+
}
|
|
5665
|
+
if (after) {
|
|
5666
|
+
return { after_token_id: after };
|
|
5667
|
+
}
|
|
5668
|
+
return value.start === true ? { start: true } : { end: true };
|
|
5669
|
+
}
|
|
5670
|
+
function parseStyle(value) {
|
|
5671
|
+
if (value === void 0) {
|
|
5672
|
+
return void 0;
|
|
5673
|
+
}
|
|
5674
|
+
if (!isObject3(value)) {
|
|
5675
|
+
throw new Document2CommandError("invalid_inline_token", "text token style must be an object");
|
|
5676
|
+
}
|
|
5677
|
+
const style = {};
|
|
5678
|
+
for (const key of ["bold", "italic", "underline"]) {
|
|
5679
|
+
if (value[key] !== void 0 && value[key] !== true) {
|
|
5680
|
+
throw new Document2CommandError("invalid_inline_token", `text token style.${key} must be true when provided`);
|
|
5681
|
+
}
|
|
5682
|
+
if (value[key] === true) {
|
|
5683
|
+
style[key] = true;
|
|
5684
|
+
}
|
|
5685
|
+
}
|
|
5686
|
+
return style.bold || style.italic || style.underline ? style : void 0;
|
|
5687
|
+
}
|
|
5688
|
+
function normalizedKeys(value) {
|
|
5689
|
+
if (!Array.isArray(value)) {
|
|
5690
|
+
throw new Document2CommandError("invalid_inline_token", "citation/reference keys must be an array");
|
|
5691
|
+
}
|
|
5692
|
+
const keys = [];
|
|
5693
|
+
for (const entry of value) {
|
|
5694
|
+
if (typeof entry !== "string") {
|
|
5695
|
+
throw new Document2CommandError("invalid_inline_token", "citation/reference keys must be strings");
|
|
5696
|
+
}
|
|
5697
|
+
const key = entry.trim();
|
|
5698
|
+
if (key.length > 0 && !keys.includes(key)) {
|
|
5699
|
+
keys.push(key);
|
|
5700
|
+
}
|
|
5701
|
+
}
|
|
5702
|
+
if (keys.length === 0) {
|
|
5703
|
+
throw new Document2CommandError("invalid_inline_token", "citation/reference requires at least one non-empty key");
|
|
5704
|
+
}
|
|
5705
|
+
return keys;
|
|
5706
|
+
}
|
|
5707
|
+
function parseMathObject(value, source) {
|
|
5708
|
+
if (!isObject3(value) || value.node_type !== "MathObject") {
|
|
5709
|
+
throw new Document2CommandError("math_object_mismatch", "math_object must be a structured MathObject");
|
|
5710
|
+
}
|
|
5711
|
+
const spans = detectInlineSpans2(source);
|
|
5712
|
+
const span = spans[0];
|
|
5713
|
+
if (spans.length !== 1 || span?.kind !== "math" || span.start !== 0 || span.end !== source.length) {
|
|
5714
|
+
throw new Document2CommandError("math_object_mismatch", "math source must contain exactly one complete delimited span");
|
|
5715
|
+
}
|
|
5716
|
+
if (value.math_mode !== span.opening || value.closing !== span.closing) {
|
|
5717
|
+
throw new Document2CommandError("math_object_mismatch", "math_object delimiters do not match math source");
|
|
5718
|
+
}
|
|
5719
|
+
try {
|
|
5720
|
+
fromMathObjectJson(value, value.source_side === "arabic" ? "arabic" : "english");
|
|
5721
|
+
} catch {
|
|
5722
|
+
throw new Document2CommandError("math_object_mismatch", "math_object must contain a valid structured equation");
|
|
5723
|
+
}
|
|
5724
|
+
return value;
|
|
5725
|
+
}
|
|
5726
|
+
function parseToken(value) {
|
|
5727
|
+
if (!isObject3(value) || typeof value.kind !== "string") {
|
|
5728
|
+
throw new Document2CommandError("invalid_inline_token", "token requires a kind");
|
|
5729
|
+
}
|
|
5730
|
+
if (value.kind === "text") {
|
|
5731
|
+
const text = requireString2(value.text, "token.text");
|
|
5732
|
+
if (detectInlineSpans2(text).length > 0) {
|
|
5733
|
+
throw new Document2CommandError("invalid_inline_token", "text token contains structured inline syntax");
|
|
5734
|
+
}
|
|
5735
|
+
const style = parseStyle(value.style);
|
|
5736
|
+
return { kind: "text", text, ...style ? { style } : {} };
|
|
5737
|
+
}
|
|
5738
|
+
if (value.kind === "cite") {
|
|
5739
|
+
return { kind: "cite", keys: normalizedKeys(value.keys) };
|
|
5740
|
+
}
|
|
5741
|
+
if (value.kind === "ref") {
|
|
5742
|
+
if (value.ref_command !== "ref" && value.ref_command !== "eqref") {
|
|
5743
|
+
throw new Document2CommandError("invalid_inline_token", "ref_command must be ref or eqref");
|
|
5744
|
+
}
|
|
5745
|
+
return { kind: "ref", keys: normalizedKeys(value.keys), ref_command: value.ref_command };
|
|
5746
|
+
}
|
|
5747
|
+
if (value.kind === "math") {
|
|
5748
|
+
const source = requireString2(value.source, "token.source", false);
|
|
5749
|
+
return { kind: "math", source, math_object: parseMathObject(value.math_object, source) };
|
|
5750
|
+
}
|
|
5751
|
+
throw new Document2CommandError("invalid_inline_token", "Unsupported inline token kind");
|
|
5752
|
+
}
|
|
5753
|
+
function parseInlineCommand(value) {
|
|
5754
|
+
if (value.op === "insert_inline_token") {
|
|
5755
|
+
return {
|
|
5756
|
+
op: value.op,
|
|
5757
|
+
field_id: requireString2(value.field_id, "field_id", false).trim(),
|
|
5758
|
+
token: parseToken(value.token),
|
|
5759
|
+
anchor: parseInlineAnchor(value.anchor)
|
|
5760
|
+
};
|
|
5761
|
+
}
|
|
5762
|
+
if (value.op === "replace_inline_token") {
|
|
5763
|
+
return {
|
|
5764
|
+
op: value.op,
|
|
5765
|
+
field_id: requireString2(value.field_id, "field_id", false).trim(),
|
|
5766
|
+
token_id: requireString2(value.token_id, "token_id", false).trim(),
|
|
5767
|
+
token: parseToken(value.token)
|
|
5768
|
+
};
|
|
5769
|
+
}
|
|
5770
|
+
if (value.op === "remove_inline_token") {
|
|
5771
|
+
return {
|
|
5772
|
+
op: value.op,
|
|
5773
|
+
field_id: requireString2(value.field_id, "field_id", false).trim(),
|
|
5774
|
+
token_id: requireString2(value.token_id, "token_id", false).trim()
|
|
5775
|
+
};
|
|
5776
|
+
}
|
|
5777
|
+
throw new Document2CommandError("invalid_command", "Unsupported inline command");
|
|
5778
|
+
}
|
|
5779
|
+
function liveToken(input, id) {
|
|
5780
|
+
if (input.kind === "text") {
|
|
5781
|
+
return { id, kind: "text", text: input.text, ...input.style ? { style: { ...input.style } } : {} };
|
|
5782
|
+
}
|
|
5783
|
+
if (input.kind === "cite") {
|
|
5784
|
+
return { id, kind: "cite", keys: [...input.keys] };
|
|
5785
|
+
}
|
|
5786
|
+
if (input.kind === "ref") {
|
|
5787
|
+
return { id, kind: "ref", keys: [...input.keys], refCommand: input.ref_command };
|
|
5788
|
+
}
|
|
5789
|
+
const mathObject = input.math_object;
|
|
5790
|
+
const spans = detectInlineSpans2(input.source);
|
|
5791
|
+
const span = spans[0];
|
|
5792
|
+
if (!span || span.kind !== "math") {
|
|
5793
|
+
throw new Document2CommandError("math_object_mismatch", "math source is not a complete delimited span");
|
|
5794
|
+
}
|
|
5795
|
+
return {
|
|
5796
|
+
id,
|
|
5797
|
+
kind: "math",
|
|
5798
|
+
display: span.display,
|
|
5799
|
+
opening: span.opening,
|
|
5800
|
+
closing: span.closing,
|
|
5801
|
+
source: input.source,
|
|
5802
|
+
sourceSide: mathObject.source_side === "arabic" ? "arabic" : "english",
|
|
5803
|
+
math: fromMathObjectJson(mathObject, mathObject.source_side === "arabic" ? "arabic" : "english"),
|
|
5804
|
+
editable: true,
|
|
5805
|
+
sourceOwner: mathObject.source_owner === "editor" ? "editor" : "imported-structured",
|
|
5806
|
+
...mathObject.label_enabled !== void 0 ? { labelEnabled: mathObject.label_enabled } : {},
|
|
5807
|
+
...mathObject.label !== void 0 ? { label: mathObject.label } : {}
|
|
5808
|
+
};
|
|
5809
|
+
}
|
|
5810
|
+
function insertionIndex(tokens, anchor) {
|
|
5811
|
+
if ("start" in anchor) {
|
|
5812
|
+
return 0;
|
|
5813
|
+
}
|
|
5814
|
+
if ("end" in anchor) {
|
|
5815
|
+
return tokens.length;
|
|
5816
|
+
}
|
|
5817
|
+
const id = "before_token_id" in anchor ? anchor.before_token_id : anchor.after_token_id;
|
|
5818
|
+
const index = tokens.findIndex((token) => token.id === id);
|
|
5819
|
+
if (index < 0) {
|
|
5820
|
+
throw new Document2CommandError("token_not_found", "Anchor token was not found");
|
|
5821
|
+
}
|
|
5822
|
+
return "before_token_id" in anchor ? index : index + 1;
|
|
5823
|
+
}
|
|
5824
|
+
function applyInlineCommand(document2, command) {
|
|
5825
|
+
const field = findField(document2.blocks, command.field_id);
|
|
5826
|
+
if (!field) {
|
|
5827
|
+
throw new Document2CommandError("field_not_found", "Inline field was not found");
|
|
5828
|
+
}
|
|
5829
|
+
if (command.op === "insert_inline_token") {
|
|
5830
|
+
const index2 = insertionIndex(field.tokens, command.anchor);
|
|
5831
|
+
field.tokens.splice(index2, 0, liveToken(command.token, newTokenId(document2, command.token.kind)));
|
|
5832
|
+
return;
|
|
5833
|
+
}
|
|
5834
|
+
const index = field.tokens.findIndex((token) => token.id === command.token_id);
|
|
5835
|
+
if (index < 0) {
|
|
5836
|
+
throw new Document2CommandError("token_not_found", "Inline token was not found");
|
|
5837
|
+
}
|
|
5838
|
+
if (command.op === "replace_inline_token") {
|
|
5839
|
+
field.tokens[index] = liveToken(command.token, command.token_id);
|
|
5840
|
+
return;
|
|
5841
|
+
}
|
|
5842
|
+
field.tokens = compactTextTokens2(
|
|
5843
|
+
[...field.tokens.slice(0, index), ...field.tokens.slice(index + 1)],
|
|
5844
|
+
newTokenId(document2, "text")
|
|
5845
|
+
);
|
|
5846
|
+
}
|
|
5847
|
+
|
|
5848
|
+
// src/document2/listJsonCommands.ts
|
|
5849
|
+
function stringArray(value, field) {
|
|
5850
|
+
if (!Array.isArray(value) || value.length === 0 || value.some((entry) => typeof entry !== "string")) {
|
|
5851
|
+
throw new Document2CommandError("invalid_command", `${field} must be a non-empty string array`);
|
|
5852
|
+
}
|
|
5853
|
+
return [...value];
|
|
5854
|
+
}
|
|
5855
|
+
function parseListCommand(value) {
|
|
5856
|
+
if (value.op === "insert_list") {
|
|
5857
|
+
const metadata = parseMetadata(value.metadata);
|
|
5858
|
+
return {
|
|
5859
|
+
op: value.op,
|
|
5860
|
+
ordered: requireBoolean(value.ordered, "ordered"),
|
|
5861
|
+
items: stringArray(value.items, "items"),
|
|
5862
|
+
anchor: parseBlockAnchor(value.anchor),
|
|
5863
|
+
...metadata ? { metadata } : {}
|
|
5864
|
+
};
|
|
5865
|
+
}
|
|
5866
|
+
if (value.op === "insert_list_item") {
|
|
5867
|
+
return {
|
|
5868
|
+
op: value.op,
|
|
5869
|
+
list_id: requireString2(value.list_id, "list_id", false).trim(),
|
|
5870
|
+
text: requireString2(value.text, "text"),
|
|
5871
|
+
anchor: parseListItemAnchor(value.anchor)
|
|
5872
|
+
};
|
|
5873
|
+
}
|
|
5874
|
+
if (value.op === "replace_list_item") {
|
|
5875
|
+
return {
|
|
5876
|
+
op: value.op,
|
|
5877
|
+
list_id: requireString2(value.list_id, "list_id", false).trim(),
|
|
5878
|
+
item_id: requireString2(value.item_id, "item_id", false).trim(),
|
|
5879
|
+
text: requireString2(value.text, "text")
|
|
5880
|
+
};
|
|
5881
|
+
}
|
|
5882
|
+
if (value.op === "remove_list_item") {
|
|
5883
|
+
return {
|
|
5884
|
+
op: value.op,
|
|
5885
|
+
list_id: requireString2(value.list_id, "list_id", false).trim(),
|
|
5886
|
+
item_id: requireString2(value.item_id, "item_id", false).trim()
|
|
5887
|
+
};
|
|
5888
|
+
}
|
|
5889
|
+
if (value.op === "move_list_item") {
|
|
5890
|
+
return {
|
|
5891
|
+
op: value.op,
|
|
5892
|
+
list_id: requireString2(value.list_id, "list_id", false).trim(),
|
|
5893
|
+
item_id: requireString2(value.item_id, "item_id", false).trim(),
|
|
5894
|
+
anchor: parseListItemAnchor(value.anchor)
|
|
5895
|
+
};
|
|
5896
|
+
}
|
|
5897
|
+
throw new Document2CommandError("invalid_command", "Unsupported list command");
|
|
5898
|
+
}
|
|
5899
|
+
function newItem(document2, text) {
|
|
5900
|
+
return { id: newItemId(document2), field: createCommandInlineField(document2, text), blocks: [] };
|
|
5901
|
+
}
|
|
5902
|
+
function insertList(document2, command) {
|
|
5903
|
+
const ordered = command.ordered;
|
|
5904
|
+
const block = {
|
|
5905
|
+
id: newBlockId(document2),
|
|
5906
|
+
kind: "list",
|
|
5907
|
+
command: ordered ? "\\begin{enumerate}" : "\\begin{itemize}",
|
|
5908
|
+
closing: ordered ? "\\end{enumerate}" : "\\end{itemize}",
|
|
5909
|
+
items: command.items.map((text) => newItem(document2, text)),
|
|
5910
|
+
...command.metadata ? { metadata: { ...command.metadata } } : {}
|
|
5911
|
+
};
|
|
5912
|
+
document2.blocks.splice(blockInsertionIndex(document2, command.anchor), 0, block);
|
|
5913
|
+
}
|
|
5914
|
+
function applyListCommand(document2, command) {
|
|
5915
|
+
if (command.op === "insert_list") {
|
|
5916
|
+
insertList(document2, command);
|
|
5917
|
+
return;
|
|
5918
|
+
}
|
|
5919
|
+
const list = requireList(document2, command.list_id);
|
|
5920
|
+
if (command.op === "insert_list_item") {
|
|
5921
|
+
list.items.splice(itemInsertionIndex(list, command.anchor), 0, newItem(document2, command.text));
|
|
5922
|
+
return;
|
|
5923
|
+
}
|
|
5924
|
+
const itemIndex = list.items.findIndex((item2) => item2.id === command.item_id);
|
|
5925
|
+
if (itemIndex < 0) {
|
|
5926
|
+
throw new Document2CommandError("item_not_found", "Document list item was not found");
|
|
5927
|
+
}
|
|
5928
|
+
if (command.op === "replace_list_item") {
|
|
5929
|
+
replacePlainField(document2, list.items[itemIndex].field, command.text);
|
|
5930
|
+
return;
|
|
5931
|
+
}
|
|
5932
|
+
if (command.op === "remove_list_item") {
|
|
5933
|
+
if (list.items.length === 1) {
|
|
5934
|
+
throw new Document2CommandError("minimum_structure", "A list must retain at least one item");
|
|
5935
|
+
}
|
|
5936
|
+
list.items.splice(itemIndex, 1);
|
|
5937
|
+
return;
|
|
5938
|
+
}
|
|
5939
|
+
const anchorId = "before_item_id" in command.anchor ? command.anchor.before_item_id : "after_item_id" in command.anchor ? command.anchor.after_item_id : null;
|
|
5940
|
+
if (anchorId === command.item_id) {
|
|
5941
|
+
throw new Document2CommandError("invalid_anchor", "A list item cannot be moved relative to itself");
|
|
5942
|
+
}
|
|
5943
|
+
const [item] = list.items.splice(itemIndex, 1);
|
|
5944
|
+
if (!item) {
|
|
5945
|
+
throw new Document2CommandError("item_not_found", "Document list item was not found");
|
|
5946
|
+
}
|
|
5947
|
+
list.items.splice(itemInsertionIndex(list, command.anchor), 0, item);
|
|
5948
|
+
}
|
|
5949
|
+
|
|
5950
|
+
// src/document2/tableJsonCommands.ts
|
|
5951
|
+
function stringArray2(value, field) {
|
|
5952
|
+
if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) {
|
|
5953
|
+
throw new Document2CommandError("invalid_command", `${field} must be a string array`);
|
|
5954
|
+
}
|
|
5955
|
+
return [...value];
|
|
5956
|
+
}
|
|
5957
|
+
function rectangularRows(value) {
|
|
5958
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
5959
|
+
throw new Document2CommandError("invalid_table_shape", "rows must be a non-empty array");
|
|
5960
|
+
}
|
|
5961
|
+
const rows = value.map((row, index) => stringArray2(row, `rows[${String(index)}]`));
|
|
5962
|
+
const columnCount = rows[0]?.length ?? 0;
|
|
5963
|
+
if (columnCount === 0 || rows.some((row) => row.length !== columnCount)) {
|
|
5964
|
+
throw new Document2CommandError("invalid_table_shape", "Table rows must form a non-empty rectangle");
|
|
5965
|
+
}
|
|
5966
|
+
return rows;
|
|
5967
|
+
}
|
|
5968
|
+
function columns(value) {
|
|
5969
|
+
const result = requireString2(value, "columns", false);
|
|
5970
|
+
if (result.trim().length === 0) {
|
|
5971
|
+
throw new Document2CommandError("invalid_table_shape", "columns must be a non-empty LaTeX specification");
|
|
5972
|
+
}
|
|
5973
|
+
return result;
|
|
5974
|
+
}
|
|
5975
|
+
function parseTableCommand(value) {
|
|
5976
|
+
if (value.op === "insert_table") {
|
|
5977
|
+
const caption = optionalString(value, "caption");
|
|
5978
|
+
const label = optionalString(value, "label");
|
|
5979
|
+
const metadata = parseMetadata(value.metadata);
|
|
5980
|
+
return {
|
|
5981
|
+
op: value.op,
|
|
5982
|
+
rows: rectangularRows(value.rows),
|
|
5983
|
+
columns: columns(value.columns),
|
|
5984
|
+
...caption !== void 0 ? { caption } : {},
|
|
5985
|
+
...label !== void 0 ? { label } : {},
|
|
5986
|
+
anchor: parseBlockAnchor(value.anchor),
|
|
5987
|
+
...metadata ? { metadata } : {}
|
|
5988
|
+
};
|
|
5989
|
+
}
|
|
5990
|
+
if (value.op === "replace_table_cell") {
|
|
5991
|
+
return {
|
|
5992
|
+
op: value.op,
|
|
5993
|
+
table_id: requireString2(value.table_id, "table_id", false).trim(),
|
|
5994
|
+
row_index: requireIndex(value.row_index, "row_index"),
|
|
5995
|
+
column_index: requireIndex(value.column_index, "column_index"),
|
|
5996
|
+
text: requireString2(value.text, "text")
|
|
5997
|
+
};
|
|
5998
|
+
}
|
|
5999
|
+
if (value.op === "insert_table_row") {
|
|
6000
|
+
return {
|
|
6001
|
+
op: value.op,
|
|
6002
|
+
table_id: requireString2(value.table_id, "table_id", false).trim(),
|
|
6003
|
+
index: requireIndex(value.index, "index"),
|
|
6004
|
+
values: stringArray2(value.values, "values")
|
|
6005
|
+
};
|
|
6006
|
+
}
|
|
6007
|
+
if (value.op === "remove_table_row") {
|
|
6008
|
+
return {
|
|
6009
|
+
op: value.op,
|
|
6010
|
+
table_id: requireString2(value.table_id, "table_id", false).trim(),
|
|
6011
|
+
index: requireIndex(value.index, "index")
|
|
6012
|
+
};
|
|
6013
|
+
}
|
|
6014
|
+
if (value.op === "move_table_row") {
|
|
6015
|
+
return {
|
|
6016
|
+
op: value.op,
|
|
6017
|
+
table_id: requireString2(value.table_id, "table_id", false).trim(),
|
|
6018
|
+
from_index: requireIndex(value.from_index, "from_index"),
|
|
6019
|
+
to_index: requireIndex(value.to_index, "to_index")
|
|
6020
|
+
};
|
|
6021
|
+
}
|
|
6022
|
+
if (value.op === "insert_table_column") {
|
|
6023
|
+
return {
|
|
6024
|
+
op: value.op,
|
|
6025
|
+
table_id: requireString2(value.table_id, "table_id", false).trim(),
|
|
6026
|
+
index: requireIndex(value.index, "index"),
|
|
6027
|
+
values: stringArray2(value.values, "values"),
|
|
6028
|
+
columns: columns(value.columns)
|
|
6029
|
+
};
|
|
6030
|
+
}
|
|
6031
|
+
if (value.op === "remove_table_column") {
|
|
6032
|
+
return {
|
|
6033
|
+
op: value.op,
|
|
6034
|
+
table_id: requireString2(value.table_id, "table_id", false).trim(),
|
|
6035
|
+
index: requireIndex(value.index, "index"),
|
|
6036
|
+
columns: columns(value.columns)
|
|
6037
|
+
};
|
|
6038
|
+
}
|
|
6039
|
+
if (value.op === "move_table_column") {
|
|
6040
|
+
return {
|
|
6041
|
+
op: value.op,
|
|
6042
|
+
table_id: requireString2(value.table_id, "table_id", false).trim(),
|
|
6043
|
+
from_index: requireIndex(value.from_index, "from_index"),
|
|
6044
|
+
to_index: requireIndex(value.to_index, "to_index"),
|
|
6045
|
+
columns: columns(value.columns)
|
|
6046
|
+
};
|
|
6047
|
+
}
|
|
6048
|
+
throw new Document2CommandError("invalid_command", "Unsupported table command");
|
|
6049
|
+
}
|
|
6050
|
+
function insertTable(document2, command) {
|
|
6051
|
+
const block = {
|
|
6052
|
+
id: newBlockId(document2),
|
|
6053
|
+
kind: "table",
|
|
6054
|
+
command: "\\begin{tabular}",
|
|
6055
|
+
closing: "\\end{tabular}",
|
|
6056
|
+
columns: command.columns,
|
|
6057
|
+
rows: command.rows.map((row) => row.map((cell) => createCommandInlineField(document2, cell))),
|
|
6058
|
+
...defaultFloatMeta(),
|
|
6059
|
+
...command.caption !== void 0 ? { caption: command.caption, captionEnabled: command.caption.trim().length > 0 } : {},
|
|
6060
|
+
...command.label !== void 0 ? { label: command.label, labelEnabled: command.label.trim().length > 0 } : {},
|
|
6061
|
+
...command.metadata ? { metadata: { ...command.metadata } } : {}
|
|
6062
|
+
};
|
|
6063
|
+
document2.blocks.splice(blockInsertionIndex(document2, command.anchor), 0, block);
|
|
6064
|
+
}
|
|
6065
|
+
function checkCell(table, rowIndex, columnIndex) {
|
|
6066
|
+
if (rowIndex >= table.rows.length || columnIndex >= (table.rows[rowIndex]?.length ?? 0)) {
|
|
6067
|
+
throw new Document2CommandError("index_out_of_range", "Table cell index is out of range");
|
|
6068
|
+
}
|
|
6069
|
+
}
|
|
6070
|
+
function checkExistingIndex(index, length, field) {
|
|
6071
|
+
if (index >= length) {
|
|
6072
|
+
throw new Document2CommandError("index_out_of_range", `${field} is out of range`);
|
|
6073
|
+
}
|
|
6074
|
+
}
|
|
6075
|
+
function applyTableCommand(document2, command) {
|
|
6076
|
+
if (command.op === "insert_table") {
|
|
6077
|
+
insertTable(document2, command);
|
|
6078
|
+
return;
|
|
6079
|
+
}
|
|
6080
|
+
const table = requireTable(document2, command.table_id);
|
|
6081
|
+
const columnCount = table.rows[0]?.length ?? 0;
|
|
6082
|
+
if (table.rows.length === 0 || columnCount === 0 || table.rows.some((row) => row.length !== columnCount)) {
|
|
6083
|
+
throw new Document2CommandError("invalid_table_shape", "Target table must be a non-empty rectangle");
|
|
6084
|
+
}
|
|
6085
|
+
if (command.op === "replace_table_cell") {
|
|
6086
|
+
checkCell(table, command.row_index, command.column_index);
|
|
6087
|
+
replacePlainField(document2, table.rows[command.row_index][command.column_index], command.text);
|
|
6088
|
+
return;
|
|
6089
|
+
}
|
|
6090
|
+
if (command.op === "insert_table_row") {
|
|
6091
|
+
if (command.index > table.rows.length) {
|
|
6092
|
+
throw new Document2CommandError("index_out_of_range", "Table row insertion index is out of range");
|
|
6093
|
+
}
|
|
6094
|
+
if (command.values.length !== columnCount) {
|
|
6095
|
+
throw new Document2CommandError("invalid_table_shape", "Inserted row must match the current column count");
|
|
6096
|
+
}
|
|
6097
|
+
table.rows.splice(command.index, 0, command.values.map((value) => createCommandInlineField(document2, value)));
|
|
6098
|
+
return;
|
|
6099
|
+
}
|
|
6100
|
+
if (command.op === "remove_table_row") {
|
|
6101
|
+
checkExistingIndex(command.index, table.rows.length, "Table row index");
|
|
6102
|
+
if (table.rows.length === 1) {
|
|
6103
|
+
throw new Document2CommandError("minimum_structure", "A table must retain at least one row");
|
|
6104
|
+
}
|
|
6105
|
+
table.rows.splice(command.index, 1);
|
|
6106
|
+
return;
|
|
6107
|
+
}
|
|
6108
|
+
if (command.op === "move_table_row") {
|
|
6109
|
+
checkExistingIndex(command.from_index, table.rows.length, "Table source row index");
|
|
6110
|
+
checkExistingIndex(command.to_index, table.rows.length, "Table target row index");
|
|
6111
|
+
const [row] = table.rows.splice(command.from_index, 1);
|
|
6112
|
+
table.rows.splice(command.to_index, 0, row);
|
|
6113
|
+
return;
|
|
6114
|
+
}
|
|
6115
|
+
if (command.op === "insert_table_column") {
|
|
6116
|
+
if (command.index > columnCount) {
|
|
6117
|
+
throw new Document2CommandError("index_out_of_range", "Table column insertion index is out of range");
|
|
6118
|
+
}
|
|
6119
|
+
if (command.values.length !== table.rows.length) {
|
|
6120
|
+
throw new Document2CommandError("invalid_table_shape", "Inserted column requires one value per row");
|
|
6121
|
+
}
|
|
6122
|
+
table.rows.forEach((row, index) => row.splice(command.index, 0, createCommandInlineField(document2, command.values[index])));
|
|
6123
|
+
table.columns = command.columns;
|
|
6124
|
+
return;
|
|
6125
|
+
}
|
|
6126
|
+
if (command.op === "remove_table_column") {
|
|
6127
|
+
checkExistingIndex(command.index, columnCount, "Table column index");
|
|
6128
|
+
if (columnCount === 1) {
|
|
6129
|
+
throw new Document2CommandError("minimum_structure", "A table must retain at least one column");
|
|
6130
|
+
}
|
|
6131
|
+
table.rows.forEach((row) => row.splice(command.index, 1));
|
|
6132
|
+
table.columns = command.columns;
|
|
6133
|
+
return;
|
|
6134
|
+
}
|
|
6135
|
+
checkExistingIndex(command.from_index, columnCount, "Table source column index");
|
|
6136
|
+
checkExistingIndex(command.to_index, columnCount, "Table target column index");
|
|
6137
|
+
table.rows.forEach((row) => {
|
|
6138
|
+
const [cell] = row.splice(command.from_index, 1);
|
|
6139
|
+
row.splice(command.to_index, 0, cell);
|
|
6140
|
+
});
|
|
6141
|
+
table.columns = command.columns;
|
|
6142
|
+
}
|
|
6143
|
+
|
|
5296
6144
|
// src/document2/exportJson.ts
|
|
5297
6145
|
function serializeField(field) {
|
|
5298
6146
|
let value = "";
|
|
@@ -5345,12 +6193,13 @@ function serializeField(field) {
|
|
|
5345
6193
|
...token.label !== void 0 ? { label: token.label } : {}
|
|
5346
6194
|
});
|
|
5347
6195
|
}
|
|
5348
|
-
return { value, formats, mathObjects, hasPersistedMath };
|
|
6196
|
+
return { value, formats, mathObjects, hasPersistedMath, inlineIds: inlineIdsFromField(field) };
|
|
5349
6197
|
}
|
|
5350
6198
|
function fieldJson(field) {
|
|
5351
6199
|
const serialized = serializeField(field);
|
|
5352
6200
|
return {
|
|
5353
6201
|
value: serialized.value,
|
|
6202
|
+
inline_ids: serialized.inlineIds,
|
|
5354
6203
|
...serialized.formats.length > 0 ? { formats: serialized.formats } : {},
|
|
5355
6204
|
...serialized.hasPersistedMath ? { math_objects: serialized.mathObjects } : {}
|
|
5356
6205
|
};
|
|
@@ -5358,7 +6207,9 @@ function fieldJson(field) {
|
|
|
5358
6207
|
function listItemJson(item) {
|
|
5359
6208
|
const field = fieldJson(item.field);
|
|
5360
6209
|
return {
|
|
6210
|
+
id: item.id,
|
|
5361
6211
|
value: field.value ?? "",
|
|
6212
|
+
inline_ids: field.inline_ids,
|
|
5362
6213
|
...field.formats ? { formats: field.formats } : {},
|
|
5363
6214
|
...field.math_objects ? { math_objects: field.math_objects } : {},
|
|
5364
6215
|
...item.blocks.length > 0 ? { blocks: item.blocks.map(blockJson) } : {}
|
|
@@ -5370,6 +6221,7 @@ function blockJson(block) {
|
|
|
5370
6221
|
id: block.id,
|
|
5371
6222
|
command: block.command,
|
|
5372
6223
|
...fieldJson(block.field),
|
|
6224
|
+
...block.metadata ? { metadata: { ...block.metadata } } : {},
|
|
5373
6225
|
...block.command === "\\paragraph" ? { centered: block.centered === true } : {}
|
|
5374
6226
|
};
|
|
5375
6227
|
}
|
|
@@ -5378,7 +6230,8 @@ function blockJson(block) {
|
|
|
5378
6230
|
id: block.id,
|
|
5379
6231
|
command: block.command,
|
|
5380
6232
|
closing: block.closing,
|
|
5381
|
-
items: block.items.map(listItemJson)
|
|
6233
|
+
items: block.items.map(listItemJson),
|
|
6234
|
+
...block.metadata ? { metadata: { ...block.metadata } } : {}
|
|
5382
6235
|
};
|
|
5383
6236
|
}
|
|
5384
6237
|
if (block.kind === "table") {
|
|
@@ -5390,13 +6243,15 @@ function blockJson(block) {
|
|
|
5390
6243
|
closing: block.closing,
|
|
5391
6244
|
columns: block.columns,
|
|
5392
6245
|
rows: fields.map((row) => row.map((field) => field.value)),
|
|
6246
|
+
cell_inline_ids: fields.map((row) => row.map((field) => field.inlineIds)),
|
|
5393
6247
|
...fields.some((row) => row.some((field) => field.formats.length > 0)) ? { cell_formats: fields.map((row) => row.map((field) => field.formats)) } : {},
|
|
5394
6248
|
...hasPersistedMath ? { math_objects: fields.flatMap((row) => row.flatMap((field) => field.mathObjects)) } : {},
|
|
5395
6249
|
centered: block.centered,
|
|
5396
6250
|
caption_enabled: block.captionEnabled,
|
|
5397
6251
|
caption: block.caption,
|
|
5398
6252
|
label_enabled: block.labelEnabled,
|
|
5399
|
-
label: block.label
|
|
6253
|
+
label: block.label,
|
|
6254
|
+
...block.metadata ? { metadata: { ...block.metadata } } : {}
|
|
5400
6255
|
};
|
|
5401
6256
|
}
|
|
5402
6257
|
if (block.kind === "image") {
|
|
@@ -5410,13 +6265,24 @@ function blockJson(block) {
|
|
|
5410
6265
|
caption_enabled: block.captionEnabled,
|
|
5411
6266
|
caption: block.caption,
|
|
5412
6267
|
label_enabled: block.labelEnabled,
|
|
5413
|
-
label: block.label
|
|
6268
|
+
label: block.label,
|
|
6269
|
+
...block.metadata ? { metadata: { ...block.metadata } } : {}
|
|
5414
6270
|
};
|
|
5415
6271
|
}
|
|
5416
6272
|
if (block.kind === "bibliography") {
|
|
5417
|
-
return {
|
|
6273
|
+
return {
|
|
6274
|
+
id: block.id,
|
|
6275
|
+
command: block.command,
|
|
6276
|
+
closing: block.closing,
|
|
6277
|
+
...block.metadata ? { metadata: { ...block.metadata } } : {}
|
|
6278
|
+
};
|
|
5418
6279
|
}
|
|
5419
|
-
return {
|
|
6280
|
+
return {
|
|
6281
|
+
id: block.id,
|
|
6282
|
+
command: block.command,
|
|
6283
|
+
value: block.value,
|
|
6284
|
+
...block.metadata ? { metadata: { ...block.metadata } } : {}
|
|
6285
|
+
};
|
|
5420
6286
|
}
|
|
5421
6287
|
function referenceJson(reference) {
|
|
5422
6288
|
return {
|
|
@@ -5447,49 +6313,14 @@ function toDocumentJson2(document2) {
|
|
|
5447
6313
|
}
|
|
5448
6314
|
|
|
5449
6315
|
// src/document2/jsonCommands.ts
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
constructor(code, message) {
|
|
5453
|
-
super(message);
|
|
5454
|
-
this.name = "Document2CommandError";
|
|
5455
|
-
this.code = code;
|
|
5456
|
-
}
|
|
5457
|
-
};
|
|
5458
|
-
function isObject3(value) {
|
|
5459
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6316
|
+
function isInlineCommand(command) {
|
|
6317
|
+
return command.op === "insert_inline_token" || command.op === "replace_inline_token" || command.op === "remove_inline_token";
|
|
5460
6318
|
}
|
|
5461
|
-
function
|
|
5462
|
-
|
|
5463
|
-
throw new Document2CommandError("invalid_command", `${field} must be a${allowEmpty ? "" : " non-empty"} string`);
|
|
5464
|
-
}
|
|
5465
|
-
return value;
|
|
6319
|
+
function isListCommand(command) {
|
|
6320
|
+
return command.op === "insert_list" || command.op === "insert_list_item" || command.op === "replace_list_item" || command.op === "remove_list_item" || command.op === "move_list_item";
|
|
5466
6321
|
}
|
|
5467
|
-
function
|
|
5468
|
-
|
|
5469
|
-
throw new Document2CommandError("invalid_command", "anchor must be an object");
|
|
5470
|
-
}
|
|
5471
|
-
const hasEnd = value.end === true;
|
|
5472
|
-
const afterBlockId2 = typeof value.after_block_id === "string" ? value.after_block_id.trim() : "";
|
|
5473
|
-
const hasAfterBlock = afterBlockId2.length > 0;
|
|
5474
|
-
if (hasEnd && hasAfterBlock) {
|
|
5475
|
-
throw new Document2CommandError("invalid_command", "anchor cannot contain both end and after_block_id");
|
|
5476
|
-
}
|
|
5477
|
-
if (hasEnd) {
|
|
5478
|
-
return { end: true };
|
|
5479
|
-
}
|
|
5480
|
-
if (hasAfterBlock) {
|
|
5481
|
-
return { after_block_id: afterBlockId2 };
|
|
5482
|
-
}
|
|
5483
|
-
throw new Document2CommandError("invalid_command", "anchor requires end: true or a non-empty after_block_id");
|
|
5484
|
-
}
|
|
5485
|
-
function optionalString(value, field) {
|
|
5486
|
-
if (!(field in value)) {
|
|
5487
|
-
return void 0;
|
|
5488
|
-
}
|
|
5489
|
-
if (typeof value[field] !== "string") {
|
|
5490
|
-
throw new Document2CommandError("invalid_command", `${field} must be a string when provided`);
|
|
5491
|
-
}
|
|
5492
|
-
return value[field];
|
|
6322
|
+
function isTableCommand(command) {
|
|
6323
|
+
return command.op === "insert_table" || command.op === "replace_table_cell" || command.op === "insert_table_row" || command.op === "remove_table_row" || command.op === "move_table_row" || command.op === "insert_table_column" || command.op === "remove_table_column" || command.op === "move_table_column";
|
|
5493
6324
|
}
|
|
5494
6325
|
function parseTextBlockKind(value) {
|
|
5495
6326
|
if (value === "section" || value === "subsection" || value === "subsubsection" || value === "paragraph") {
|
|
@@ -5497,16 +6328,15 @@ function parseTextBlockKind(value) {
|
|
|
5497
6328
|
}
|
|
5498
6329
|
throw new Document2CommandError("invalid_command", "kind must be section, subsection, subsubsection, or paragraph");
|
|
5499
6330
|
}
|
|
5500
|
-
function
|
|
5501
|
-
if (!isObject3(value) || typeof value.op !== "string") {
|
|
5502
|
-
throw new Document2CommandError("invalid_command", "command requires an op");
|
|
5503
|
-
}
|
|
6331
|
+
function parseBasicCommand(value) {
|
|
5504
6332
|
if (value.op === "insert_text_block") {
|
|
6333
|
+
const metadata = parseMetadata(value.metadata);
|
|
5505
6334
|
return {
|
|
5506
6335
|
op: value.op,
|
|
5507
6336
|
kind: parseTextBlockKind(value.kind),
|
|
5508
6337
|
text: requireString2(value.text, "text"),
|
|
5509
|
-
anchor:
|
|
6338
|
+
anchor: parseBlockAnchor(value.anchor),
|
|
6339
|
+
...metadata ? { metadata } : {}
|
|
5510
6340
|
};
|
|
5511
6341
|
}
|
|
5512
6342
|
if (value.op === "replace_text_block") {
|
|
@@ -5517,140 +6347,118 @@ function parseCommand2(value) {
|
|
|
5517
6347
|
};
|
|
5518
6348
|
}
|
|
5519
6349
|
if (value.op === "remove_block") {
|
|
5520
|
-
return {
|
|
5521
|
-
op: value.op,
|
|
5522
|
-
block_id: requireString2(value.block_id, "block_id", false).trim()
|
|
5523
|
-
};
|
|
6350
|
+
return { op: value.op, block_id: requireString2(value.block_id, "block_id", false).trim() };
|
|
5524
6351
|
}
|
|
5525
6352
|
if (value.op === "insert_figure") {
|
|
5526
6353
|
const figureValue = optionalString(value, "value");
|
|
5527
6354
|
const caption = optionalString(value, "caption");
|
|
5528
6355
|
const label = optionalString(value, "label");
|
|
6356
|
+
const metadata = parseMetadata(value.metadata);
|
|
5529
6357
|
return {
|
|
5530
6358
|
op: value.op,
|
|
5531
6359
|
asset_id: requireString2(value.asset_id, "asset_id", false).trim(),
|
|
5532
6360
|
...figureValue !== void 0 ? { value: figureValue } : {},
|
|
5533
6361
|
...caption !== void 0 ? { caption } : {},
|
|
5534
6362
|
...label !== void 0 ? { label } : {},
|
|
5535
|
-
anchor:
|
|
6363
|
+
anchor: parseBlockAnchor(value.anchor),
|
|
6364
|
+
...metadata ? { metadata } : {}
|
|
5536
6365
|
};
|
|
5537
6366
|
}
|
|
5538
|
-
throw new Document2CommandError("invalid_command",
|
|
6367
|
+
throw new Document2CommandError("invalid_command", "Unsupported block command");
|
|
6368
|
+
}
|
|
6369
|
+
function parseCommand2(value) {
|
|
6370
|
+
if (!isObject3(value) || typeof value.op !== "string") {
|
|
6371
|
+
throw new Document2CommandError("invalid_command", "command requires an op");
|
|
6372
|
+
}
|
|
6373
|
+
if (value.op === "insert_inline_token" || value.op === "replace_inline_token" || value.op === "remove_inline_token") {
|
|
6374
|
+
return parseInlineCommand(value);
|
|
6375
|
+
}
|
|
6376
|
+
if (value.op === "insert_list" || value.op === "insert_list_item" || value.op === "replace_list_item" || value.op === "remove_list_item" || value.op === "move_list_item") {
|
|
6377
|
+
return parseListCommand(value);
|
|
6378
|
+
}
|
|
6379
|
+
if (value.op === "insert_table" || value.op === "replace_table_cell" || value.op === "insert_table_row" || value.op === "remove_table_row" || value.op === "move_table_row" || value.op === "insert_table_column" || value.op === "remove_table_column" || value.op === "move_table_column") {
|
|
6380
|
+
return parseTableCommand(value);
|
|
6381
|
+
}
|
|
6382
|
+
if (value.op === "insert_text_block" || value.op === "replace_text_block" || value.op === "remove_block" || value.op === "insert_figure") {
|
|
6383
|
+
return parseBasicCommand(value);
|
|
6384
|
+
}
|
|
6385
|
+
throw new Document2CommandError("invalid_command", "Unsupported document command");
|
|
5539
6386
|
}
|
|
5540
6387
|
function parseDocument(json) {
|
|
5541
6388
|
try {
|
|
5542
6389
|
return fromDocumentJson2(json);
|
|
5543
|
-
} catch
|
|
5544
|
-
|
|
5545
|
-
throw new Document2CommandError("invalid_document", message);
|
|
6390
|
+
} catch {
|
|
6391
|
+
throw new Document2CommandError("invalid_document", "Document JSON is invalid");
|
|
5546
6392
|
}
|
|
5547
6393
|
}
|
|
5548
|
-
function
|
|
6394
|
+
function textCommand(kind) {
|
|
5549
6395
|
if (kind === "section") {
|
|
5550
6396
|
return "\\section";
|
|
5551
6397
|
}
|
|
5552
6398
|
if (kind === "subsection") {
|
|
5553
6399
|
return "\\subsection";
|
|
5554
6400
|
}
|
|
5555
|
-
|
|
5556
|
-
return "\\subsubsection";
|
|
5557
|
-
}
|
|
5558
|
-
return "\\paragraph";
|
|
5559
|
-
}
|
|
5560
|
-
function insertionIndex(document2, anchor) {
|
|
5561
|
-
if ("end" in anchor) {
|
|
5562
|
-
return document2.blocks.length;
|
|
5563
|
-
}
|
|
5564
|
-
const index = document2.blocks.findIndex((block) => block.id === anchor.after_block_id);
|
|
5565
|
-
if (index < 0) {
|
|
5566
|
-
throw new Document2CommandError("anchor_not_found", `Anchor block was not found: ${anchor.after_block_id}`);
|
|
5567
|
-
}
|
|
5568
|
-
return index + 1;
|
|
5569
|
-
}
|
|
5570
|
-
function afterBlockId(document2, index) {
|
|
5571
|
-
return index > 0 ? document2.blocks[index - 1]?.id ?? null : null;
|
|
6401
|
+
return kind === "subsubsection" ? "\\subsubsection" : "\\paragraph";
|
|
5572
6402
|
}
|
|
5573
|
-
function
|
|
5574
|
-
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
throw new Document2CommandError("block_kind_mismatch", "Inserted block is not a text block");
|
|
5586
|
-
}
|
|
5587
|
-
block.field = createInlineField2(command.text);
|
|
5588
|
-
return next;
|
|
5589
|
-
}
|
|
5590
|
-
function replaceTextBlock(document2, command) {
|
|
5591
|
-
const index = document2.blocks.findIndex((block2) => block2.id === command.block_id);
|
|
5592
|
-
if (index < 0) {
|
|
5593
|
-
throw new Document2CommandError("block_not_found", `Document block was not found: ${command.block_id}`);
|
|
5594
|
-
}
|
|
5595
|
-
const block = document2.blocks[index];
|
|
5596
|
-
if (!block || block.kind !== "textBlock") {
|
|
5597
|
-
throw new Document2CommandError("block_kind_mismatch", `Document block is not a text block: ${command.block_id}`);
|
|
5598
|
-
}
|
|
5599
|
-
if (block.field.tokens.some((token) => token.kind !== "text" || token.style !== void 0)) {
|
|
5600
|
-
throw new Document2CommandError(
|
|
5601
|
-
"unsupported_inline_content",
|
|
5602
|
-
"Whole-block replacement is not supported for formatted or structured inline content"
|
|
5603
|
-
);
|
|
5604
|
-
}
|
|
5605
|
-
const next = parseDocument(toDocumentJson2(document2));
|
|
5606
|
-
const nextBlock = next.blocks[index];
|
|
5607
|
-
if (!nextBlock || nextBlock.kind !== "textBlock") {
|
|
5608
|
-
throw new Document2CommandError("block_kind_mismatch", `Document block is not a text block: ${command.block_id}`);
|
|
5609
|
-
}
|
|
5610
|
-
nextBlock.field = createInlineField2(command.text);
|
|
5611
|
-
return next;
|
|
5612
|
-
}
|
|
5613
|
-
function removeBlock(document2, command) {
|
|
5614
|
-
if (!document2.blocks.some((block) => block.id === command.block_id)) {
|
|
5615
|
-
throw new Document2CommandError("block_not_found", `Document block was not found: ${command.block_id}`);
|
|
5616
|
-
}
|
|
5617
|
-
return removeDocument2BlockById(document2, command.block_id);
|
|
5618
|
-
}
|
|
5619
|
-
function insertFigure(document2, command) {
|
|
5620
|
-
const index = insertionIndex(document2, command.anchor);
|
|
5621
|
-
const next = addDocument2ImageBlock(
|
|
5622
|
-
document2,
|
|
5623
|
-
{ assetId: command.asset_id, ...command.value !== void 0 ? { value: command.value } : {} },
|
|
5624
|
-
afterBlockId(document2, index)
|
|
5625
|
-
);
|
|
5626
|
-
const block = insertedBlock(next, index);
|
|
5627
|
-
if (block.kind !== "image") {
|
|
5628
|
-
throw new Document2CommandError("block_kind_mismatch", "Inserted block is not a figure");
|
|
6403
|
+
function applyBasicCommand(document2, command) {
|
|
6404
|
+
if (command.op === "insert_text_block") {
|
|
6405
|
+
const block2 = {
|
|
6406
|
+
id: newBlockId(document2),
|
|
6407
|
+
kind: "textBlock",
|
|
6408
|
+
command: textCommand(command.kind),
|
|
6409
|
+
field: createCommandInlineField(document2, command.text),
|
|
6410
|
+
...command.kind === "paragraph" ? { centered: false } : {},
|
|
6411
|
+
...command.metadata ? { metadata: { ...command.metadata } } : {}
|
|
6412
|
+
};
|
|
6413
|
+
document2.blocks.splice(blockInsertionIndex(document2, command.anchor), 0, block2);
|
|
6414
|
+
return;
|
|
5629
6415
|
}
|
|
5630
|
-
if (command.
|
|
5631
|
-
|
|
5632
|
-
|
|
6416
|
+
if (command.op === "replace_text_block") {
|
|
6417
|
+
const block2 = document2.blocks.find((entry) => entry.id === command.block_id);
|
|
6418
|
+
if (!block2) {
|
|
6419
|
+
throw new Document2CommandError("block_not_found", "Document block was not found");
|
|
6420
|
+
}
|
|
6421
|
+
if (block2.kind !== "textBlock") {
|
|
6422
|
+
throw new Document2CommandError("block_kind_mismatch", "Document block is not a text block");
|
|
6423
|
+
}
|
|
6424
|
+
replacePlainField(document2, block2.field, command.text);
|
|
6425
|
+
return;
|
|
5633
6426
|
}
|
|
5634
|
-
if (command.
|
|
5635
|
-
|
|
5636
|
-
|
|
6427
|
+
if (command.op === "remove_block") {
|
|
6428
|
+
const index = document2.blocks.findIndex((block2) => block2.id === command.block_id);
|
|
6429
|
+
if (index < 0) {
|
|
6430
|
+
throw new Document2CommandError("block_not_found", "Document block was not found");
|
|
6431
|
+
}
|
|
6432
|
+
document2.blocks.splice(index, 1);
|
|
6433
|
+
return;
|
|
5637
6434
|
}
|
|
5638
|
-
|
|
6435
|
+
const block = {
|
|
6436
|
+
id: newBlockId(document2),
|
|
6437
|
+
kind: "image",
|
|
6438
|
+
command: "\\includegraphics",
|
|
6439
|
+
value: command.value ?? command.asset_id,
|
|
6440
|
+
assetId: command.asset_id,
|
|
6441
|
+
options: { width: "0.8\\columnwidth" },
|
|
6442
|
+
...defaultFloatMeta(),
|
|
6443
|
+
...command.caption !== void 0 ? { caption: command.caption, captionEnabled: command.caption.trim().length > 0 } : {},
|
|
6444
|
+
...command.label !== void 0 ? { label: command.label, labelEnabled: command.label.trim().length > 0 } : {},
|
|
6445
|
+
...command.metadata ? { metadata: { ...command.metadata } } : {}
|
|
6446
|
+
};
|
|
6447
|
+
document2.blocks.splice(blockInsertionIndex(document2, command.anchor), 0, block);
|
|
5639
6448
|
}
|
|
5640
6449
|
function applyDocument2Command(json, commandInput) {
|
|
5641
6450
|
const document2 = parseDocument(json);
|
|
5642
6451
|
const command = parseCommand2(commandInput);
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
next = removeBlock(document2, command);
|
|
6452
|
+
if (isInlineCommand(command)) {
|
|
6453
|
+
applyInlineCommand(document2, command);
|
|
6454
|
+
} else if (isListCommand(command)) {
|
|
6455
|
+
applyListCommand(document2, command);
|
|
6456
|
+
} else if (isTableCommand(command)) {
|
|
6457
|
+
applyTableCommand(document2, command);
|
|
5650
6458
|
} else {
|
|
5651
|
-
|
|
6459
|
+
applyBasicCommand(document2, command);
|
|
5652
6460
|
}
|
|
5653
|
-
return toDocumentJson2(
|
|
6461
|
+
return toDocumentJson2(document2);
|
|
5654
6462
|
}
|
|
5655
6463
|
|
|
5656
6464
|
// src/document2/outline.ts
|
|
@@ -6350,19 +7158,21 @@ function previewInlines(field, islands, output, equationSide, document2, preview
|
|
|
6350
7158
|
}
|
|
6351
7159
|
function textBlockPreview(block, islands, output, equationSide, document2, previewOptions) {
|
|
6352
7160
|
const inlines = previewInlines(block.field, islands, output, equationSide, document2, previewOptions);
|
|
7161
|
+
const metadata = block.metadata ? { metadata: { ...block.metadata } } : {};
|
|
6353
7162
|
if (block.command === "\\section") {
|
|
6354
|
-
return { kind: "heading", id: block.id, level: 1, inlines };
|
|
7163
|
+
return { kind: "heading", id: block.id, level: 1, inlines, ...metadata };
|
|
6355
7164
|
}
|
|
6356
7165
|
if (block.command === "\\subsection") {
|
|
6357
|
-
return { kind: "heading", id: block.id, level: 2, inlines };
|
|
7166
|
+
return { kind: "heading", id: block.id, level: 2, inlines, ...metadata };
|
|
6358
7167
|
}
|
|
6359
7168
|
if (block.command === "\\subsubsection") {
|
|
6360
|
-
return { kind: "heading", id: block.id, level: 3, inlines };
|
|
7169
|
+
return { kind: "heading", id: block.id, level: 3, inlines, ...metadata };
|
|
6361
7170
|
}
|
|
6362
7171
|
return {
|
|
6363
7172
|
kind: "paragraph",
|
|
6364
7173
|
id: block.id,
|
|
6365
7174
|
inlines,
|
|
7175
|
+
...metadata,
|
|
6366
7176
|
...block.centered ? { centered: true } : {}
|
|
6367
7177
|
};
|
|
6368
7178
|
}
|
|
@@ -6393,7 +7203,8 @@ function blockPreview(block, islands, output, equationSide, document2, previewOp
|
|
|
6393
7203
|
id: item.id,
|
|
6394
7204
|
inlines: previewInlines(item.field, islands, output, equationSide, document2, previewOptions),
|
|
6395
7205
|
blocks: item.blocks.map((child) => blockPreview(child, islands, output, equationSide, document2, previewOptions))
|
|
6396
|
-
}))
|
|
7206
|
+
})),
|
|
7207
|
+
...block.metadata ? { metadata: { ...block.metadata } } : {}
|
|
6397
7208
|
};
|
|
6398
7209
|
}
|
|
6399
7210
|
if (block.kind === "table") {
|
|
@@ -6403,7 +7214,8 @@ function blockPreview(block, islands, output, equationSide, document2, previewOp
|
|
|
6403
7214
|
id: block.id,
|
|
6404
7215
|
rows: block.rows.map((row) => row.map((cell) => previewInlines(cell, islands, output, equationSide, document2, previewOptions))),
|
|
6405
7216
|
...block.captionEnabled && block.caption.trim().length > 0 ? { caption: block.caption.trim() } : {},
|
|
6406
|
-
...label.length > 0 ? { label, numberLabel: floatNumberLabel(document2, label, previewOptions) } : {}
|
|
7217
|
+
...label.length > 0 ? { label, numberLabel: floatNumberLabel(document2, label, previewOptions) } : {},
|
|
7218
|
+
...block.metadata ? { metadata: { ...block.metadata } } : {}
|
|
6407
7219
|
};
|
|
6408
7220
|
}
|
|
6409
7221
|
if (block.kind === "image") {
|
|
@@ -6415,7 +7227,8 @@ function blockPreview(block, islands, output, equationSide, document2, previewOp
|
|
|
6415
7227
|
...block.assetId !== void 0 ? { assetId: block.assetId } : {},
|
|
6416
7228
|
options: block.options,
|
|
6417
7229
|
...block.captionEnabled && block.caption.trim().length > 0 ? { caption: block.caption.trim() } : {},
|
|
6418
|
-
...label.length > 0 ? { label, numberLabel: floatNumberLabel(document2, label, previewOptions) } : {}
|
|
7230
|
+
...label.length > 0 ? { label, numberLabel: floatNumberLabel(document2, label, previewOptions) } : {},
|
|
7231
|
+
...block.metadata ? { metadata: { ...block.metadata } } : {}
|
|
6419
7232
|
};
|
|
6420
7233
|
}
|
|
6421
7234
|
if (block.kind === "bibliography") {
|
|
@@ -6435,10 +7248,11 @@ function blockPreview(block, islands, output, equationSide, document2, previewOp
|
|
|
6435
7248
|
url: reference.url,
|
|
6436
7249
|
venue: reference.venue,
|
|
6437
7250
|
fieldSeparator: reference.fieldSeparator
|
|
6438
|
-
}))
|
|
7251
|
+
})),
|
|
7252
|
+
...block.metadata ? { metadata: { ...block.metadata } } : {}
|
|
6439
7253
|
};
|
|
6440
7254
|
}
|
|
6441
|
-
return { kind: "omit", id: block.id };
|
|
7255
|
+
return { kind: "omit", id: block.id, ...block.metadata ? { metadata: { ...block.metadata } } : {} };
|
|
6442
7256
|
}
|
|
6443
7257
|
function articleChromePreview(document2, uiLocale, previewOptions) {
|
|
6444
7258
|
const meta = document2.meta ?? emptyDocument2Meta();
|