@drghaliasri/butex 6.0.1 → 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.js
CHANGED
|
@@ -1135,6 +1135,76 @@ function applyFloatMetaPatch(block, patch) {
|
|
|
1135
1135
|
}
|
|
1136
1136
|
}
|
|
1137
1137
|
|
|
1138
|
+
// src/document2/inlineIdentity.ts
|
|
1139
|
+
function createDocument2IdentityState() {
|
|
1140
|
+
return {
|
|
1141
|
+
blockIds: /* @__PURE__ */ new Set(),
|
|
1142
|
+
itemIds: /* @__PURE__ */ new Set(),
|
|
1143
|
+
fieldIds: /* @__PURE__ */ new Set(),
|
|
1144
|
+
tokenIds: /* @__PURE__ */ new Set()
|
|
1145
|
+
};
|
|
1146
|
+
}
|
|
1147
|
+
function importedOrGeneratedId(value, prefix, used) {
|
|
1148
|
+
const imported = typeof value === "string" ? value.trim() : "";
|
|
1149
|
+
if (imported.length > 0 && !used.has(imported)) {
|
|
1150
|
+
used.add(imported);
|
|
1151
|
+
return imported;
|
|
1152
|
+
}
|
|
1153
|
+
let generated = document2Id(prefix);
|
|
1154
|
+
while (used.has(generated)) {
|
|
1155
|
+
generated = document2Id(prefix);
|
|
1156
|
+
}
|
|
1157
|
+
used.add(generated);
|
|
1158
|
+
return generated;
|
|
1159
|
+
}
|
|
1160
|
+
function inlineTokenSource(token) {
|
|
1161
|
+
if (token.kind === "text") {
|
|
1162
|
+
return token.text;
|
|
1163
|
+
}
|
|
1164
|
+
if (token.kind === "math") {
|
|
1165
|
+
return token.source;
|
|
1166
|
+
}
|
|
1167
|
+
if (token.kind === "cite") {
|
|
1168
|
+
return citeTokenLatex(token.keys);
|
|
1169
|
+
}
|
|
1170
|
+
return refTokenLatex(token.keys, token.refCommand);
|
|
1171
|
+
}
|
|
1172
|
+
function inlineIdsFromField(field) {
|
|
1173
|
+
let offset = 0;
|
|
1174
|
+
const tokens = field.tokens.map((token) => {
|
|
1175
|
+
const start = offset;
|
|
1176
|
+
offset += inlineTokenSource(token).length;
|
|
1177
|
+
return { id: token.id, kind: token.kind, start, end: offset };
|
|
1178
|
+
});
|
|
1179
|
+
return { field_id: field.id, tokens };
|
|
1180
|
+
}
|
|
1181
|
+
function isAlignedSidecar(value, field) {
|
|
1182
|
+
if (typeof value !== "object" || value === null || !Array.isArray(value.tokens)) {
|
|
1183
|
+
return false;
|
|
1184
|
+
}
|
|
1185
|
+
const tokens = value.tokens;
|
|
1186
|
+
const expected = inlineIdsFromField(field).tokens;
|
|
1187
|
+
if (tokens.length !== expected.length) {
|
|
1188
|
+
return false;
|
|
1189
|
+
}
|
|
1190
|
+
return tokens.every((token, index) => {
|
|
1191
|
+
const expectedToken = expected[index];
|
|
1192
|
+
return typeof token === "object" && token !== null && expectedToken !== void 0 && token.kind === expectedToken.kind && token.start === expectedToken.start && token.end === expectedToken.end;
|
|
1193
|
+
});
|
|
1194
|
+
}
|
|
1195
|
+
function applyImportedInlineIds(field, sidecar, state) {
|
|
1196
|
+
field.id = importedOrGeneratedId(
|
|
1197
|
+
typeof sidecar === "object" && sidecar !== null ? sidecar.field_id : void 0,
|
|
1198
|
+
"field",
|
|
1199
|
+
state.fieldIds
|
|
1200
|
+
);
|
|
1201
|
+
const aligned = isAlignedSidecar(sidecar, field);
|
|
1202
|
+
field.tokens.forEach((token, index) => {
|
|
1203
|
+
token.id = importedOrGeneratedId(aligned ? sidecar.tokens[index]?.id : void 0, token.kind, state.tokenIds);
|
|
1204
|
+
});
|
|
1205
|
+
return field;
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1138
1208
|
// src/document2/inlineScanner.ts
|
|
1139
1209
|
var MATH_ENVIRONMENTS = /* @__PURE__ */ new Set([
|
|
1140
1210
|
"equation",
|
|
@@ -1213,17 +1283,13 @@ function citeSpan(value, start) {
|
|
|
1213
1283
|
function refSpan(value, start) {
|
|
1214
1284
|
const eqrefPrefix = "\\eqref{";
|
|
1215
1285
|
const refPrefix = "\\ref{";
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
if (
|
|
1219
|
-
refCommand = "eqref";
|
|
1220
|
-
prefix = eqrefPrefix;
|
|
1221
|
-
} else if (value.startsWith(refPrefix, start) && !isEscaped(value, start)) {
|
|
1222
|
-
refCommand = "ref";
|
|
1223
|
-
prefix = refPrefix;
|
|
1224
|
-
} else {
|
|
1286
|
+
const isEqref = value.startsWith(eqrefPrefix, start) && !isEscaped(value, start);
|
|
1287
|
+
const isRef = value.startsWith(refPrefix, start) && !isEscaped(value, start);
|
|
1288
|
+
if (!isEqref && !isRef) {
|
|
1225
1289
|
return null;
|
|
1226
1290
|
}
|
|
1291
|
+
const refCommand = isEqref ? "eqref" : "ref";
|
|
1292
|
+
const prefix = isEqref ? eqrefPrefix : refPrefix;
|
|
1227
1293
|
const openBrace = start + prefix.length - 1;
|
|
1228
1294
|
if (value[openBrace] !== "{") {
|
|
1229
1295
|
return null;
|
|
@@ -1282,7 +1348,14 @@ function mathSpanAt(value, i) {
|
|
|
1282
1348
|
return null;
|
|
1283
1349
|
}
|
|
1284
1350
|
function detectMathSpans2(value) {
|
|
1285
|
-
return detectInlineSpans2(value).filter((span) => span.kind === "math").map((
|
|
1351
|
+
return detectInlineSpans2(value).filter((span) => span.kind === "math").map((span) => ({
|
|
1352
|
+
start: span.start,
|
|
1353
|
+
end: span.end,
|
|
1354
|
+
source: span.source,
|
|
1355
|
+
opening: span.opening,
|
|
1356
|
+
closing: span.closing,
|
|
1357
|
+
display: span.display
|
|
1358
|
+
}));
|
|
1286
1359
|
}
|
|
1287
1360
|
function detectInlineSpans2(value) {
|
|
1288
1361
|
const spans = [];
|
|
@@ -1336,17 +1409,13 @@ function asBlockJson(value) {
|
|
|
1336
1409
|
return value;
|
|
1337
1410
|
}
|
|
1338
1411
|
function blockIdFromJson(json, state) {
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
let generated = document2Id("block");
|
|
1345
|
-
while (state.used.has(generated)) {
|
|
1346
|
-
generated = document2Id("block");
|
|
1412
|
+
return importedOrGeneratedId(json.id, "block", state.blockIds);
|
|
1413
|
+
}
|
|
1414
|
+
function metadataFromJson(value) {
|
|
1415
|
+
if (!isObject2(value) || value.source !== "agent" && value.source !== "user") {
|
|
1416
|
+
return {};
|
|
1347
1417
|
}
|
|
1348
|
-
|
|
1349
|
-
return generated;
|
|
1418
|
+
return { metadata: { source: value.source } };
|
|
1350
1419
|
}
|
|
1351
1420
|
function pushDiagnostic(diagnostics, options, path, message) {
|
|
1352
1421
|
if (options.strict) {
|
|
@@ -1529,44 +1598,54 @@ function pushFormattedTextTokens(tokens, text, sourceStart, formats) {
|
|
|
1529
1598
|
function closingForList(command) {
|
|
1530
1599
|
return command === "\\begin{itemize}" ? "\\end{itemize}" : "\\end{enumerate}";
|
|
1531
1600
|
}
|
|
1532
|
-
function parseTextBlock(json, options, path, diagnostics,
|
|
1601
|
+
function parseTextBlock(json, options, path, diagnostics, identities) {
|
|
1533
1602
|
const value = requireString(json.value, `${json.command} requires string value`);
|
|
1534
1603
|
return {
|
|
1535
|
-
id: blockIdFromJson(json,
|
|
1604
|
+
id: blockIdFromJson(json, identities),
|
|
1536
1605
|
kind: "textBlock",
|
|
1537
1606
|
command: json.command,
|
|
1538
|
-
field:
|
|
1607
|
+
field: applyImportedInlineIds(
|
|
1608
|
+
createInlineField2(value, json.math_objects ?? [], options, `${path}.value`, diagnostics, json.command === "\\paragraph" ? json.formats ?? [] : []),
|
|
1609
|
+
json.inline_ids,
|
|
1610
|
+
identities
|
|
1611
|
+
),
|
|
1612
|
+
...metadataFromJson(json.metadata),
|
|
1539
1613
|
...json.centered === true ? { centered: true } : {}
|
|
1540
1614
|
};
|
|
1541
1615
|
}
|
|
1542
|
-
function parseListItem(json, options, path, diagnostics,
|
|
1616
|
+
function parseListItem(json, options, path, diagnostics, identities) {
|
|
1543
1617
|
const value = requireString(json.value, "Document list item requires string value");
|
|
1544
1618
|
const blocksJson = Array.isArray(json.blocks) ? json.blocks : [];
|
|
1545
1619
|
return {
|
|
1546
|
-
id:
|
|
1547
|
-
field:
|
|
1620
|
+
id: importedOrGeneratedId(json.id, "item", identities.itemIds),
|
|
1621
|
+
field: applyImportedInlineIds(
|
|
1622
|
+
createInlineField2(value, json.math_objects ?? [], options, `${path}.value`, diagnostics, json.formats ?? []),
|
|
1623
|
+
json.inline_ids,
|
|
1624
|
+
identities
|
|
1625
|
+
),
|
|
1548
1626
|
blocks: blocksJson.map(
|
|
1549
|
-
(block, index) => parseBlock(asBlockJson(block), options, `${path}.blocks[${String(index)}]`, diagnostics,
|
|
1627
|
+
(block, index) => parseBlock(asBlockJson(block), options, `${path}.blocks[${String(index)}]`, diagnostics, identities)
|
|
1550
1628
|
)
|
|
1551
1629
|
};
|
|
1552
1630
|
}
|
|
1553
|
-
function parseListBlock(json, options, path, diagnostics,
|
|
1631
|
+
function parseListBlock(json, options, path, diagnostics, identities) {
|
|
1554
1632
|
if (!Array.isArray(json.items)) {
|
|
1555
1633
|
throw new Error(`${json.command} requires items array`);
|
|
1556
1634
|
}
|
|
1557
1635
|
const command = json.command;
|
|
1558
1636
|
const closing = closingForList(command);
|
|
1559
1637
|
return {
|
|
1560
|
-
id: blockIdFromJson(json,
|
|
1638
|
+
id: blockIdFromJson(json, identities),
|
|
1561
1639
|
kind: "list",
|
|
1562
1640
|
command,
|
|
1563
1641
|
closing,
|
|
1564
1642
|
items: json.items.map(
|
|
1565
|
-
(item, index) => parseListItem(item, options, `${path}.items[${String(index)}]`, diagnostics,
|
|
1566
|
-
)
|
|
1643
|
+
(item, index) => parseListItem(item, options, `${path}.items[${String(index)}]`, diagnostics, identities)
|
|
1644
|
+
),
|
|
1645
|
+
...metadataFromJson(json.metadata)
|
|
1567
1646
|
};
|
|
1568
1647
|
}
|
|
1569
|
-
function parseTableBlock(json, options, path, diagnostics,
|
|
1648
|
+
function parseTableBlock(json, options, path, diagnostics, identities) {
|
|
1570
1649
|
if (!Array.isArray(json.rows)) {
|
|
1571
1650
|
throw new Error("\\begin{tabular} requires rows array");
|
|
1572
1651
|
}
|
|
@@ -1582,75 +1661,84 @@ function parseTableBlock(json, options, path, diagnostics, blockIds) {
|
|
|
1582
1661
|
const cellMathObjects = mathObjects.slice(mathObjectIndex, mathObjectIndex + spanCount);
|
|
1583
1662
|
mathObjectIndex += spanCount;
|
|
1584
1663
|
const cellFormats = json.cell_formats?.[rowIndex]?.[columnIndex] ?? [];
|
|
1585
|
-
return
|
|
1664
|
+
return applyImportedInlineIds(
|
|
1665
|
+
createInlineField2(value, cellMathObjects, options, `${path}.rows[${String(rowIndex)}][${String(columnIndex)}]`, diagnostics, cellFormats),
|
|
1666
|
+
json.cell_inline_ids?.[rowIndex]?.[columnIndex],
|
|
1667
|
+
identities
|
|
1668
|
+
);
|
|
1586
1669
|
});
|
|
1587
1670
|
});
|
|
1588
1671
|
if (mathObjects.length > 0 && mathObjects.length !== mathObjectIndex) {
|
|
1589
1672
|
pushDiagnostic(diagnostics, options, path, `math_objects count mismatch: detected ${String(mathObjectIndex)}, got ${String(mathObjects.length)}`);
|
|
1590
1673
|
}
|
|
1591
1674
|
return {
|
|
1592
|
-
id: blockIdFromJson(json,
|
|
1675
|
+
id: blockIdFromJson(json, identities),
|
|
1593
1676
|
kind: "table",
|
|
1594
1677
|
command: "\\begin{tabular}",
|
|
1595
1678
|
closing: "\\end{tabular}",
|
|
1596
1679
|
columns: typeof json.columns === "string" ? json.columns : "",
|
|
1597
1680
|
rows,
|
|
1598
|
-
...parseFloatMetaFromJson(json)
|
|
1681
|
+
...parseFloatMetaFromJson(json),
|
|
1682
|
+
...metadataFromJson(json.metadata)
|
|
1599
1683
|
};
|
|
1600
1684
|
}
|
|
1601
|
-
function parseImageBlock(json,
|
|
1685
|
+
function parseImageBlock(json, identities) {
|
|
1602
1686
|
const assetId = typeof json.asset_id === "string" && json.asset_id.length > 0 ? json.asset_id : void 0;
|
|
1603
1687
|
const value = assetId !== void 0 ? typeof json.value === "string" ? json.value : "" : requireString(json.value, "\\includegraphics requires string value");
|
|
1604
1688
|
return {
|
|
1605
|
-
id: blockIdFromJson(json,
|
|
1689
|
+
id: blockIdFromJson(json, identities),
|
|
1606
1690
|
kind: "image",
|
|
1607
1691
|
command: "\\includegraphics",
|
|
1608
1692
|
value,
|
|
1609
1693
|
...assetId !== void 0 ? { assetId } : {},
|
|
1610
1694
|
options: isRecordOfStrings(json.options) ? json.options : {},
|
|
1611
|
-
...parseFloatMetaFromJson(json)
|
|
1695
|
+
...parseFloatMetaFromJson(json),
|
|
1696
|
+
...metadataFromJson(json.metadata)
|
|
1612
1697
|
};
|
|
1613
1698
|
}
|
|
1614
|
-
function parseRawBlock(json,
|
|
1699
|
+
function parseRawBlock(json, identities) {
|
|
1615
1700
|
return {
|
|
1616
|
-
id: blockIdFromJson(json,
|
|
1701
|
+
id: blockIdFromJson(json, identities),
|
|
1617
1702
|
kind: "raw",
|
|
1618
1703
|
command: "\\raw",
|
|
1619
|
-
value: typeof json.value === "string" ? json.value : ""
|
|
1704
|
+
value: typeof json.value === "string" ? json.value : "",
|
|
1705
|
+
...metadataFromJson(json.metadata)
|
|
1620
1706
|
};
|
|
1621
1707
|
}
|
|
1622
|
-
function parseBibliographyBlock(json,
|
|
1708
|
+
function parseBibliographyBlock(json, identities) {
|
|
1623
1709
|
return {
|
|
1624
|
-
id: blockIdFromJson(json,
|
|
1710
|
+
id: blockIdFromJson(json, identities),
|
|
1625
1711
|
kind: "bibliography",
|
|
1626
1712
|
command: "\\begin{thebibliography}",
|
|
1627
|
-
closing: "\\end{thebibliography}"
|
|
1713
|
+
closing: "\\end{thebibliography}",
|
|
1714
|
+
...metadataFromJson(json.metadata)
|
|
1628
1715
|
};
|
|
1629
1716
|
}
|
|
1630
|
-
function parseBlock(json, options, path, diagnostics,
|
|
1717
|
+
function parseBlock(json, options, path, diagnostics, identities) {
|
|
1631
1718
|
if (TEXT_COMMANDS.has(json.command)) {
|
|
1632
|
-
return parseTextBlock(json, options, path, diagnostics,
|
|
1719
|
+
return parseTextBlock(json, options, path, diagnostics, identities);
|
|
1633
1720
|
}
|
|
1634
1721
|
if (LIST_COMMANDS.has(json.command)) {
|
|
1635
|
-
return parseListBlock(json, options, path, diagnostics,
|
|
1722
|
+
return parseListBlock(json, options, path, diagnostics, identities);
|
|
1636
1723
|
}
|
|
1637
1724
|
if (json.command === "\\begin{tabular}") {
|
|
1638
|
-
return parseTableBlock(json, options, path, diagnostics,
|
|
1725
|
+
return parseTableBlock(json, options, path, diagnostics, identities);
|
|
1639
1726
|
}
|
|
1640
1727
|
if (json.command === "\\includegraphics") {
|
|
1641
|
-
return parseImageBlock(json,
|
|
1728
|
+
return parseImageBlock(json, identities);
|
|
1642
1729
|
}
|
|
1643
1730
|
if (json.command === "\\begin{thebibliography}" || json.command === "\\bibliography") {
|
|
1644
|
-
return parseBibliographyBlock(json,
|
|
1731
|
+
return parseBibliographyBlock(json, identities);
|
|
1645
1732
|
}
|
|
1646
1733
|
if (json.command === "\\raw") {
|
|
1647
|
-
return parseRawBlock(json,
|
|
1734
|
+
return parseRawBlock(json, identities);
|
|
1648
1735
|
}
|
|
1649
1736
|
return {
|
|
1650
|
-
id: blockIdFromJson(json,
|
|
1737
|
+
id: blockIdFromJson(json, identities),
|
|
1651
1738
|
kind: "raw",
|
|
1652
1739
|
command: "\\raw",
|
|
1653
|
-
value: typeof json.value === "string" ? json.value : json.command
|
|
1740
|
+
value: typeof json.value === "string" ? json.value : json.command,
|
|
1741
|
+
...metadataFromJson(json.metadata)
|
|
1654
1742
|
};
|
|
1655
1743
|
}
|
|
1656
1744
|
function fromDocumentJson2(json, options = {}) {
|
|
@@ -1661,13 +1749,13 @@ function fromDocumentJson2(json, options = {}) {
|
|
|
1661
1749
|
throw new Error("DocumentObject requires blocks array");
|
|
1662
1750
|
}
|
|
1663
1751
|
const diagnostics = [];
|
|
1664
|
-
const
|
|
1752
|
+
const identities = createDocument2IdentityState();
|
|
1665
1753
|
return {
|
|
1666
1754
|
nodeType: "DocumentObject",
|
|
1667
1755
|
meta: normalizeDocument2Meta(json.meta),
|
|
1668
1756
|
references: parseReferences(json.references),
|
|
1669
1757
|
blocks: json.blocks.map(
|
|
1670
|
-
(block, index) => parseBlock(asBlockJson(block), options, `$.blocks[${String(index)}]`, diagnostics,
|
|
1758
|
+
(block, index) => parseBlock(asBlockJson(block), options, `$.blocks[${String(index)}]`, diagnostics, identities)
|
|
1671
1759
|
),
|
|
1672
1760
|
diagnostics
|
|
1673
1761
|
};
|
|
@@ -2885,9 +2973,9 @@ function createAccentNode(accentId) {
|
|
|
2885
2973
|
baseExpr: createEditorChain()
|
|
2886
2974
|
};
|
|
2887
2975
|
}
|
|
2888
|
-
function createGridEnvNode(envName, rows,
|
|
2976
|
+
function createGridEnvNode(envName, rows, columns2, columnAlignments) {
|
|
2889
2977
|
const safeRows = Math.max(1, Math.min(12, Math.trunc(rows)));
|
|
2890
|
-
const safeColumns = Math.max(1, Math.min(12, Math.trunc(
|
|
2978
|
+
const safeColumns = Math.max(1, Math.min(12, Math.trunc(columns2)));
|
|
2891
2979
|
const matrixStyles = /* @__PURE__ */ new Set(["matrix", "pmatrix", "bmatrix", "Bmatrix", "vmatrix", "Vmatrix"]);
|
|
2892
2980
|
const isMatrix = matrixStyles.has(envName) && envName !== "array" && envName !== "aligned";
|
|
2893
2981
|
return {
|
|
@@ -4156,11 +4244,11 @@ function envToEditorNode(node) {
|
|
|
4156
4244
|
}
|
|
4157
4245
|
const rowCells = node.lines.map(splitEnvLine);
|
|
4158
4246
|
const rows = Math.max(1, rowCells.length);
|
|
4159
|
-
const
|
|
4160
|
-
const env = createGridEnvNode(parsed.envName, rows,
|
|
4247
|
+
const columns2 = Math.max(1, ...rowCells.map((row) => row.length));
|
|
4248
|
+
const env = createGridEnvNode(parsed.envName, rows, columns2, parsed.alignments);
|
|
4161
4249
|
for (let rowIndex = 0; rowIndex < rows; rowIndex += 1) {
|
|
4162
4250
|
const row = rowCells[rowIndex] ?? [];
|
|
4163
|
-
for (let columnIndex = 0; columnIndex <
|
|
4251
|
+
for (let columnIndex = 0; columnIndex < columns2; columnIndex += 1) {
|
|
4164
4252
|
const cell = chainToEditorChain(row[columnIndex] ?? new ChainNode());
|
|
4165
4253
|
if (!cell.editable) {
|
|
4166
4254
|
return cell;
|
|
@@ -4170,7 +4258,7 @@ function envToEditorNode(node) {
|
|
|
4170
4258
|
}
|
|
4171
4259
|
if (parsed.envName === "array") {
|
|
4172
4260
|
env.columnAlignments = Array.from(
|
|
4173
|
-
{ length:
|
|
4261
|
+
{ length: columns2 },
|
|
4174
4262
|
(_, index) => parsed.alignments?.[index] ?? "c"
|
|
4175
4263
|
);
|
|
4176
4264
|
}
|
|
@@ -4648,12 +4736,14 @@ function cloneField(field) {
|
|
|
4648
4736
|
return { id: field.id, tokens: field.tokens.map(cloneToken) };
|
|
4649
4737
|
}
|
|
4650
4738
|
function cloneBlock(block) {
|
|
4739
|
+
const metadata = block.metadata ? { metadata: { ...block.metadata } } : {};
|
|
4651
4740
|
if (block.kind === "textBlock") {
|
|
4652
|
-
return { ...block, field: cloneField(block.field) };
|
|
4741
|
+
return { ...block, ...metadata, field: cloneField(block.field) };
|
|
4653
4742
|
}
|
|
4654
4743
|
if (block.kind === "list") {
|
|
4655
4744
|
return {
|
|
4656
4745
|
...block,
|
|
4746
|
+
...metadata,
|
|
4657
4747
|
items: block.items.map((item) => ({
|
|
4658
4748
|
...item,
|
|
4659
4749
|
field: cloneField(item.field),
|
|
@@ -4662,12 +4752,12 @@ function cloneBlock(block) {
|
|
|
4662
4752
|
};
|
|
4663
4753
|
}
|
|
4664
4754
|
if (block.kind === "table") {
|
|
4665
|
-
return { ...block, rows: block.rows.map((row) => row.map(cloneField)) };
|
|
4755
|
+
return { ...block, ...metadata, rows: block.rows.map((row) => row.map(cloneField)) };
|
|
4666
4756
|
}
|
|
4667
4757
|
if (block.kind === "image") {
|
|
4668
|
-
return { ...block, options: { ...block.options } };
|
|
4758
|
+
return { ...block, ...metadata, options: { ...block.options } };
|
|
4669
4759
|
}
|
|
4670
|
-
return { ...block };
|
|
4760
|
+
return { ...block, ...metadata };
|
|
4671
4761
|
}
|
|
4672
4762
|
function cloneDocument(document2) {
|
|
4673
4763
|
return {
|
|
@@ -4752,21 +4842,21 @@ function splitTextForInsertion(token) {
|
|
|
4752
4842
|
function cloneDocument2Node(document2) {
|
|
4753
4843
|
return cloneDocument(document2);
|
|
4754
4844
|
}
|
|
4755
|
-
function insertBlockAfter(blocks,
|
|
4756
|
-
if (!
|
|
4845
|
+
function insertBlockAfter(blocks, afterBlockId, block) {
|
|
4846
|
+
if (!afterBlockId) {
|
|
4757
4847
|
blocks.push(block);
|
|
4758
4848
|
return;
|
|
4759
4849
|
}
|
|
4760
|
-
const index = blocks.findIndex((entry) => entry.id ===
|
|
4850
|
+
const index = blocks.findIndex((entry) => entry.id === afterBlockId);
|
|
4761
4851
|
if (index < 0) {
|
|
4762
4852
|
blocks.push(block);
|
|
4763
4853
|
return;
|
|
4764
4854
|
}
|
|
4765
4855
|
blocks.splice(index + 1, 0, block);
|
|
4766
4856
|
}
|
|
4767
|
-
function insertDocument2BlockAfter(document2,
|
|
4857
|
+
function insertDocument2BlockAfter(document2, afterBlockId, block) {
|
|
4768
4858
|
const next = cloneDocument(document2);
|
|
4769
|
-
insertBlockAfter(next.blocks,
|
|
4859
|
+
insertBlockAfter(next.blocks, afterBlockId, block);
|
|
4770
4860
|
return next;
|
|
4771
4861
|
}
|
|
4772
4862
|
function moveDocument2BlockById(document2, blockId, direction) {
|
|
@@ -4986,7 +5076,7 @@ function replaceMathTokenFromSession(document2, tokenId, session, opening, closi
|
|
|
4986
5076
|
});
|
|
4987
5077
|
return next;
|
|
4988
5078
|
}
|
|
4989
|
-
function addDocument2TextBlock(document2, command = "\\paragraph",
|
|
5079
|
+
function addDocument2TextBlock(document2, command = "\\paragraph", afterBlockId) {
|
|
4990
5080
|
const block = {
|
|
4991
5081
|
id: document2Id("block"),
|
|
4992
5082
|
kind: "textBlock",
|
|
@@ -4994,7 +5084,7 @@ function addDocument2TextBlock(document2, command = "\\paragraph", afterBlockId2
|
|
|
4994
5084
|
field: createInlineField2(""),
|
|
4995
5085
|
...command === "\\paragraph" ? { centered: false } : {}
|
|
4996
5086
|
};
|
|
4997
|
-
return insertDocument2BlockAfter(document2,
|
|
5087
|
+
return insertDocument2BlockAfter(document2, afterBlockId, block);
|
|
4998
5088
|
}
|
|
4999
5089
|
function updateDocument2TextBlockCentered(document2, blockId, centered) {
|
|
5000
5090
|
const next = cloneDocument(document2);
|
|
@@ -5033,10 +5123,10 @@ function newListBlock(ordered) {
|
|
|
5033
5123
|
items: [{ id: document2Id("item"), field: createInlineField2(""), blocks: [] }]
|
|
5034
5124
|
};
|
|
5035
5125
|
}
|
|
5036
|
-
function addDocument2ListBlock(document2, ordered,
|
|
5037
|
-
return insertDocument2BlockAfter(document2,
|
|
5126
|
+
function addDocument2ListBlock(document2, ordered, afterBlockId) {
|
|
5127
|
+
return insertDocument2BlockAfter(document2, afterBlockId, newListBlock(ordered));
|
|
5038
5128
|
}
|
|
5039
|
-
function addDocument2TableBlock(document2,
|
|
5129
|
+
function addDocument2TableBlock(document2, columns2 = "lll", rowCount = 3, colCount = 3, afterBlockId) {
|
|
5040
5130
|
const rows = Math.max(1, rowCount);
|
|
5041
5131
|
const cols = Math.max(1, colCount);
|
|
5042
5132
|
const tableRows = [];
|
|
@@ -5052,11 +5142,11 @@ function addDocument2TableBlock(document2, columns = "lll", rowCount = 3, colCou
|
|
|
5052
5142
|
kind: "table",
|
|
5053
5143
|
command: "\\begin{tabular}",
|
|
5054
5144
|
closing: "\\end{tabular}",
|
|
5055
|
-
columns:
|
|
5145
|
+
columns: columns2 || "l".repeat(cols),
|
|
5056
5146
|
rows: tableRows,
|
|
5057
5147
|
...defaultFloatMeta()
|
|
5058
5148
|
};
|
|
5059
|
-
return insertDocument2BlockAfter(document2,
|
|
5149
|
+
return insertDocument2BlockAfter(document2, afterBlockId, block);
|
|
5060
5150
|
}
|
|
5061
5151
|
function normalizeImageInput(srcOrAsset) {
|
|
5062
5152
|
if (typeof srcOrAsset === "string") {
|
|
@@ -5067,7 +5157,7 @@ function normalizeImageInput(srcOrAsset) {
|
|
|
5067
5157
|
}
|
|
5068
5158
|
return { value: "" };
|
|
5069
5159
|
}
|
|
5070
|
-
function addDocument2ImageBlock(document2, srcOrAsset,
|
|
5160
|
+
function addDocument2ImageBlock(document2, srcOrAsset, afterBlockId) {
|
|
5071
5161
|
const image = normalizeImageInput(srcOrAsset);
|
|
5072
5162
|
const block = {
|
|
5073
5163
|
id: document2Id("block"),
|
|
@@ -5078,7 +5168,7 @@ function addDocument2ImageBlock(document2, srcOrAsset, afterBlockId2) {
|
|
|
5078
5168
|
options: { width: "0.8\\columnwidth" },
|
|
5079
5169
|
...defaultFloatMeta()
|
|
5080
5170
|
};
|
|
5081
|
-
return insertDocument2BlockAfter(document2,
|
|
5171
|
+
return insertDocument2BlockAfter(document2, afterBlockId, block);
|
|
5082
5172
|
}
|
|
5083
5173
|
function updateDocument2ImageValue(document2, blockId, value) {
|
|
5084
5174
|
const next = cloneDocument(document2);
|
|
@@ -5368,7 +5458,7 @@ function removeCiteTokenById(document2, tokenId) {
|
|
|
5368
5458
|
});
|
|
5369
5459
|
return next;
|
|
5370
5460
|
}
|
|
5371
|
-
function ensureDocument2BibliographyBlock(document2,
|
|
5461
|
+
function ensureDocument2BibliographyBlock(document2, afterBlockId) {
|
|
5372
5462
|
if (document2.blocks.some((block2) => block2.kind === "bibliography")) {
|
|
5373
5463
|
return document2;
|
|
5374
5464
|
}
|
|
@@ -5378,7 +5468,7 @@ function ensureDocument2BibliographyBlock(document2, afterBlockId2) {
|
|
|
5378
5468
|
command: "\\begin{thebibliography}",
|
|
5379
5469
|
closing: "\\end{thebibliography}"
|
|
5380
5470
|
};
|
|
5381
|
-
return insertDocument2BlockAfter(document2,
|
|
5471
|
+
return insertDocument2BlockAfter(document2, afterBlockId ?? null, block);
|
|
5382
5472
|
}
|
|
5383
5473
|
function addDocument2Reference(document2, partial = {}) {
|
|
5384
5474
|
const next = cloneDocument(document2);
|
|
@@ -5450,6 +5540,764 @@ function updateDocument2Meta(document2, patch) {
|
|
|
5450
5540
|
return next;
|
|
5451
5541
|
}
|
|
5452
5542
|
|
|
5543
|
+
// src/document2/jsonCommandTypes.ts
|
|
5544
|
+
var Document2CommandError = class extends Error {
|
|
5545
|
+
code;
|
|
5546
|
+
constructor(code, message) {
|
|
5547
|
+
super(message);
|
|
5548
|
+
this.name = "Document2CommandError";
|
|
5549
|
+
this.code = code;
|
|
5550
|
+
}
|
|
5551
|
+
};
|
|
5552
|
+
|
|
5553
|
+
// src/document2/jsonCommandHelpers.ts
|
|
5554
|
+
function isObject3(value) {
|
|
5555
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5556
|
+
}
|
|
5557
|
+
function requireString2(value, field, allowEmpty = true) {
|
|
5558
|
+
if (typeof value !== "string" || !allowEmpty && value.trim().length === 0) {
|
|
5559
|
+
throw new Document2CommandError("invalid_command", `${field} must be a${allowEmpty ? "" : " non-empty"} string`);
|
|
5560
|
+
}
|
|
5561
|
+
return value;
|
|
5562
|
+
}
|
|
5563
|
+
function optionalString(value, field) {
|
|
5564
|
+
if (!(field in value)) {
|
|
5565
|
+
return void 0;
|
|
5566
|
+
}
|
|
5567
|
+
if (typeof value[field] !== "string") {
|
|
5568
|
+
throw new Document2CommandError("invalid_command", `${field} must be a string when provided`);
|
|
5569
|
+
}
|
|
5570
|
+
return value[field];
|
|
5571
|
+
}
|
|
5572
|
+
function requireBoolean(value, field) {
|
|
5573
|
+
if (typeof value !== "boolean") {
|
|
5574
|
+
throw new Document2CommandError("invalid_command", `${field} must be a boolean`);
|
|
5575
|
+
}
|
|
5576
|
+
return value;
|
|
5577
|
+
}
|
|
5578
|
+
function requireIndex(value, field) {
|
|
5579
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
|
|
5580
|
+
throw new Document2CommandError("invalid_command", `${field} must be a non-negative integer`);
|
|
5581
|
+
}
|
|
5582
|
+
return value;
|
|
5583
|
+
}
|
|
5584
|
+
function parseMetadata(value) {
|
|
5585
|
+
if (value === void 0) {
|
|
5586
|
+
return void 0;
|
|
5587
|
+
}
|
|
5588
|
+
if (!isObject3(value)) {
|
|
5589
|
+
throw new Document2CommandError("invalid_command", "metadata must be an object");
|
|
5590
|
+
}
|
|
5591
|
+
if (value.source === void 0) {
|
|
5592
|
+
return void 0;
|
|
5593
|
+
}
|
|
5594
|
+
if (value.source !== "agent" && value.source !== "user") {
|
|
5595
|
+
throw new Document2CommandError("invalid_command", "metadata.source must be agent or user");
|
|
5596
|
+
}
|
|
5597
|
+
return { source: value.source };
|
|
5598
|
+
}
|
|
5599
|
+
function parseBlockAnchor(value) {
|
|
5600
|
+
if (!isObject3(value)) {
|
|
5601
|
+
throw new Document2CommandError("invalid_anchor", "anchor must be an object");
|
|
5602
|
+
}
|
|
5603
|
+
const before = typeof value.before_block_id === "string" ? value.before_block_id.trim() : "";
|
|
5604
|
+
const after = typeof value.after_block_id === "string" ? value.after_block_id.trim() : "";
|
|
5605
|
+
const choices = Number(before.length > 0) + Number(after.length > 0) + Number(value.end === true);
|
|
5606
|
+
if (choices !== 1) {
|
|
5607
|
+
throw new Document2CommandError("invalid_anchor", "anchor requires exactly one block position");
|
|
5608
|
+
}
|
|
5609
|
+
if (before) {
|
|
5610
|
+
return { before_block_id: before };
|
|
5611
|
+
}
|
|
5612
|
+
if (after) {
|
|
5613
|
+
return { after_block_id: after };
|
|
5614
|
+
}
|
|
5615
|
+
return { end: true };
|
|
5616
|
+
}
|
|
5617
|
+
function parseListItemAnchor(value) {
|
|
5618
|
+
if (!isObject3(value)) {
|
|
5619
|
+
throw new Document2CommandError("invalid_anchor", "anchor must be an object");
|
|
5620
|
+
}
|
|
5621
|
+
const before = typeof value.before_item_id === "string" ? value.before_item_id.trim() : "";
|
|
5622
|
+
const after = typeof value.after_item_id === "string" ? value.after_item_id.trim() : "";
|
|
5623
|
+
const choices = Number(before.length > 0) + Number(after.length > 0) + Number(value.end === true);
|
|
5624
|
+
if (choices !== 1) {
|
|
5625
|
+
throw new Document2CommandError("invalid_anchor", "anchor requires exactly one list-item position");
|
|
5626
|
+
}
|
|
5627
|
+
if (before) {
|
|
5628
|
+
return { before_item_id: before };
|
|
5629
|
+
}
|
|
5630
|
+
if (after) {
|
|
5631
|
+
return { after_item_id: after };
|
|
5632
|
+
}
|
|
5633
|
+
return { end: true };
|
|
5634
|
+
}
|
|
5635
|
+
function blockInsertionIndex(document2, anchor) {
|
|
5636
|
+
if ("end" in anchor) {
|
|
5637
|
+
return document2.blocks.length;
|
|
5638
|
+
}
|
|
5639
|
+
const id = "before_block_id" in anchor ? anchor.before_block_id : anchor.after_block_id;
|
|
5640
|
+
const index = document2.blocks.findIndex((block) => block.id === id);
|
|
5641
|
+
if (index < 0) {
|
|
5642
|
+
throw new Document2CommandError("anchor_not_found", "Anchor block was not found");
|
|
5643
|
+
}
|
|
5644
|
+
return "before_block_id" in anchor ? index : index + 1;
|
|
5645
|
+
}
|
|
5646
|
+
function itemInsertionIndex(list, anchor) {
|
|
5647
|
+
if ("end" in anchor) {
|
|
5648
|
+
return list.items.length;
|
|
5649
|
+
}
|
|
5650
|
+
const id = "before_item_id" in anchor ? anchor.before_item_id : anchor.after_item_id;
|
|
5651
|
+
const index = list.items.findIndex((item) => item.id === id);
|
|
5652
|
+
if (index < 0) {
|
|
5653
|
+
throw new Document2CommandError("anchor_not_found", "Anchor list item was not found");
|
|
5654
|
+
}
|
|
5655
|
+
return "before_item_id" in anchor ? index : index + 1;
|
|
5656
|
+
}
|
|
5657
|
+
function findField(blocks, fieldId) {
|
|
5658
|
+
for (const block of blocks) {
|
|
5659
|
+
if (block.kind === "textBlock" && block.field.id === fieldId) {
|
|
5660
|
+
return block.field;
|
|
5661
|
+
}
|
|
5662
|
+
if (block.kind === "list") {
|
|
5663
|
+
for (const item of block.items) {
|
|
5664
|
+
if (item.field.id === fieldId) {
|
|
5665
|
+
return item.field;
|
|
5666
|
+
}
|
|
5667
|
+
const nested = findField(item.blocks, fieldId);
|
|
5668
|
+
if (nested) {
|
|
5669
|
+
return nested;
|
|
5670
|
+
}
|
|
5671
|
+
}
|
|
5672
|
+
}
|
|
5673
|
+
if (block.kind === "table") {
|
|
5674
|
+
for (const row of block.rows) {
|
|
5675
|
+
const cell = row.find((field) => field.id === fieldId);
|
|
5676
|
+
if (cell) {
|
|
5677
|
+
return cell;
|
|
5678
|
+
}
|
|
5679
|
+
}
|
|
5680
|
+
}
|
|
5681
|
+
}
|
|
5682
|
+
return null;
|
|
5683
|
+
}
|
|
5684
|
+
function findBlock(blocks, blockId) {
|
|
5685
|
+
for (const block of blocks) {
|
|
5686
|
+
if (block.id === blockId) {
|
|
5687
|
+
return block;
|
|
5688
|
+
}
|
|
5689
|
+
if (block.kind === "list") {
|
|
5690
|
+
for (const item of block.items) {
|
|
5691
|
+
const nested = findBlock(item.blocks, blockId);
|
|
5692
|
+
if (nested) {
|
|
5693
|
+
return nested;
|
|
5694
|
+
}
|
|
5695
|
+
}
|
|
5696
|
+
}
|
|
5697
|
+
}
|
|
5698
|
+
return null;
|
|
5699
|
+
}
|
|
5700
|
+
function collectIdentitySets(blocks, sets) {
|
|
5701
|
+
for (const block of blocks) {
|
|
5702
|
+
sets.blocks.add(block.id);
|
|
5703
|
+
if (block.kind === "textBlock") {
|
|
5704
|
+
sets.fields.add(block.field.id);
|
|
5705
|
+
block.field.tokens.forEach((token) => sets.tokens.add(token.id));
|
|
5706
|
+
} else if (block.kind === "list") {
|
|
5707
|
+
for (const item of block.items) {
|
|
5708
|
+
sets.items.add(item.id);
|
|
5709
|
+
sets.fields.add(item.field.id);
|
|
5710
|
+
item.field.tokens.forEach((token) => sets.tokens.add(token.id));
|
|
5711
|
+
collectIdentitySets(item.blocks, sets);
|
|
5712
|
+
}
|
|
5713
|
+
} else if (block.kind === "table") {
|
|
5714
|
+
for (const row of block.rows) {
|
|
5715
|
+
for (const field of row) {
|
|
5716
|
+
sets.fields.add(field.id);
|
|
5717
|
+
field.tokens.forEach((token) => sets.tokens.add(token.id));
|
|
5718
|
+
}
|
|
5719
|
+
}
|
|
5720
|
+
}
|
|
5721
|
+
}
|
|
5722
|
+
}
|
|
5723
|
+
function documentIdentitySets(document2) {
|
|
5724
|
+
const sets = {
|
|
5725
|
+
blocks: /* @__PURE__ */ new Set(),
|
|
5726
|
+
items: /* @__PURE__ */ new Set(),
|
|
5727
|
+
fields: /* @__PURE__ */ new Set(),
|
|
5728
|
+
tokens: /* @__PURE__ */ new Set()
|
|
5729
|
+
};
|
|
5730
|
+
collectIdentitySets(document2.blocks, sets);
|
|
5731
|
+
return sets;
|
|
5732
|
+
}
|
|
5733
|
+
function unusedGeneratedId(prefix, used) {
|
|
5734
|
+
let id = document2Id(prefix);
|
|
5735
|
+
while (used.has(id)) {
|
|
5736
|
+
id = document2Id(prefix);
|
|
5737
|
+
}
|
|
5738
|
+
return id;
|
|
5739
|
+
}
|
|
5740
|
+
function newBlockId(document2) {
|
|
5741
|
+
return unusedGeneratedId("block", documentIdentitySets(document2).blocks);
|
|
5742
|
+
}
|
|
5743
|
+
function newItemId(document2) {
|
|
5744
|
+
return unusedGeneratedId("item", documentIdentitySets(document2).items);
|
|
5745
|
+
}
|
|
5746
|
+
function newTokenId(document2, prefix) {
|
|
5747
|
+
return unusedGeneratedId(prefix, documentIdentitySets(document2).tokens);
|
|
5748
|
+
}
|
|
5749
|
+
function createCommandInlineField(document2, text) {
|
|
5750
|
+
const field = createInlineField2(text);
|
|
5751
|
+
const used = documentIdentitySets(document2);
|
|
5752
|
+
field.id = unusedGeneratedId("field", used.fields);
|
|
5753
|
+
field.tokens.forEach((token) => {
|
|
5754
|
+
token.id = unusedGeneratedId(token.kind, used.tokens);
|
|
5755
|
+
used.tokens.add(token.id);
|
|
5756
|
+
});
|
|
5757
|
+
return field;
|
|
5758
|
+
}
|
|
5759
|
+
function requireList(document2, listId) {
|
|
5760
|
+
const block = findBlock(document2.blocks, listId);
|
|
5761
|
+
if (!block) {
|
|
5762
|
+
throw new Document2CommandError("list_not_found", "Document list was not found");
|
|
5763
|
+
}
|
|
5764
|
+
if (block.kind !== "list") {
|
|
5765
|
+
throw new Document2CommandError("block_kind_mismatch", "Target block is not a list");
|
|
5766
|
+
}
|
|
5767
|
+
return block;
|
|
5768
|
+
}
|
|
5769
|
+
function requireTable(document2, tableId) {
|
|
5770
|
+
const block = findBlock(document2.blocks, tableId);
|
|
5771
|
+
if (!block) {
|
|
5772
|
+
throw new Document2CommandError("table_not_found", "Document table was not found");
|
|
5773
|
+
}
|
|
5774
|
+
if (block.kind !== "table") {
|
|
5775
|
+
throw new Document2CommandError("block_kind_mismatch", "Target block is not a table");
|
|
5776
|
+
}
|
|
5777
|
+
return block;
|
|
5778
|
+
}
|
|
5779
|
+
function fieldHasStructuredContent(field) {
|
|
5780
|
+
return field.tokens.some((token) => token.kind !== "text" || token.style !== void 0);
|
|
5781
|
+
}
|
|
5782
|
+
function replacePlainField(document2, field, text) {
|
|
5783
|
+
if (fieldHasStructuredContent(field)) {
|
|
5784
|
+
throw new Document2CommandError(
|
|
5785
|
+
"unsupported_inline_content",
|
|
5786
|
+
"Whole-field replacement is not supported for formatted or structured inline content"
|
|
5787
|
+
);
|
|
5788
|
+
}
|
|
5789
|
+
const next = createCommandInlineField(document2, text);
|
|
5790
|
+
field.tokens = next.tokens;
|
|
5791
|
+
}
|
|
5792
|
+
function textStylesEqual3(a, b) {
|
|
5793
|
+
return Boolean(a?.bold) === Boolean(b?.bold) && Boolean(a?.italic) === Boolean(b?.italic) && Boolean(a?.underline) === Boolean(b?.underline);
|
|
5794
|
+
}
|
|
5795
|
+
function compactTextTokens2(tokens, emptyTokenId = document2Id("text")) {
|
|
5796
|
+
const compacted = [];
|
|
5797
|
+
for (const token of tokens) {
|
|
5798
|
+
const previous = compacted[compacted.length - 1];
|
|
5799
|
+
if (previous?.kind === "text" && token.kind === "text" && textStylesEqual3(previous.style, token.style)) {
|
|
5800
|
+
previous.text += token.text;
|
|
5801
|
+
} else {
|
|
5802
|
+
compacted.push(token);
|
|
5803
|
+
}
|
|
5804
|
+
}
|
|
5805
|
+
return compacted.length > 0 ? compacted : [{ id: emptyTokenId, kind: "text", text: "" }];
|
|
5806
|
+
}
|
|
5807
|
+
|
|
5808
|
+
// src/document2/inlineJsonCommands.ts
|
|
5809
|
+
function parseInlineAnchor(value) {
|
|
5810
|
+
if (!isObject3(value)) {
|
|
5811
|
+
throw new Document2CommandError("invalid_anchor", "anchor must be an object");
|
|
5812
|
+
}
|
|
5813
|
+
const before = typeof value.before_token_id === "string" ? value.before_token_id.trim() : "";
|
|
5814
|
+
const after = typeof value.after_token_id === "string" ? value.after_token_id.trim() : "";
|
|
5815
|
+
const choices = Number(before.length > 0) + Number(after.length > 0) + Number(value.start === true) + Number(value.end === true);
|
|
5816
|
+
if (choices !== 1) {
|
|
5817
|
+
throw new Document2CommandError("invalid_anchor", "anchor requires exactly one inline-token position");
|
|
5818
|
+
}
|
|
5819
|
+
if (before) {
|
|
5820
|
+
return { before_token_id: before };
|
|
5821
|
+
}
|
|
5822
|
+
if (after) {
|
|
5823
|
+
return { after_token_id: after };
|
|
5824
|
+
}
|
|
5825
|
+
return value.start === true ? { start: true } : { end: true };
|
|
5826
|
+
}
|
|
5827
|
+
function parseStyle(value) {
|
|
5828
|
+
if (value === void 0) {
|
|
5829
|
+
return void 0;
|
|
5830
|
+
}
|
|
5831
|
+
if (!isObject3(value)) {
|
|
5832
|
+
throw new Document2CommandError("invalid_inline_token", "text token style must be an object");
|
|
5833
|
+
}
|
|
5834
|
+
const style = {};
|
|
5835
|
+
for (const key of ["bold", "italic", "underline"]) {
|
|
5836
|
+
if (value[key] !== void 0 && value[key] !== true) {
|
|
5837
|
+
throw new Document2CommandError("invalid_inline_token", `text token style.${key} must be true when provided`);
|
|
5838
|
+
}
|
|
5839
|
+
if (value[key] === true) {
|
|
5840
|
+
style[key] = true;
|
|
5841
|
+
}
|
|
5842
|
+
}
|
|
5843
|
+
return style.bold || style.italic || style.underline ? style : void 0;
|
|
5844
|
+
}
|
|
5845
|
+
function normalizedKeys(value) {
|
|
5846
|
+
if (!Array.isArray(value)) {
|
|
5847
|
+
throw new Document2CommandError("invalid_inline_token", "citation/reference keys must be an array");
|
|
5848
|
+
}
|
|
5849
|
+
const keys = [];
|
|
5850
|
+
for (const entry of value) {
|
|
5851
|
+
if (typeof entry !== "string") {
|
|
5852
|
+
throw new Document2CommandError("invalid_inline_token", "citation/reference keys must be strings");
|
|
5853
|
+
}
|
|
5854
|
+
const key = entry.trim();
|
|
5855
|
+
if (key.length > 0 && !keys.includes(key)) {
|
|
5856
|
+
keys.push(key);
|
|
5857
|
+
}
|
|
5858
|
+
}
|
|
5859
|
+
if (keys.length === 0) {
|
|
5860
|
+
throw new Document2CommandError("invalid_inline_token", "citation/reference requires at least one non-empty key");
|
|
5861
|
+
}
|
|
5862
|
+
return keys;
|
|
5863
|
+
}
|
|
5864
|
+
function parseMathObject(value, source) {
|
|
5865
|
+
if (!isObject3(value) || value.node_type !== "MathObject") {
|
|
5866
|
+
throw new Document2CommandError("math_object_mismatch", "math_object must be a structured MathObject");
|
|
5867
|
+
}
|
|
5868
|
+
const spans = detectInlineSpans2(source);
|
|
5869
|
+
const span = spans[0];
|
|
5870
|
+
if (spans.length !== 1 || span?.kind !== "math" || span.start !== 0 || span.end !== source.length) {
|
|
5871
|
+
throw new Document2CommandError("math_object_mismatch", "math source must contain exactly one complete delimited span");
|
|
5872
|
+
}
|
|
5873
|
+
if (value.math_mode !== span.opening || value.closing !== span.closing) {
|
|
5874
|
+
throw new Document2CommandError("math_object_mismatch", "math_object delimiters do not match math source");
|
|
5875
|
+
}
|
|
5876
|
+
try {
|
|
5877
|
+
fromMathObjectJson(value, value.source_side === "arabic" ? "arabic" : "english");
|
|
5878
|
+
} catch {
|
|
5879
|
+
throw new Document2CommandError("math_object_mismatch", "math_object must contain a valid structured equation");
|
|
5880
|
+
}
|
|
5881
|
+
return value;
|
|
5882
|
+
}
|
|
5883
|
+
function parseToken(value) {
|
|
5884
|
+
if (!isObject3(value) || typeof value.kind !== "string") {
|
|
5885
|
+
throw new Document2CommandError("invalid_inline_token", "token requires a kind");
|
|
5886
|
+
}
|
|
5887
|
+
if (value.kind === "text") {
|
|
5888
|
+
const text = requireString2(value.text, "token.text");
|
|
5889
|
+
if (detectInlineSpans2(text).length > 0) {
|
|
5890
|
+
throw new Document2CommandError("invalid_inline_token", "text token contains structured inline syntax");
|
|
5891
|
+
}
|
|
5892
|
+
const style = parseStyle(value.style);
|
|
5893
|
+
return { kind: "text", text, ...style ? { style } : {} };
|
|
5894
|
+
}
|
|
5895
|
+
if (value.kind === "cite") {
|
|
5896
|
+
return { kind: "cite", keys: normalizedKeys(value.keys) };
|
|
5897
|
+
}
|
|
5898
|
+
if (value.kind === "ref") {
|
|
5899
|
+
if (value.ref_command !== "ref" && value.ref_command !== "eqref") {
|
|
5900
|
+
throw new Document2CommandError("invalid_inline_token", "ref_command must be ref or eqref");
|
|
5901
|
+
}
|
|
5902
|
+
return { kind: "ref", keys: normalizedKeys(value.keys), ref_command: value.ref_command };
|
|
5903
|
+
}
|
|
5904
|
+
if (value.kind === "math") {
|
|
5905
|
+
const source = requireString2(value.source, "token.source", false);
|
|
5906
|
+
return { kind: "math", source, math_object: parseMathObject(value.math_object, source) };
|
|
5907
|
+
}
|
|
5908
|
+
throw new Document2CommandError("invalid_inline_token", "Unsupported inline token kind");
|
|
5909
|
+
}
|
|
5910
|
+
function parseInlineCommand(value) {
|
|
5911
|
+
if (value.op === "insert_inline_token") {
|
|
5912
|
+
return {
|
|
5913
|
+
op: value.op,
|
|
5914
|
+
field_id: requireString2(value.field_id, "field_id", false).trim(),
|
|
5915
|
+
token: parseToken(value.token),
|
|
5916
|
+
anchor: parseInlineAnchor(value.anchor)
|
|
5917
|
+
};
|
|
5918
|
+
}
|
|
5919
|
+
if (value.op === "replace_inline_token") {
|
|
5920
|
+
return {
|
|
5921
|
+
op: value.op,
|
|
5922
|
+
field_id: requireString2(value.field_id, "field_id", false).trim(),
|
|
5923
|
+
token_id: requireString2(value.token_id, "token_id", false).trim(),
|
|
5924
|
+
token: parseToken(value.token)
|
|
5925
|
+
};
|
|
5926
|
+
}
|
|
5927
|
+
if (value.op === "remove_inline_token") {
|
|
5928
|
+
return {
|
|
5929
|
+
op: value.op,
|
|
5930
|
+
field_id: requireString2(value.field_id, "field_id", false).trim(),
|
|
5931
|
+
token_id: requireString2(value.token_id, "token_id", false).trim()
|
|
5932
|
+
};
|
|
5933
|
+
}
|
|
5934
|
+
throw new Document2CommandError("invalid_command", "Unsupported inline command");
|
|
5935
|
+
}
|
|
5936
|
+
function liveToken(input, id) {
|
|
5937
|
+
if (input.kind === "text") {
|
|
5938
|
+
return { id, kind: "text", text: input.text, ...input.style ? { style: { ...input.style } } : {} };
|
|
5939
|
+
}
|
|
5940
|
+
if (input.kind === "cite") {
|
|
5941
|
+
return { id, kind: "cite", keys: [...input.keys] };
|
|
5942
|
+
}
|
|
5943
|
+
if (input.kind === "ref") {
|
|
5944
|
+
return { id, kind: "ref", keys: [...input.keys], refCommand: input.ref_command };
|
|
5945
|
+
}
|
|
5946
|
+
const mathObject = input.math_object;
|
|
5947
|
+
const spans = detectInlineSpans2(input.source);
|
|
5948
|
+
const span = spans[0];
|
|
5949
|
+
if (!span || span.kind !== "math") {
|
|
5950
|
+
throw new Document2CommandError("math_object_mismatch", "math source is not a complete delimited span");
|
|
5951
|
+
}
|
|
5952
|
+
return {
|
|
5953
|
+
id,
|
|
5954
|
+
kind: "math",
|
|
5955
|
+
display: span.display,
|
|
5956
|
+
opening: span.opening,
|
|
5957
|
+
closing: span.closing,
|
|
5958
|
+
source: input.source,
|
|
5959
|
+
sourceSide: mathObject.source_side === "arabic" ? "arabic" : "english",
|
|
5960
|
+
math: fromMathObjectJson(mathObject, mathObject.source_side === "arabic" ? "arabic" : "english"),
|
|
5961
|
+
editable: true,
|
|
5962
|
+
sourceOwner: mathObject.source_owner === "editor" ? "editor" : "imported-structured",
|
|
5963
|
+
...mathObject.label_enabled !== void 0 ? { labelEnabled: mathObject.label_enabled } : {},
|
|
5964
|
+
...mathObject.label !== void 0 ? { label: mathObject.label } : {}
|
|
5965
|
+
};
|
|
5966
|
+
}
|
|
5967
|
+
function insertionIndex(tokens, anchor) {
|
|
5968
|
+
if ("start" in anchor) {
|
|
5969
|
+
return 0;
|
|
5970
|
+
}
|
|
5971
|
+
if ("end" in anchor) {
|
|
5972
|
+
return tokens.length;
|
|
5973
|
+
}
|
|
5974
|
+
const id = "before_token_id" in anchor ? anchor.before_token_id : anchor.after_token_id;
|
|
5975
|
+
const index = tokens.findIndex((token) => token.id === id);
|
|
5976
|
+
if (index < 0) {
|
|
5977
|
+
throw new Document2CommandError("token_not_found", "Anchor token was not found");
|
|
5978
|
+
}
|
|
5979
|
+
return "before_token_id" in anchor ? index : index + 1;
|
|
5980
|
+
}
|
|
5981
|
+
function applyInlineCommand(document2, command) {
|
|
5982
|
+
const field = findField(document2.blocks, command.field_id);
|
|
5983
|
+
if (!field) {
|
|
5984
|
+
throw new Document2CommandError("field_not_found", "Inline field was not found");
|
|
5985
|
+
}
|
|
5986
|
+
if (command.op === "insert_inline_token") {
|
|
5987
|
+
const index2 = insertionIndex(field.tokens, command.anchor);
|
|
5988
|
+
field.tokens.splice(index2, 0, liveToken(command.token, newTokenId(document2, command.token.kind)));
|
|
5989
|
+
return;
|
|
5990
|
+
}
|
|
5991
|
+
const index = field.tokens.findIndex((token) => token.id === command.token_id);
|
|
5992
|
+
if (index < 0) {
|
|
5993
|
+
throw new Document2CommandError("token_not_found", "Inline token was not found");
|
|
5994
|
+
}
|
|
5995
|
+
if (command.op === "replace_inline_token") {
|
|
5996
|
+
field.tokens[index] = liveToken(command.token, command.token_id);
|
|
5997
|
+
return;
|
|
5998
|
+
}
|
|
5999
|
+
field.tokens = compactTextTokens2(
|
|
6000
|
+
[...field.tokens.slice(0, index), ...field.tokens.slice(index + 1)],
|
|
6001
|
+
newTokenId(document2, "text")
|
|
6002
|
+
);
|
|
6003
|
+
}
|
|
6004
|
+
|
|
6005
|
+
// src/document2/listJsonCommands.ts
|
|
6006
|
+
function stringArray(value, field) {
|
|
6007
|
+
if (!Array.isArray(value) || value.length === 0 || value.some((entry) => typeof entry !== "string")) {
|
|
6008
|
+
throw new Document2CommandError("invalid_command", `${field} must be a non-empty string array`);
|
|
6009
|
+
}
|
|
6010
|
+
return [...value];
|
|
6011
|
+
}
|
|
6012
|
+
function parseListCommand(value) {
|
|
6013
|
+
if (value.op === "insert_list") {
|
|
6014
|
+
const metadata = parseMetadata(value.metadata);
|
|
6015
|
+
return {
|
|
6016
|
+
op: value.op,
|
|
6017
|
+
ordered: requireBoolean(value.ordered, "ordered"),
|
|
6018
|
+
items: stringArray(value.items, "items"),
|
|
6019
|
+
anchor: parseBlockAnchor(value.anchor),
|
|
6020
|
+
...metadata ? { metadata } : {}
|
|
6021
|
+
};
|
|
6022
|
+
}
|
|
6023
|
+
if (value.op === "insert_list_item") {
|
|
6024
|
+
return {
|
|
6025
|
+
op: value.op,
|
|
6026
|
+
list_id: requireString2(value.list_id, "list_id", false).trim(),
|
|
6027
|
+
text: requireString2(value.text, "text"),
|
|
6028
|
+
anchor: parseListItemAnchor(value.anchor)
|
|
6029
|
+
};
|
|
6030
|
+
}
|
|
6031
|
+
if (value.op === "replace_list_item") {
|
|
6032
|
+
return {
|
|
6033
|
+
op: value.op,
|
|
6034
|
+
list_id: requireString2(value.list_id, "list_id", false).trim(),
|
|
6035
|
+
item_id: requireString2(value.item_id, "item_id", false).trim(),
|
|
6036
|
+
text: requireString2(value.text, "text")
|
|
6037
|
+
};
|
|
6038
|
+
}
|
|
6039
|
+
if (value.op === "remove_list_item") {
|
|
6040
|
+
return {
|
|
6041
|
+
op: value.op,
|
|
6042
|
+
list_id: requireString2(value.list_id, "list_id", false).trim(),
|
|
6043
|
+
item_id: requireString2(value.item_id, "item_id", false).trim()
|
|
6044
|
+
};
|
|
6045
|
+
}
|
|
6046
|
+
if (value.op === "move_list_item") {
|
|
6047
|
+
return {
|
|
6048
|
+
op: value.op,
|
|
6049
|
+
list_id: requireString2(value.list_id, "list_id", false).trim(),
|
|
6050
|
+
item_id: requireString2(value.item_id, "item_id", false).trim(),
|
|
6051
|
+
anchor: parseListItemAnchor(value.anchor)
|
|
6052
|
+
};
|
|
6053
|
+
}
|
|
6054
|
+
throw new Document2CommandError("invalid_command", "Unsupported list command");
|
|
6055
|
+
}
|
|
6056
|
+
function newItem(document2, text) {
|
|
6057
|
+
return { id: newItemId(document2), field: createCommandInlineField(document2, text), blocks: [] };
|
|
6058
|
+
}
|
|
6059
|
+
function insertList(document2, command) {
|
|
6060
|
+
const ordered = command.ordered;
|
|
6061
|
+
const block = {
|
|
6062
|
+
id: newBlockId(document2),
|
|
6063
|
+
kind: "list",
|
|
6064
|
+
command: ordered ? "\\begin{enumerate}" : "\\begin{itemize}",
|
|
6065
|
+
closing: ordered ? "\\end{enumerate}" : "\\end{itemize}",
|
|
6066
|
+
items: command.items.map((text) => newItem(document2, text)),
|
|
6067
|
+
...command.metadata ? { metadata: { ...command.metadata } } : {}
|
|
6068
|
+
};
|
|
6069
|
+
document2.blocks.splice(blockInsertionIndex(document2, command.anchor), 0, block);
|
|
6070
|
+
}
|
|
6071
|
+
function applyListCommand(document2, command) {
|
|
6072
|
+
if (command.op === "insert_list") {
|
|
6073
|
+
insertList(document2, command);
|
|
6074
|
+
return;
|
|
6075
|
+
}
|
|
6076
|
+
const list = requireList(document2, command.list_id);
|
|
6077
|
+
if (command.op === "insert_list_item") {
|
|
6078
|
+
list.items.splice(itemInsertionIndex(list, command.anchor), 0, newItem(document2, command.text));
|
|
6079
|
+
return;
|
|
6080
|
+
}
|
|
6081
|
+
const itemIndex = list.items.findIndex((item2) => item2.id === command.item_id);
|
|
6082
|
+
if (itemIndex < 0) {
|
|
6083
|
+
throw new Document2CommandError("item_not_found", "Document list item was not found");
|
|
6084
|
+
}
|
|
6085
|
+
if (command.op === "replace_list_item") {
|
|
6086
|
+
replacePlainField(document2, list.items[itemIndex].field, command.text);
|
|
6087
|
+
return;
|
|
6088
|
+
}
|
|
6089
|
+
if (command.op === "remove_list_item") {
|
|
6090
|
+
if (list.items.length === 1) {
|
|
6091
|
+
throw new Document2CommandError("minimum_structure", "A list must retain at least one item");
|
|
6092
|
+
}
|
|
6093
|
+
list.items.splice(itemIndex, 1);
|
|
6094
|
+
return;
|
|
6095
|
+
}
|
|
6096
|
+
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;
|
|
6097
|
+
if (anchorId === command.item_id) {
|
|
6098
|
+
throw new Document2CommandError("invalid_anchor", "A list item cannot be moved relative to itself");
|
|
6099
|
+
}
|
|
6100
|
+
const [item] = list.items.splice(itemIndex, 1);
|
|
6101
|
+
if (!item) {
|
|
6102
|
+
throw new Document2CommandError("item_not_found", "Document list item was not found");
|
|
6103
|
+
}
|
|
6104
|
+
list.items.splice(itemInsertionIndex(list, command.anchor), 0, item);
|
|
6105
|
+
}
|
|
6106
|
+
|
|
6107
|
+
// src/document2/tableJsonCommands.ts
|
|
6108
|
+
function stringArray2(value, field) {
|
|
6109
|
+
if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) {
|
|
6110
|
+
throw new Document2CommandError("invalid_command", `${field} must be a string array`);
|
|
6111
|
+
}
|
|
6112
|
+
return [...value];
|
|
6113
|
+
}
|
|
6114
|
+
function rectangularRows(value) {
|
|
6115
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
6116
|
+
throw new Document2CommandError("invalid_table_shape", "rows must be a non-empty array");
|
|
6117
|
+
}
|
|
6118
|
+
const rows = value.map((row, index) => stringArray2(row, `rows[${String(index)}]`));
|
|
6119
|
+
const columnCount = rows[0]?.length ?? 0;
|
|
6120
|
+
if (columnCount === 0 || rows.some((row) => row.length !== columnCount)) {
|
|
6121
|
+
throw new Document2CommandError("invalid_table_shape", "Table rows must form a non-empty rectangle");
|
|
6122
|
+
}
|
|
6123
|
+
return rows;
|
|
6124
|
+
}
|
|
6125
|
+
function columns(value) {
|
|
6126
|
+
const result = requireString2(value, "columns", false);
|
|
6127
|
+
if (result.trim().length === 0) {
|
|
6128
|
+
throw new Document2CommandError("invalid_table_shape", "columns must be a non-empty LaTeX specification");
|
|
6129
|
+
}
|
|
6130
|
+
return result;
|
|
6131
|
+
}
|
|
6132
|
+
function parseTableCommand(value) {
|
|
6133
|
+
if (value.op === "insert_table") {
|
|
6134
|
+
const caption = optionalString(value, "caption");
|
|
6135
|
+
const label = optionalString(value, "label");
|
|
6136
|
+
const metadata = parseMetadata(value.metadata);
|
|
6137
|
+
return {
|
|
6138
|
+
op: value.op,
|
|
6139
|
+
rows: rectangularRows(value.rows),
|
|
6140
|
+
columns: columns(value.columns),
|
|
6141
|
+
...caption !== void 0 ? { caption } : {},
|
|
6142
|
+
...label !== void 0 ? { label } : {},
|
|
6143
|
+
anchor: parseBlockAnchor(value.anchor),
|
|
6144
|
+
...metadata ? { metadata } : {}
|
|
6145
|
+
};
|
|
6146
|
+
}
|
|
6147
|
+
if (value.op === "replace_table_cell") {
|
|
6148
|
+
return {
|
|
6149
|
+
op: value.op,
|
|
6150
|
+
table_id: requireString2(value.table_id, "table_id", false).trim(),
|
|
6151
|
+
row_index: requireIndex(value.row_index, "row_index"),
|
|
6152
|
+
column_index: requireIndex(value.column_index, "column_index"),
|
|
6153
|
+
text: requireString2(value.text, "text")
|
|
6154
|
+
};
|
|
6155
|
+
}
|
|
6156
|
+
if (value.op === "insert_table_row") {
|
|
6157
|
+
return {
|
|
6158
|
+
op: value.op,
|
|
6159
|
+
table_id: requireString2(value.table_id, "table_id", false).trim(),
|
|
6160
|
+
index: requireIndex(value.index, "index"),
|
|
6161
|
+
values: stringArray2(value.values, "values")
|
|
6162
|
+
};
|
|
6163
|
+
}
|
|
6164
|
+
if (value.op === "remove_table_row") {
|
|
6165
|
+
return {
|
|
6166
|
+
op: value.op,
|
|
6167
|
+
table_id: requireString2(value.table_id, "table_id", false).trim(),
|
|
6168
|
+
index: requireIndex(value.index, "index")
|
|
6169
|
+
};
|
|
6170
|
+
}
|
|
6171
|
+
if (value.op === "move_table_row") {
|
|
6172
|
+
return {
|
|
6173
|
+
op: value.op,
|
|
6174
|
+
table_id: requireString2(value.table_id, "table_id", false).trim(),
|
|
6175
|
+
from_index: requireIndex(value.from_index, "from_index"),
|
|
6176
|
+
to_index: requireIndex(value.to_index, "to_index")
|
|
6177
|
+
};
|
|
6178
|
+
}
|
|
6179
|
+
if (value.op === "insert_table_column") {
|
|
6180
|
+
return {
|
|
6181
|
+
op: value.op,
|
|
6182
|
+
table_id: requireString2(value.table_id, "table_id", false).trim(),
|
|
6183
|
+
index: requireIndex(value.index, "index"),
|
|
6184
|
+
values: stringArray2(value.values, "values"),
|
|
6185
|
+
columns: columns(value.columns)
|
|
6186
|
+
};
|
|
6187
|
+
}
|
|
6188
|
+
if (value.op === "remove_table_column") {
|
|
6189
|
+
return {
|
|
6190
|
+
op: value.op,
|
|
6191
|
+
table_id: requireString2(value.table_id, "table_id", false).trim(),
|
|
6192
|
+
index: requireIndex(value.index, "index"),
|
|
6193
|
+
columns: columns(value.columns)
|
|
6194
|
+
};
|
|
6195
|
+
}
|
|
6196
|
+
if (value.op === "move_table_column") {
|
|
6197
|
+
return {
|
|
6198
|
+
op: value.op,
|
|
6199
|
+
table_id: requireString2(value.table_id, "table_id", false).trim(),
|
|
6200
|
+
from_index: requireIndex(value.from_index, "from_index"),
|
|
6201
|
+
to_index: requireIndex(value.to_index, "to_index"),
|
|
6202
|
+
columns: columns(value.columns)
|
|
6203
|
+
};
|
|
6204
|
+
}
|
|
6205
|
+
throw new Document2CommandError("invalid_command", "Unsupported table command");
|
|
6206
|
+
}
|
|
6207
|
+
function insertTable(document2, command) {
|
|
6208
|
+
const block = {
|
|
6209
|
+
id: newBlockId(document2),
|
|
6210
|
+
kind: "table",
|
|
6211
|
+
command: "\\begin{tabular}",
|
|
6212
|
+
closing: "\\end{tabular}",
|
|
6213
|
+
columns: command.columns,
|
|
6214
|
+
rows: command.rows.map((row) => row.map((cell) => createCommandInlineField(document2, cell))),
|
|
6215
|
+
...defaultFloatMeta(),
|
|
6216
|
+
...command.caption !== void 0 ? { caption: command.caption, captionEnabled: command.caption.trim().length > 0 } : {},
|
|
6217
|
+
...command.label !== void 0 ? { label: command.label, labelEnabled: command.label.trim().length > 0 } : {},
|
|
6218
|
+
...command.metadata ? { metadata: { ...command.metadata } } : {}
|
|
6219
|
+
};
|
|
6220
|
+
document2.blocks.splice(blockInsertionIndex(document2, command.anchor), 0, block);
|
|
6221
|
+
}
|
|
6222
|
+
function checkCell(table, rowIndex, columnIndex) {
|
|
6223
|
+
if (rowIndex >= table.rows.length || columnIndex >= (table.rows[rowIndex]?.length ?? 0)) {
|
|
6224
|
+
throw new Document2CommandError("index_out_of_range", "Table cell index is out of range");
|
|
6225
|
+
}
|
|
6226
|
+
}
|
|
6227
|
+
function checkExistingIndex(index, length, field) {
|
|
6228
|
+
if (index >= length) {
|
|
6229
|
+
throw new Document2CommandError("index_out_of_range", `${field} is out of range`);
|
|
6230
|
+
}
|
|
6231
|
+
}
|
|
6232
|
+
function applyTableCommand(document2, command) {
|
|
6233
|
+
if (command.op === "insert_table") {
|
|
6234
|
+
insertTable(document2, command);
|
|
6235
|
+
return;
|
|
6236
|
+
}
|
|
6237
|
+
const table = requireTable(document2, command.table_id);
|
|
6238
|
+
const columnCount = table.rows[0]?.length ?? 0;
|
|
6239
|
+
if (table.rows.length === 0 || columnCount === 0 || table.rows.some((row) => row.length !== columnCount)) {
|
|
6240
|
+
throw new Document2CommandError("invalid_table_shape", "Target table must be a non-empty rectangle");
|
|
6241
|
+
}
|
|
6242
|
+
if (command.op === "replace_table_cell") {
|
|
6243
|
+
checkCell(table, command.row_index, command.column_index);
|
|
6244
|
+
replacePlainField(document2, table.rows[command.row_index][command.column_index], command.text);
|
|
6245
|
+
return;
|
|
6246
|
+
}
|
|
6247
|
+
if (command.op === "insert_table_row") {
|
|
6248
|
+
if (command.index > table.rows.length) {
|
|
6249
|
+
throw new Document2CommandError("index_out_of_range", "Table row insertion index is out of range");
|
|
6250
|
+
}
|
|
6251
|
+
if (command.values.length !== columnCount) {
|
|
6252
|
+
throw new Document2CommandError("invalid_table_shape", "Inserted row must match the current column count");
|
|
6253
|
+
}
|
|
6254
|
+
table.rows.splice(command.index, 0, command.values.map((value) => createCommandInlineField(document2, value)));
|
|
6255
|
+
return;
|
|
6256
|
+
}
|
|
6257
|
+
if (command.op === "remove_table_row") {
|
|
6258
|
+
checkExistingIndex(command.index, table.rows.length, "Table row index");
|
|
6259
|
+
if (table.rows.length === 1) {
|
|
6260
|
+
throw new Document2CommandError("minimum_structure", "A table must retain at least one row");
|
|
6261
|
+
}
|
|
6262
|
+
table.rows.splice(command.index, 1);
|
|
6263
|
+
return;
|
|
6264
|
+
}
|
|
6265
|
+
if (command.op === "move_table_row") {
|
|
6266
|
+
checkExistingIndex(command.from_index, table.rows.length, "Table source row index");
|
|
6267
|
+
checkExistingIndex(command.to_index, table.rows.length, "Table target row index");
|
|
6268
|
+
const [row] = table.rows.splice(command.from_index, 1);
|
|
6269
|
+
table.rows.splice(command.to_index, 0, row);
|
|
6270
|
+
return;
|
|
6271
|
+
}
|
|
6272
|
+
if (command.op === "insert_table_column") {
|
|
6273
|
+
if (command.index > columnCount) {
|
|
6274
|
+
throw new Document2CommandError("index_out_of_range", "Table column insertion index is out of range");
|
|
6275
|
+
}
|
|
6276
|
+
if (command.values.length !== table.rows.length) {
|
|
6277
|
+
throw new Document2CommandError("invalid_table_shape", "Inserted column requires one value per row");
|
|
6278
|
+
}
|
|
6279
|
+
table.rows.forEach((row, index) => row.splice(command.index, 0, createCommandInlineField(document2, command.values[index])));
|
|
6280
|
+
table.columns = command.columns;
|
|
6281
|
+
return;
|
|
6282
|
+
}
|
|
6283
|
+
if (command.op === "remove_table_column") {
|
|
6284
|
+
checkExistingIndex(command.index, columnCount, "Table column index");
|
|
6285
|
+
if (columnCount === 1) {
|
|
6286
|
+
throw new Document2CommandError("minimum_structure", "A table must retain at least one column");
|
|
6287
|
+
}
|
|
6288
|
+
table.rows.forEach((row) => row.splice(command.index, 1));
|
|
6289
|
+
table.columns = command.columns;
|
|
6290
|
+
return;
|
|
6291
|
+
}
|
|
6292
|
+
checkExistingIndex(command.from_index, columnCount, "Table source column index");
|
|
6293
|
+
checkExistingIndex(command.to_index, columnCount, "Table target column index");
|
|
6294
|
+
table.rows.forEach((row) => {
|
|
6295
|
+
const [cell] = row.splice(command.from_index, 1);
|
|
6296
|
+
row.splice(command.to_index, 0, cell);
|
|
6297
|
+
});
|
|
6298
|
+
table.columns = command.columns;
|
|
6299
|
+
}
|
|
6300
|
+
|
|
5453
6301
|
// src/document2/exportJson.ts
|
|
5454
6302
|
function serializeField(field) {
|
|
5455
6303
|
let value = "";
|
|
@@ -5502,12 +6350,13 @@ function serializeField(field) {
|
|
|
5502
6350
|
...token.label !== void 0 ? { label: token.label } : {}
|
|
5503
6351
|
});
|
|
5504
6352
|
}
|
|
5505
|
-
return { value, formats, mathObjects, hasPersistedMath };
|
|
6353
|
+
return { value, formats, mathObjects, hasPersistedMath, inlineIds: inlineIdsFromField(field) };
|
|
5506
6354
|
}
|
|
5507
6355
|
function fieldJson(field) {
|
|
5508
6356
|
const serialized = serializeField(field);
|
|
5509
6357
|
return {
|
|
5510
6358
|
value: serialized.value,
|
|
6359
|
+
inline_ids: serialized.inlineIds,
|
|
5511
6360
|
...serialized.formats.length > 0 ? { formats: serialized.formats } : {},
|
|
5512
6361
|
...serialized.hasPersistedMath ? { math_objects: serialized.mathObjects } : {}
|
|
5513
6362
|
};
|
|
@@ -5515,7 +6364,9 @@ function fieldJson(field) {
|
|
|
5515
6364
|
function listItemJson(item) {
|
|
5516
6365
|
const field = fieldJson(item.field);
|
|
5517
6366
|
return {
|
|
6367
|
+
id: item.id,
|
|
5518
6368
|
value: field.value ?? "",
|
|
6369
|
+
inline_ids: field.inline_ids,
|
|
5519
6370
|
...field.formats ? { formats: field.formats } : {},
|
|
5520
6371
|
...field.math_objects ? { math_objects: field.math_objects } : {},
|
|
5521
6372
|
...item.blocks.length > 0 ? { blocks: item.blocks.map(blockJson) } : {}
|
|
@@ -5527,6 +6378,7 @@ function blockJson(block) {
|
|
|
5527
6378
|
id: block.id,
|
|
5528
6379
|
command: block.command,
|
|
5529
6380
|
...fieldJson(block.field),
|
|
6381
|
+
...block.metadata ? { metadata: { ...block.metadata } } : {},
|
|
5530
6382
|
...block.command === "\\paragraph" ? { centered: block.centered === true } : {}
|
|
5531
6383
|
};
|
|
5532
6384
|
}
|
|
@@ -5535,7 +6387,8 @@ function blockJson(block) {
|
|
|
5535
6387
|
id: block.id,
|
|
5536
6388
|
command: block.command,
|
|
5537
6389
|
closing: block.closing,
|
|
5538
|
-
items: block.items.map(listItemJson)
|
|
6390
|
+
items: block.items.map(listItemJson),
|
|
6391
|
+
...block.metadata ? { metadata: { ...block.metadata } } : {}
|
|
5539
6392
|
};
|
|
5540
6393
|
}
|
|
5541
6394
|
if (block.kind === "table") {
|
|
@@ -5547,13 +6400,15 @@ function blockJson(block) {
|
|
|
5547
6400
|
closing: block.closing,
|
|
5548
6401
|
columns: block.columns,
|
|
5549
6402
|
rows: fields.map((row) => row.map((field) => field.value)),
|
|
6403
|
+
cell_inline_ids: fields.map((row) => row.map((field) => field.inlineIds)),
|
|
5550
6404
|
...fields.some((row) => row.some((field) => field.formats.length > 0)) ? { cell_formats: fields.map((row) => row.map((field) => field.formats)) } : {},
|
|
5551
6405
|
...hasPersistedMath ? { math_objects: fields.flatMap((row) => row.flatMap((field) => field.mathObjects)) } : {},
|
|
5552
6406
|
centered: block.centered,
|
|
5553
6407
|
caption_enabled: block.captionEnabled,
|
|
5554
6408
|
caption: block.caption,
|
|
5555
6409
|
label_enabled: block.labelEnabled,
|
|
5556
|
-
label: block.label
|
|
6410
|
+
label: block.label,
|
|
6411
|
+
...block.metadata ? { metadata: { ...block.metadata } } : {}
|
|
5557
6412
|
};
|
|
5558
6413
|
}
|
|
5559
6414
|
if (block.kind === "image") {
|
|
@@ -5567,13 +6422,24 @@ function blockJson(block) {
|
|
|
5567
6422
|
caption_enabled: block.captionEnabled,
|
|
5568
6423
|
caption: block.caption,
|
|
5569
6424
|
label_enabled: block.labelEnabled,
|
|
5570
|
-
label: block.label
|
|
6425
|
+
label: block.label,
|
|
6426
|
+
...block.metadata ? { metadata: { ...block.metadata } } : {}
|
|
5571
6427
|
};
|
|
5572
6428
|
}
|
|
5573
6429
|
if (block.kind === "bibliography") {
|
|
5574
|
-
return {
|
|
6430
|
+
return {
|
|
6431
|
+
id: block.id,
|
|
6432
|
+
command: block.command,
|
|
6433
|
+
closing: block.closing,
|
|
6434
|
+
...block.metadata ? { metadata: { ...block.metadata } } : {}
|
|
6435
|
+
};
|
|
5575
6436
|
}
|
|
5576
|
-
return {
|
|
6437
|
+
return {
|
|
6438
|
+
id: block.id,
|
|
6439
|
+
command: block.command,
|
|
6440
|
+
value: block.value,
|
|
6441
|
+
...block.metadata ? { metadata: { ...block.metadata } } : {}
|
|
6442
|
+
};
|
|
5577
6443
|
}
|
|
5578
6444
|
function referenceJson(reference) {
|
|
5579
6445
|
return {
|
|
@@ -5604,49 +6470,14 @@ function toDocumentJson2(document2) {
|
|
|
5604
6470
|
}
|
|
5605
6471
|
|
|
5606
6472
|
// src/document2/jsonCommands.ts
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
constructor(code, message) {
|
|
5610
|
-
super(message);
|
|
5611
|
-
this.name = "Document2CommandError";
|
|
5612
|
-
this.code = code;
|
|
5613
|
-
}
|
|
5614
|
-
};
|
|
5615
|
-
function isObject3(value) {
|
|
5616
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6473
|
+
function isInlineCommand(command) {
|
|
6474
|
+
return command.op === "insert_inline_token" || command.op === "replace_inline_token" || command.op === "remove_inline_token";
|
|
5617
6475
|
}
|
|
5618
|
-
function
|
|
5619
|
-
|
|
5620
|
-
throw new Document2CommandError("invalid_command", `${field} must be a${allowEmpty ? "" : " non-empty"} string`);
|
|
5621
|
-
}
|
|
5622
|
-
return value;
|
|
6476
|
+
function isListCommand(command) {
|
|
6477
|
+
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";
|
|
5623
6478
|
}
|
|
5624
|
-
function
|
|
5625
|
-
|
|
5626
|
-
throw new Document2CommandError("invalid_command", "anchor must be an object");
|
|
5627
|
-
}
|
|
5628
|
-
const hasEnd = value.end === true;
|
|
5629
|
-
const afterBlockId2 = typeof value.after_block_id === "string" ? value.after_block_id.trim() : "";
|
|
5630
|
-
const hasAfterBlock = afterBlockId2.length > 0;
|
|
5631
|
-
if (hasEnd && hasAfterBlock) {
|
|
5632
|
-
throw new Document2CommandError("invalid_command", "anchor cannot contain both end and after_block_id");
|
|
5633
|
-
}
|
|
5634
|
-
if (hasEnd) {
|
|
5635
|
-
return { end: true };
|
|
5636
|
-
}
|
|
5637
|
-
if (hasAfterBlock) {
|
|
5638
|
-
return { after_block_id: afterBlockId2 };
|
|
5639
|
-
}
|
|
5640
|
-
throw new Document2CommandError("invalid_command", "anchor requires end: true or a non-empty after_block_id");
|
|
5641
|
-
}
|
|
5642
|
-
function optionalString(value, field) {
|
|
5643
|
-
if (!(field in value)) {
|
|
5644
|
-
return void 0;
|
|
5645
|
-
}
|
|
5646
|
-
if (typeof value[field] !== "string") {
|
|
5647
|
-
throw new Document2CommandError("invalid_command", `${field} must be a string when provided`);
|
|
5648
|
-
}
|
|
5649
|
-
return value[field];
|
|
6479
|
+
function isTableCommand(command) {
|
|
6480
|
+
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";
|
|
5650
6481
|
}
|
|
5651
6482
|
function parseTextBlockKind(value) {
|
|
5652
6483
|
if (value === "section" || value === "subsection" || value === "subsubsection" || value === "paragraph") {
|
|
@@ -5654,16 +6485,15 @@ function parseTextBlockKind(value) {
|
|
|
5654
6485
|
}
|
|
5655
6486
|
throw new Document2CommandError("invalid_command", "kind must be section, subsection, subsubsection, or paragraph");
|
|
5656
6487
|
}
|
|
5657
|
-
function
|
|
5658
|
-
if (!isObject3(value) || typeof value.op !== "string") {
|
|
5659
|
-
throw new Document2CommandError("invalid_command", "command requires an op");
|
|
5660
|
-
}
|
|
6488
|
+
function parseBasicCommand(value) {
|
|
5661
6489
|
if (value.op === "insert_text_block") {
|
|
6490
|
+
const metadata = parseMetadata(value.metadata);
|
|
5662
6491
|
return {
|
|
5663
6492
|
op: value.op,
|
|
5664
6493
|
kind: parseTextBlockKind(value.kind),
|
|
5665
6494
|
text: requireString2(value.text, "text"),
|
|
5666
|
-
anchor:
|
|
6495
|
+
anchor: parseBlockAnchor(value.anchor),
|
|
6496
|
+
...metadata ? { metadata } : {}
|
|
5667
6497
|
};
|
|
5668
6498
|
}
|
|
5669
6499
|
if (value.op === "replace_text_block") {
|
|
@@ -5674,140 +6504,118 @@ function parseCommand2(value) {
|
|
|
5674
6504
|
};
|
|
5675
6505
|
}
|
|
5676
6506
|
if (value.op === "remove_block") {
|
|
5677
|
-
return {
|
|
5678
|
-
op: value.op,
|
|
5679
|
-
block_id: requireString2(value.block_id, "block_id", false).trim()
|
|
5680
|
-
};
|
|
6507
|
+
return { op: value.op, block_id: requireString2(value.block_id, "block_id", false).trim() };
|
|
5681
6508
|
}
|
|
5682
6509
|
if (value.op === "insert_figure") {
|
|
5683
6510
|
const figureValue = optionalString(value, "value");
|
|
5684
6511
|
const caption = optionalString(value, "caption");
|
|
5685
6512
|
const label = optionalString(value, "label");
|
|
6513
|
+
const metadata = parseMetadata(value.metadata);
|
|
5686
6514
|
return {
|
|
5687
6515
|
op: value.op,
|
|
5688
6516
|
asset_id: requireString2(value.asset_id, "asset_id", false).trim(),
|
|
5689
6517
|
...figureValue !== void 0 ? { value: figureValue } : {},
|
|
5690
6518
|
...caption !== void 0 ? { caption } : {},
|
|
5691
6519
|
...label !== void 0 ? { label } : {},
|
|
5692
|
-
anchor:
|
|
6520
|
+
anchor: parseBlockAnchor(value.anchor),
|
|
6521
|
+
...metadata ? { metadata } : {}
|
|
5693
6522
|
};
|
|
5694
6523
|
}
|
|
5695
|
-
throw new Document2CommandError("invalid_command",
|
|
6524
|
+
throw new Document2CommandError("invalid_command", "Unsupported block command");
|
|
6525
|
+
}
|
|
6526
|
+
function parseCommand2(value) {
|
|
6527
|
+
if (!isObject3(value) || typeof value.op !== "string") {
|
|
6528
|
+
throw new Document2CommandError("invalid_command", "command requires an op");
|
|
6529
|
+
}
|
|
6530
|
+
if (value.op === "insert_inline_token" || value.op === "replace_inline_token" || value.op === "remove_inline_token") {
|
|
6531
|
+
return parseInlineCommand(value);
|
|
6532
|
+
}
|
|
6533
|
+
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") {
|
|
6534
|
+
return parseListCommand(value);
|
|
6535
|
+
}
|
|
6536
|
+
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") {
|
|
6537
|
+
return parseTableCommand(value);
|
|
6538
|
+
}
|
|
6539
|
+
if (value.op === "insert_text_block" || value.op === "replace_text_block" || value.op === "remove_block" || value.op === "insert_figure") {
|
|
6540
|
+
return parseBasicCommand(value);
|
|
6541
|
+
}
|
|
6542
|
+
throw new Document2CommandError("invalid_command", "Unsupported document command");
|
|
5696
6543
|
}
|
|
5697
6544
|
function parseDocument(json) {
|
|
5698
6545
|
try {
|
|
5699
6546
|
return fromDocumentJson2(json);
|
|
5700
|
-
} catch
|
|
5701
|
-
|
|
5702
|
-
throw new Document2CommandError("invalid_document", message);
|
|
6547
|
+
} catch {
|
|
6548
|
+
throw new Document2CommandError("invalid_document", "Document JSON is invalid");
|
|
5703
6549
|
}
|
|
5704
6550
|
}
|
|
5705
|
-
function
|
|
6551
|
+
function textCommand(kind) {
|
|
5706
6552
|
if (kind === "section") {
|
|
5707
6553
|
return "\\section";
|
|
5708
6554
|
}
|
|
5709
6555
|
if (kind === "subsection") {
|
|
5710
6556
|
return "\\subsection";
|
|
5711
6557
|
}
|
|
5712
|
-
|
|
5713
|
-
return "\\subsubsection";
|
|
5714
|
-
}
|
|
5715
|
-
return "\\paragraph";
|
|
5716
|
-
}
|
|
5717
|
-
function insertionIndex(document2, anchor) {
|
|
5718
|
-
if ("end" in anchor) {
|
|
5719
|
-
return document2.blocks.length;
|
|
5720
|
-
}
|
|
5721
|
-
const index = document2.blocks.findIndex((block) => block.id === anchor.after_block_id);
|
|
5722
|
-
if (index < 0) {
|
|
5723
|
-
throw new Document2CommandError("anchor_not_found", `Anchor block was not found: ${anchor.after_block_id}`);
|
|
5724
|
-
}
|
|
5725
|
-
return index + 1;
|
|
5726
|
-
}
|
|
5727
|
-
function afterBlockId(document2, index) {
|
|
5728
|
-
return index > 0 ? document2.blocks[index - 1]?.id ?? null : null;
|
|
6558
|
+
return kind === "subsubsection" ? "\\subsubsection" : "\\paragraph";
|
|
5729
6559
|
}
|
|
5730
|
-
function
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
|
|
5740
|
-
|
|
5741
|
-
|
|
5742
|
-
throw new Document2CommandError("block_kind_mismatch", "Inserted block is not a text block");
|
|
5743
|
-
}
|
|
5744
|
-
block.field = createInlineField2(command.text);
|
|
5745
|
-
return next;
|
|
5746
|
-
}
|
|
5747
|
-
function replaceTextBlock(document2, command) {
|
|
5748
|
-
const index = document2.blocks.findIndex((block2) => block2.id === command.block_id);
|
|
5749
|
-
if (index < 0) {
|
|
5750
|
-
throw new Document2CommandError("block_not_found", `Document block was not found: ${command.block_id}`);
|
|
5751
|
-
}
|
|
5752
|
-
const block = document2.blocks[index];
|
|
5753
|
-
if (!block || block.kind !== "textBlock") {
|
|
5754
|
-
throw new Document2CommandError("block_kind_mismatch", `Document block is not a text block: ${command.block_id}`);
|
|
5755
|
-
}
|
|
5756
|
-
if (block.field.tokens.some((token) => token.kind !== "text" || token.style !== void 0)) {
|
|
5757
|
-
throw new Document2CommandError(
|
|
5758
|
-
"unsupported_inline_content",
|
|
5759
|
-
"Whole-block replacement is not supported for formatted or structured inline content"
|
|
5760
|
-
);
|
|
5761
|
-
}
|
|
5762
|
-
const next = parseDocument(toDocumentJson2(document2));
|
|
5763
|
-
const nextBlock = next.blocks[index];
|
|
5764
|
-
if (!nextBlock || nextBlock.kind !== "textBlock") {
|
|
5765
|
-
throw new Document2CommandError("block_kind_mismatch", `Document block is not a text block: ${command.block_id}`);
|
|
5766
|
-
}
|
|
5767
|
-
nextBlock.field = createInlineField2(command.text);
|
|
5768
|
-
return next;
|
|
5769
|
-
}
|
|
5770
|
-
function removeBlock(document2, command) {
|
|
5771
|
-
if (!document2.blocks.some((block) => block.id === command.block_id)) {
|
|
5772
|
-
throw new Document2CommandError("block_not_found", `Document block was not found: ${command.block_id}`);
|
|
5773
|
-
}
|
|
5774
|
-
return removeDocument2BlockById(document2, command.block_id);
|
|
5775
|
-
}
|
|
5776
|
-
function insertFigure(document2, command) {
|
|
5777
|
-
const index = insertionIndex(document2, command.anchor);
|
|
5778
|
-
const next = addDocument2ImageBlock(
|
|
5779
|
-
document2,
|
|
5780
|
-
{ assetId: command.asset_id, ...command.value !== void 0 ? { value: command.value } : {} },
|
|
5781
|
-
afterBlockId(document2, index)
|
|
5782
|
-
);
|
|
5783
|
-
const block = insertedBlock(next, index);
|
|
5784
|
-
if (block.kind !== "image") {
|
|
5785
|
-
throw new Document2CommandError("block_kind_mismatch", "Inserted block is not a figure");
|
|
6560
|
+
function applyBasicCommand(document2, command) {
|
|
6561
|
+
if (command.op === "insert_text_block") {
|
|
6562
|
+
const block2 = {
|
|
6563
|
+
id: newBlockId(document2),
|
|
6564
|
+
kind: "textBlock",
|
|
6565
|
+
command: textCommand(command.kind),
|
|
6566
|
+
field: createCommandInlineField(document2, command.text),
|
|
6567
|
+
...command.kind === "paragraph" ? { centered: false } : {},
|
|
6568
|
+
...command.metadata ? { metadata: { ...command.metadata } } : {}
|
|
6569
|
+
};
|
|
6570
|
+
document2.blocks.splice(blockInsertionIndex(document2, command.anchor), 0, block2);
|
|
6571
|
+
return;
|
|
5786
6572
|
}
|
|
5787
|
-
if (command.
|
|
5788
|
-
|
|
5789
|
-
|
|
6573
|
+
if (command.op === "replace_text_block") {
|
|
6574
|
+
const block2 = document2.blocks.find((entry) => entry.id === command.block_id);
|
|
6575
|
+
if (!block2) {
|
|
6576
|
+
throw new Document2CommandError("block_not_found", "Document block was not found");
|
|
6577
|
+
}
|
|
6578
|
+
if (block2.kind !== "textBlock") {
|
|
6579
|
+
throw new Document2CommandError("block_kind_mismatch", "Document block is not a text block");
|
|
6580
|
+
}
|
|
6581
|
+
replacePlainField(document2, block2.field, command.text);
|
|
6582
|
+
return;
|
|
5790
6583
|
}
|
|
5791
|
-
if (command.
|
|
5792
|
-
|
|
5793
|
-
|
|
6584
|
+
if (command.op === "remove_block") {
|
|
6585
|
+
const index = document2.blocks.findIndex((block2) => block2.id === command.block_id);
|
|
6586
|
+
if (index < 0) {
|
|
6587
|
+
throw new Document2CommandError("block_not_found", "Document block was not found");
|
|
6588
|
+
}
|
|
6589
|
+
document2.blocks.splice(index, 1);
|
|
6590
|
+
return;
|
|
5794
6591
|
}
|
|
5795
|
-
|
|
6592
|
+
const block = {
|
|
6593
|
+
id: newBlockId(document2),
|
|
6594
|
+
kind: "image",
|
|
6595
|
+
command: "\\includegraphics",
|
|
6596
|
+
value: command.value ?? command.asset_id,
|
|
6597
|
+
assetId: command.asset_id,
|
|
6598
|
+
options: { width: "0.8\\columnwidth" },
|
|
6599
|
+
...defaultFloatMeta(),
|
|
6600
|
+
...command.caption !== void 0 ? { caption: command.caption, captionEnabled: command.caption.trim().length > 0 } : {},
|
|
6601
|
+
...command.label !== void 0 ? { label: command.label, labelEnabled: command.label.trim().length > 0 } : {},
|
|
6602
|
+
...command.metadata ? { metadata: { ...command.metadata } } : {}
|
|
6603
|
+
};
|
|
6604
|
+
document2.blocks.splice(blockInsertionIndex(document2, command.anchor), 0, block);
|
|
5796
6605
|
}
|
|
5797
6606
|
function applyDocument2Command(json, commandInput) {
|
|
5798
6607
|
const document2 = parseDocument(json);
|
|
5799
6608
|
const command = parseCommand2(commandInput);
|
|
5800
|
-
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
|
|
5806
|
-
next = removeBlock(document2, command);
|
|
6609
|
+
if (isInlineCommand(command)) {
|
|
6610
|
+
applyInlineCommand(document2, command);
|
|
6611
|
+
} else if (isListCommand(command)) {
|
|
6612
|
+
applyListCommand(document2, command);
|
|
6613
|
+
} else if (isTableCommand(command)) {
|
|
6614
|
+
applyTableCommand(document2, command);
|
|
5807
6615
|
} else {
|
|
5808
|
-
|
|
6616
|
+
applyBasicCommand(document2, command);
|
|
5809
6617
|
}
|
|
5810
|
-
return toDocumentJson2(
|
|
6618
|
+
return toDocumentJson2(document2);
|
|
5811
6619
|
}
|
|
5812
6620
|
|
|
5813
6621
|
// src/document2/outline.ts
|
|
@@ -6507,19 +7315,21 @@ function previewInlines(field, islands, output, equationSide, document2, preview
|
|
|
6507
7315
|
}
|
|
6508
7316
|
function textBlockPreview(block, islands, output, equationSide, document2, previewOptions) {
|
|
6509
7317
|
const inlines = previewInlines(block.field, islands, output, equationSide, document2, previewOptions);
|
|
7318
|
+
const metadata = block.metadata ? { metadata: { ...block.metadata } } : {};
|
|
6510
7319
|
if (block.command === "\\section") {
|
|
6511
|
-
return { kind: "heading", id: block.id, level: 1, inlines };
|
|
7320
|
+
return { kind: "heading", id: block.id, level: 1, inlines, ...metadata };
|
|
6512
7321
|
}
|
|
6513
7322
|
if (block.command === "\\subsection") {
|
|
6514
|
-
return { kind: "heading", id: block.id, level: 2, inlines };
|
|
7323
|
+
return { kind: "heading", id: block.id, level: 2, inlines, ...metadata };
|
|
6515
7324
|
}
|
|
6516
7325
|
if (block.command === "\\subsubsection") {
|
|
6517
|
-
return { kind: "heading", id: block.id, level: 3, inlines };
|
|
7326
|
+
return { kind: "heading", id: block.id, level: 3, inlines, ...metadata };
|
|
6518
7327
|
}
|
|
6519
7328
|
return {
|
|
6520
7329
|
kind: "paragraph",
|
|
6521
7330
|
id: block.id,
|
|
6522
7331
|
inlines,
|
|
7332
|
+
...metadata,
|
|
6523
7333
|
...block.centered ? { centered: true } : {}
|
|
6524
7334
|
};
|
|
6525
7335
|
}
|
|
@@ -6550,7 +7360,8 @@ function blockPreview(block, islands, output, equationSide, document2, previewOp
|
|
|
6550
7360
|
id: item.id,
|
|
6551
7361
|
inlines: previewInlines(item.field, islands, output, equationSide, document2, previewOptions),
|
|
6552
7362
|
blocks: item.blocks.map((child) => blockPreview(child, islands, output, equationSide, document2, previewOptions))
|
|
6553
|
-
}))
|
|
7363
|
+
})),
|
|
7364
|
+
...block.metadata ? { metadata: { ...block.metadata } } : {}
|
|
6554
7365
|
};
|
|
6555
7366
|
}
|
|
6556
7367
|
if (block.kind === "table") {
|
|
@@ -6560,7 +7371,8 @@ function blockPreview(block, islands, output, equationSide, document2, previewOp
|
|
|
6560
7371
|
id: block.id,
|
|
6561
7372
|
rows: block.rows.map((row) => row.map((cell) => previewInlines(cell, islands, output, equationSide, document2, previewOptions))),
|
|
6562
7373
|
...block.captionEnabled && block.caption.trim().length > 0 ? { caption: block.caption.trim() } : {},
|
|
6563
|
-
...label.length > 0 ? { label, numberLabel: floatNumberLabel(document2, label, previewOptions) } : {}
|
|
7374
|
+
...label.length > 0 ? { label, numberLabel: floatNumberLabel(document2, label, previewOptions) } : {},
|
|
7375
|
+
...block.metadata ? { metadata: { ...block.metadata } } : {}
|
|
6564
7376
|
};
|
|
6565
7377
|
}
|
|
6566
7378
|
if (block.kind === "image") {
|
|
@@ -6572,7 +7384,8 @@ function blockPreview(block, islands, output, equationSide, document2, previewOp
|
|
|
6572
7384
|
...block.assetId !== void 0 ? { assetId: block.assetId } : {},
|
|
6573
7385
|
options: block.options,
|
|
6574
7386
|
...block.captionEnabled && block.caption.trim().length > 0 ? { caption: block.caption.trim() } : {},
|
|
6575
|
-
...label.length > 0 ? { label, numberLabel: floatNumberLabel(document2, label, previewOptions) } : {}
|
|
7387
|
+
...label.length > 0 ? { label, numberLabel: floatNumberLabel(document2, label, previewOptions) } : {},
|
|
7388
|
+
...block.metadata ? { metadata: { ...block.metadata } } : {}
|
|
6576
7389
|
};
|
|
6577
7390
|
}
|
|
6578
7391
|
if (block.kind === "bibliography") {
|
|
@@ -6592,10 +7405,11 @@ function blockPreview(block, islands, output, equationSide, document2, previewOp
|
|
|
6592
7405
|
url: reference.url,
|
|
6593
7406
|
venue: reference.venue,
|
|
6594
7407
|
fieldSeparator: reference.fieldSeparator
|
|
6595
|
-
}))
|
|
7408
|
+
})),
|
|
7409
|
+
...block.metadata ? { metadata: { ...block.metadata } } : {}
|
|
6596
7410
|
};
|
|
6597
7411
|
}
|
|
6598
|
-
return { kind: "omit", id: block.id };
|
|
7412
|
+
return { kind: "omit", id: block.id, ...block.metadata ? { metadata: { ...block.metadata } } : {} };
|
|
6599
7413
|
}
|
|
6600
7414
|
function articleChromePreview(document2, uiLocale, previewOptions) {
|
|
6601
7415
|
const meta = document2.meta ?? emptyDocument2Meta();
|