@drghaliasri/butex 5.6.1 → 6.0.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 +49 -3
- package/dist/document2-cli.js +3346 -0
- package/dist/document2-cli.js.map +1 -0
- package/dist/document2.d.mts +55 -2
- package/dist/document2.d.ts +55 -2
- package/dist/document2.js +566 -190
- package/dist/document2.js.map +1 -1
- package/dist/document2.mjs +561 -190
- package/dist/document2.mjs.map +1 -1
- package/dist/react-document2.d.mts +32 -3
- package/dist/react-document2.d.ts +32 -3
- package/dist/react-document2.js +572 -199
- package/dist/react-document2.js.map +1 -1
- package/dist/react-document2.mjs +606 -233
- package/dist/react-document2.mjs.map +1 -1
- package/package.json +11 -1
package/dist/document2.js
CHANGED
|
@@ -28,6 +28,7 @@ __export(document2_exports, {
|
|
|
28
28
|
DEFAULT_DOCUMENT2_HISTORY_MAX_DEPTH: () => DEFAULT_DOCUMENT2_HISTORY_MAX_DEPTH,
|
|
29
29
|
DEFAULT_HIJRI_DATE: () => DEFAULT_HIJRI_DATE,
|
|
30
30
|
DEFAULT_REFERENCE_FIELD_SEPARATOR: () => DEFAULT_REFERENCE_FIELD_SEPARATOR,
|
|
31
|
+
Document2CommandError: () => Document2CommandError,
|
|
31
32
|
HIJRI_MONTH_IDS: () => HIJRI_MONTH_IDS,
|
|
32
33
|
HIJRI_YEAR_MAX: () => HIJRI_YEAR_MAX,
|
|
33
34
|
HIJRI_YEAR_MIN: () => HIJRI_YEAR_MIN,
|
|
@@ -38,6 +39,7 @@ __export(document2_exports, {
|
|
|
38
39
|
addDocument2Reference: () => addDocument2Reference,
|
|
39
40
|
addDocument2TableBlock: () => addDocument2TableBlock,
|
|
40
41
|
addDocument2TextBlock: () => addDocument2TextBlock,
|
|
42
|
+
applyDocument2Command: () => applyDocument2Command,
|
|
41
43
|
applyFloatMetaPatch: () => applyFloatMetaPatch,
|
|
42
44
|
arabicXeLatexPreambleCmd: () => arabicXeLatexPreambleCmd,
|
|
43
45
|
arabicXeLatexPreambleFont: () => arabicXeLatexPreambleFont,
|
|
@@ -53,6 +55,7 @@ __export(document2_exports, {
|
|
|
53
55
|
butexMaghribiDisplayLatex: () => butexMaghribiDisplayLatex,
|
|
54
56
|
butexMaghribiDisplayTex: () => butexMaghribiDisplayTex,
|
|
55
57
|
citeTokenLatex: () => citeTokenLatex,
|
|
58
|
+
clearDocument2ImageAsset: () => clearDocument2ImageAsset,
|
|
56
59
|
cloneDocument2Meta: () => cloneDocument2Meta,
|
|
57
60
|
cloneDocument2Node: () => cloneDocument2Node,
|
|
58
61
|
collectDocument2Labels: () => collectDocument2Labels,
|
|
@@ -72,6 +75,7 @@ __export(document2_exports, {
|
|
|
72
75
|
document2HistoryCanUndo: () => document2HistoryCanUndo,
|
|
73
76
|
document2KeyError: () => document2KeyError,
|
|
74
77
|
document2Latex: () => document2Latex,
|
|
78
|
+
document2Outline: () => document2Outline,
|
|
75
79
|
document2Preview: () => document2Preview,
|
|
76
80
|
emptyBlockSelection: () => emptyBlockSelection,
|
|
77
81
|
emptyDocument2Meta: () => emptyDocument2Meta,
|
|
@@ -138,6 +142,7 @@ __export(document2_exports, {
|
|
|
138
142
|
toggleBlockInSelection: () => toggleBlockInSelection,
|
|
139
143
|
toggleTextTokenStyle: () => toggleTextTokenStyle,
|
|
140
144
|
updateCiteTokenKeys: () => updateCiteTokenKeys,
|
|
145
|
+
updateDocument2ImageAsset: () => updateDocument2ImageAsset,
|
|
141
146
|
updateDocument2ImageMeta: () => updateDocument2ImageMeta,
|
|
142
147
|
updateDocument2ImageValue: () => updateDocument2ImageValue,
|
|
143
148
|
updateDocument2Meta: () => updateDocument2Meta,
|
|
@@ -152,8 +157,9 @@ module.exports = __toCommonJS(document2_exports);
|
|
|
152
157
|
|
|
153
158
|
// src/document2/ids.ts
|
|
154
159
|
var nextId = 1;
|
|
160
|
+
var instanceId = `${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
|
|
155
161
|
function document2Id(prefix) {
|
|
156
|
-
const id = `${prefix}_${String(nextId)}`;
|
|
162
|
+
const id = `${prefix}_${instanceId}_${String(nextId)}`;
|
|
157
163
|
nextId += 1;
|
|
158
164
|
return id;
|
|
159
165
|
}
|
|
@@ -1329,6 +1335,19 @@ function asBlockJson(value) {
|
|
|
1329
1335
|
}
|
|
1330
1336
|
return value;
|
|
1331
1337
|
}
|
|
1338
|
+
function blockIdFromJson(json, state) {
|
|
1339
|
+
const imported = typeof json.id === "string" ? json.id.trim() : "";
|
|
1340
|
+
if (imported.length > 0 && !state.used.has(imported)) {
|
|
1341
|
+
state.used.add(imported);
|
|
1342
|
+
return imported;
|
|
1343
|
+
}
|
|
1344
|
+
let generated = document2Id("block");
|
|
1345
|
+
while (state.used.has(generated)) {
|
|
1346
|
+
generated = document2Id("block");
|
|
1347
|
+
}
|
|
1348
|
+
state.used.add(generated);
|
|
1349
|
+
return generated;
|
|
1350
|
+
}
|
|
1332
1351
|
function pushDiagnostic(diagnostics, options, path, message) {
|
|
1333
1352
|
if (options.strict) {
|
|
1334
1353
|
throw new Error(message);
|
|
@@ -1510,40 +1529,44 @@ function pushFormattedTextTokens(tokens, text, sourceStart, formats) {
|
|
|
1510
1529
|
function closingForList(command) {
|
|
1511
1530
|
return command === "\\begin{itemize}" ? "\\end{itemize}" : "\\end{enumerate}";
|
|
1512
1531
|
}
|
|
1513
|
-
function parseTextBlock(json, options, path, diagnostics) {
|
|
1532
|
+
function parseTextBlock(json, options, path, diagnostics, blockIds) {
|
|
1514
1533
|
const value = requireString(json.value, `${json.command} requires string value`);
|
|
1515
1534
|
return {
|
|
1516
|
-
id:
|
|
1535
|
+
id: blockIdFromJson(json, blockIds),
|
|
1517
1536
|
kind: "textBlock",
|
|
1518
1537
|
command: json.command,
|
|
1519
1538
|
field: createInlineField2(value, json.math_objects ?? [], options, `${path}.value`, diagnostics, json.command === "\\paragraph" ? json.formats ?? [] : []),
|
|
1520
1539
|
...json.centered === true ? { centered: true } : {}
|
|
1521
1540
|
};
|
|
1522
1541
|
}
|
|
1523
|
-
function parseListItem(json, options, path, diagnostics) {
|
|
1542
|
+
function parseListItem(json, options, path, diagnostics, blockIds) {
|
|
1524
1543
|
const value = requireString(json.value, "Document list item requires string value");
|
|
1525
1544
|
const blocksJson = Array.isArray(json.blocks) ? json.blocks : [];
|
|
1526
1545
|
return {
|
|
1527
1546
|
id: document2Id("item"),
|
|
1528
1547
|
field: createInlineField2(value, json.math_objects ?? [], options, `${path}.value`, diagnostics, json.formats ?? []),
|
|
1529
|
-
blocks: blocksJson.map(
|
|
1548
|
+
blocks: blocksJson.map(
|
|
1549
|
+
(block, index) => parseBlock(asBlockJson(block), options, `${path}.blocks[${String(index)}]`, diagnostics, blockIds)
|
|
1550
|
+
)
|
|
1530
1551
|
};
|
|
1531
1552
|
}
|
|
1532
|
-
function parseListBlock(json, options, path, diagnostics) {
|
|
1553
|
+
function parseListBlock(json, options, path, diagnostics, blockIds) {
|
|
1533
1554
|
if (!Array.isArray(json.items)) {
|
|
1534
1555
|
throw new Error(`${json.command} requires items array`);
|
|
1535
1556
|
}
|
|
1536
1557
|
const command = json.command;
|
|
1537
1558
|
const closing = closingForList(command);
|
|
1538
1559
|
return {
|
|
1539
|
-
id:
|
|
1560
|
+
id: blockIdFromJson(json, blockIds),
|
|
1540
1561
|
kind: "list",
|
|
1541
1562
|
command,
|
|
1542
1563
|
closing,
|
|
1543
|
-
items: json.items.map(
|
|
1564
|
+
items: json.items.map(
|
|
1565
|
+
(item, index) => parseListItem(item, options, `${path}.items[${String(index)}]`, diagnostics, blockIds)
|
|
1566
|
+
)
|
|
1544
1567
|
};
|
|
1545
1568
|
}
|
|
1546
|
-
function parseTableBlock(json, options, path, diagnostics) {
|
|
1569
|
+
function parseTableBlock(json, options, path, diagnostics, blockIds) {
|
|
1547
1570
|
if (!Array.isArray(json.rows)) {
|
|
1548
1571
|
throw new Error("\\begin{tabular} requires rows array");
|
|
1549
1572
|
}
|
|
@@ -1566,7 +1589,7 @@ function parseTableBlock(json, options, path, diagnostics) {
|
|
|
1566
1589
|
pushDiagnostic(diagnostics, options, path, `math_objects count mismatch: detected ${String(mathObjectIndex)}, got ${String(mathObjects.length)}`);
|
|
1567
1590
|
}
|
|
1568
1591
|
return {
|
|
1569
|
-
id:
|
|
1592
|
+
id: blockIdFromJson(json, blockIds),
|
|
1570
1593
|
kind: "table",
|
|
1571
1594
|
command: "\\begin{tabular}",
|
|
1572
1595
|
closing: "\\end{tabular}",
|
|
@@ -1575,11 +1598,11 @@ function parseTableBlock(json, options, path, diagnostics) {
|
|
|
1575
1598
|
...parseFloatMetaFromJson(json)
|
|
1576
1599
|
};
|
|
1577
1600
|
}
|
|
1578
|
-
function parseImageBlock(json) {
|
|
1601
|
+
function parseImageBlock(json, blockIds) {
|
|
1579
1602
|
const assetId = typeof json.asset_id === "string" && json.asset_id.length > 0 ? json.asset_id : void 0;
|
|
1580
1603
|
const value = assetId !== void 0 ? typeof json.value === "string" ? json.value : "" : requireString(json.value, "\\includegraphics requires string value");
|
|
1581
1604
|
return {
|
|
1582
|
-
id:
|
|
1605
|
+
id: blockIdFromJson(json, blockIds),
|
|
1583
1606
|
kind: "image",
|
|
1584
1607
|
command: "\\includegraphics",
|
|
1585
1608
|
value,
|
|
@@ -1588,43 +1611,43 @@ function parseImageBlock(json) {
|
|
|
1588
1611
|
...parseFloatMetaFromJson(json)
|
|
1589
1612
|
};
|
|
1590
1613
|
}
|
|
1591
|
-
function parseRawBlock(json) {
|
|
1614
|
+
function parseRawBlock(json, blockIds) {
|
|
1592
1615
|
return {
|
|
1593
|
-
id:
|
|
1616
|
+
id: blockIdFromJson(json, blockIds),
|
|
1594
1617
|
kind: "raw",
|
|
1595
1618
|
command: "\\raw",
|
|
1596
1619
|
value: typeof json.value === "string" ? json.value : ""
|
|
1597
1620
|
};
|
|
1598
1621
|
}
|
|
1599
|
-
function parseBibliographyBlock() {
|
|
1622
|
+
function parseBibliographyBlock(json, blockIds) {
|
|
1600
1623
|
return {
|
|
1601
|
-
id:
|
|
1624
|
+
id: blockIdFromJson(json, blockIds),
|
|
1602
1625
|
kind: "bibliography",
|
|
1603
1626
|
command: "\\begin{thebibliography}",
|
|
1604
1627
|
closing: "\\end{thebibliography}"
|
|
1605
1628
|
};
|
|
1606
1629
|
}
|
|
1607
|
-
function parseBlock(json, options, path, diagnostics) {
|
|
1630
|
+
function parseBlock(json, options, path, diagnostics, blockIds) {
|
|
1608
1631
|
if (TEXT_COMMANDS.has(json.command)) {
|
|
1609
|
-
return parseTextBlock(json, options, path, diagnostics);
|
|
1632
|
+
return parseTextBlock(json, options, path, diagnostics, blockIds);
|
|
1610
1633
|
}
|
|
1611
1634
|
if (LIST_COMMANDS.has(json.command)) {
|
|
1612
|
-
return parseListBlock(json, options, path, diagnostics);
|
|
1635
|
+
return parseListBlock(json, options, path, diagnostics, blockIds);
|
|
1613
1636
|
}
|
|
1614
1637
|
if (json.command === "\\begin{tabular}") {
|
|
1615
|
-
return parseTableBlock(json, options, path, diagnostics);
|
|
1638
|
+
return parseTableBlock(json, options, path, diagnostics, blockIds);
|
|
1616
1639
|
}
|
|
1617
1640
|
if (json.command === "\\includegraphics") {
|
|
1618
|
-
return parseImageBlock(json);
|
|
1641
|
+
return parseImageBlock(json, blockIds);
|
|
1619
1642
|
}
|
|
1620
1643
|
if (json.command === "\\begin{thebibliography}" || json.command === "\\bibliography") {
|
|
1621
|
-
return parseBibliographyBlock();
|
|
1644
|
+
return parseBibliographyBlock(json, blockIds);
|
|
1622
1645
|
}
|
|
1623
1646
|
if (json.command === "\\raw") {
|
|
1624
|
-
return parseRawBlock(json);
|
|
1647
|
+
return parseRawBlock(json, blockIds);
|
|
1625
1648
|
}
|
|
1626
1649
|
return {
|
|
1627
|
-
id:
|
|
1650
|
+
id: blockIdFromJson(json, blockIds),
|
|
1628
1651
|
kind: "raw",
|
|
1629
1652
|
command: "\\raw",
|
|
1630
1653
|
value: typeof json.value === "string" ? json.value : json.command
|
|
@@ -1638,11 +1661,14 @@ function fromDocumentJson2(json, options = {}) {
|
|
|
1638
1661
|
throw new Error("DocumentObject requires blocks array");
|
|
1639
1662
|
}
|
|
1640
1663
|
const diagnostics = [];
|
|
1664
|
+
const blockIds = { used: /* @__PURE__ */ new Set() };
|
|
1641
1665
|
return {
|
|
1642
1666
|
nodeType: "DocumentObject",
|
|
1643
1667
|
meta: normalizeDocument2Meta(json.meta),
|
|
1644
1668
|
references: parseReferences(json.references),
|
|
1645
|
-
blocks: json.blocks.map(
|
|
1669
|
+
blocks: json.blocks.map(
|
|
1670
|
+
(block, index) => parseBlock(asBlockJson(block), options, `$.blocks[${String(index)}]`, diagnostics, blockIds)
|
|
1671
|
+
),
|
|
1646
1672
|
diagnostics
|
|
1647
1673
|
};
|
|
1648
1674
|
}
|
|
@@ -4726,21 +4752,21 @@ function splitTextForInsertion(token) {
|
|
|
4726
4752
|
function cloneDocument2Node(document2) {
|
|
4727
4753
|
return cloneDocument(document2);
|
|
4728
4754
|
}
|
|
4729
|
-
function insertBlockAfter(blocks,
|
|
4730
|
-
if (!
|
|
4755
|
+
function insertBlockAfter(blocks, afterBlockId2, block) {
|
|
4756
|
+
if (!afterBlockId2) {
|
|
4731
4757
|
blocks.push(block);
|
|
4732
4758
|
return;
|
|
4733
4759
|
}
|
|
4734
|
-
const index = blocks.findIndex((entry) => entry.id ===
|
|
4760
|
+
const index = blocks.findIndex((entry) => entry.id === afterBlockId2);
|
|
4735
4761
|
if (index < 0) {
|
|
4736
4762
|
blocks.push(block);
|
|
4737
4763
|
return;
|
|
4738
4764
|
}
|
|
4739
4765
|
blocks.splice(index + 1, 0, block);
|
|
4740
4766
|
}
|
|
4741
|
-
function insertDocument2BlockAfter(document2,
|
|
4767
|
+
function insertDocument2BlockAfter(document2, afterBlockId2, block) {
|
|
4742
4768
|
const next = cloneDocument(document2);
|
|
4743
|
-
insertBlockAfter(next.blocks,
|
|
4769
|
+
insertBlockAfter(next.blocks, afterBlockId2, block);
|
|
4744
4770
|
return next;
|
|
4745
4771
|
}
|
|
4746
4772
|
function moveDocument2BlockById(document2, blockId, direction) {
|
|
@@ -4960,7 +4986,7 @@ function replaceMathTokenFromSession(document2, tokenId, session, opening, closi
|
|
|
4960
4986
|
});
|
|
4961
4987
|
return next;
|
|
4962
4988
|
}
|
|
4963
|
-
function addDocument2TextBlock(document2, command = "\\paragraph",
|
|
4989
|
+
function addDocument2TextBlock(document2, command = "\\paragraph", afterBlockId2) {
|
|
4964
4990
|
const block = {
|
|
4965
4991
|
id: document2Id("block"),
|
|
4966
4992
|
kind: "textBlock",
|
|
@@ -4968,7 +4994,7 @@ function addDocument2TextBlock(document2, command = "\\paragraph", afterBlockId)
|
|
|
4968
4994
|
field: createInlineField2(""),
|
|
4969
4995
|
...command === "\\paragraph" ? { centered: false } : {}
|
|
4970
4996
|
};
|
|
4971
|
-
return insertDocument2BlockAfter(document2,
|
|
4997
|
+
return insertDocument2BlockAfter(document2, afterBlockId2, block);
|
|
4972
4998
|
}
|
|
4973
4999
|
function updateDocument2TextBlockCentered(document2, blockId, centered) {
|
|
4974
5000
|
const next = cloneDocument(document2);
|
|
@@ -5007,10 +5033,10 @@ function newListBlock(ordered) {
|
|
|
5007
5033
|
items: [{ id: document2Id("item"), field: createInlineField2(""), blocks: [] }]
|
|
5008
5034
|
};
|
|
5009
5035
|
}
|
|
5010
|
-
function addDocument2ListBlock(document2, ordered,
|
|
5011
|
-
return insertDocument2BlockAfter(document2,
|
|
5036
|
+
function addDocument2ListBlock(document2, ordered, afterBlockId2) {
|
|
5037
|
+
return insertDocument2BlockAfter(document2, afterBlockId2, newListBlock(ordered));
|
|
5012
5038
|
}
|
|
5013
|
-
function addDocument2TableBlock(document2, columns = "lll", rowCount = 3, colCount = 3,
|
|
5039
|
+
function addDocument2TableBlock(document2, columns = "lll", rowCount = 3, colCount = 3, afterBlockId2) {
|
|
5014
5040
|
const rows = Math.max(1, rowCount);
|
|
5015
5041
|
const cols = Math.max(1, colCount);
|
|
5016
5042
|
const tableRows = [];
|
|
@@ -5030,18 +5056,29 @@ function addDocument2TableBlock(document2, columns = "lll", rowCount = 3, colCou
|
|
|
5030
5056
|
rows: tableRows,
|
|
5031
5057
|
...defaultFloatMeta()
|
|
5032
5058
|
};
|
|
5033
|
-
return insertDocument2BlockAfter(document2,
|
|
5059
|
+
return insertDocument2BlockAfter(document2, afterBlockId2, block);
|
|
5060
|
+
}
|
|
5061
|
+
function normalizeImageInput(srcOrAsset) {
|
|
5062
|
+
if (typeof srcOrAsset === "string") {
|
|
5063
|
+
return srcOrAsset.length > 0 ? { value: srcOrAsset, assetId: srcOrAsset } : { value: "" };
|
|
5064
|
+
}
|
|
5065
|
+
if (srcOrAsset && srcOrAsset.assetId.length > 0) {
|
|
5066
|
+
return { value: srcOrAsset.value ?? srcOrAsset.assetId, assetId: srcOrAsset.assetId };
|
|
5067
|
+
}
|
|
5068
|
+
return { value: "" };
|
|
5034
5069
|
}
|
|
5035
|
-
function addDocument2ImageBlock(document2,
|
|
5070
|
+
function addDocument2ImageBlock(document2, srcOrAsset, afterBlockId2) {
|
|
5071
|
+
const image = normalizeImageInput(srcOrAsset);
|
|
5036
5072
|
const block = {
|
|
5037
5073
|
id: document2Id("block"),
|
|
5038
5074
|
kind: "image",
|
|
5039
5075
|
command: "\\includegraphics",
|
|
5040
|
-
value:
|
|
5076
|
+
value: image.value,
|
|
5077
|
+
...image.assetId !== void 0 ? { assetId: image.assetId } : {},
|
|
5041
5078
|
options: { width: "0.8\\columnwidth" },
|
|
5042
5079
|
...defaultFloatMeta()
|
|
5043
5080
|
};
|
|
5044
|
-
return insertDocument2BlockAfter(document2,
|
|
5081
|
+
return insertDocument2BlockAfter(document2, afterBlockId2, block);
|
|
5045
5082
|
}
|
|
5046
5083
|
function updateDocument2ImageValue(document2, blockId, value) {
|
|
5047
5084
|
const next = cloneDocument(document2);
|
|
@@ -5064,6 +5101,55 @@ function updateDocument2ImageValue(document2, blockId, value) {
|
|
|
5064
5101
|
visit(next.blocks);
|
|
5065
5102
|
return next;
|
|
5066
5103
|
}
|
|
5104
|
+
function updateDocument2ImageAsset(document2, blockId, asset) {
|
|
5105
|
+
const next = cloneDocument(document2);
|
|
5106
|
+
const image = normalizeImageInput(asset);
|
|
5107
|
+
function visit(blocks) {
|
|
5108
|
+
for (const block of blocks) {
|
|
5109
|
+
if (block.id === blockId && block.kind === "image") {
|
|
5110
|
+
block.value = image.value;
|
|
5111
|
+
if (image.assetId !== void 0) {
|
|
5112
|
+
block.assetId = image.assetId;
|
|
5113
|
+
} else {
|
|
5114
|
+
delete block.assetId;
|
|
5115
|
+
}
|
|
5116
|
+
return true;
|
|
5117
|
+
}
|
|
5118
|
+
if (block.kind === "list") {
|
|
5119
|
+
for (const item of block.items) {
|
|
5120
|
+
if (visit(item.blocks)) {
|
|
5121
|
+
return true;
|
|
5122
|
+
}
|
|
5123
|
+
}
|
|
5124
|
+
}
|
|
5125
|
+
}
|
|
5126
|
+
return false;
|
|
5127
|
+
}
|
|
5128
|
+
visit(next.blocks);
|
|
5129
|
+
return next;
|
|
5130
|
+
}
|
|
5131
|
+
function clearDocument2ImageAsset(document2, blockId) {
|
|
5132
|
+
const next = cloneDocument(document2);
|
|
5133
|
+
function visit(blocks) {
|
|
5134
|
+
for (const block of blocks) {
|
|
5135
|
+
if (block.id === blockId && block.kind === "image") {
|
|
5136
|
+
block.value = "";
|
|
5137
|
+
delete block.assetId;
|
|
5138
|
+
return true;
|
|
5139
|
+
}
|
|
5140
|
+
if (block.kind === "list") {
|
|
5141
|
+
for (const item of block.items) {
|
|
5142
|
+
if (visit(item.blocks)) {
|
|
5143
|
+
return true;
|
|
5144
|
+
}
|
|
5145
|
+
}
|
|
5146
|
+
}
|
|
5147
|
+
}
|
|
5148
|
+
return false;
|
|
5149
|
+
}
|
|
5150
|
+
visit(next.blocks);
|
|
5151
|
+
return next;
|
|
5152
|
+
}
|
|
5067
5153
|
function updateDocument2ImageMeta(document2, blockId, patch) {
|
|
5068
5154
|
const next = cloneDocument(document2);
|
|
5069
5155
|
function visit(blocks) {
|
|
@@ -5282,7 +5368,7 @@ function removeCiteTokenById(document2, tokenId) {
|
|
|
5282
5368
|
});
|
|
5283
5369
|
return next;
|
|
5284
5370
|
}
|
|
5285
|
-
function ensureDocument2BibliographyBlock(document2,
|
|
5371
|
+
function ensureDocument2BibliographyBlock(document2, afterBlockId2) {
|
|
5286
5372
|
if (document2.blocks.some((block2) => block2.kind === "bibliography")) {
|
|
5287
5373
|
return document2;
|
|
5288
5374
|
}
|
|
@@ -5292,7 +5378,7 @@ function ensureDocument2BibliographyBlock(document2, afterBlockId) {
|
|
|
5292
5378
|
command: "\\begin{thebibliography}",
|
|
5293
5379
|
closing: "\\end{thebibliography}"
|
|
5294
5380
|
};
|
|
5295
|
-
return insertDocument2BlockAfter(document2,
|
|
5381
|
+
return insertDocument2BlockAfter(document2, afterBlockId2 ?? null, block);
|
|
5296
5382
|
}
|
|
5297
5383
|
function addDocument2Reference(document2, partial = {}) {
|
|
5298
5384
|
const next = cloneDocument(document2);
|
|
@@ -5364,6 +5450,440 @@ function updateDocument2Meta(document2, patch) {
|
|
|
5364
5450
|
return next;
|
|
5365
5451
|
}
|
|
5366
5452
|
|
|
5453
|
+
// src/document2/exportJson.ts
|
|
5454
|
+
function serializeField(field) {
|
|
5455
|
+
let value = "";
|
|
5456
|
+
let hasPersistedMath = false;
|
|
5457
|
+
const formats = [];
|
|
5458
|
+
const mathObjects = [];
|
|
5459
|
+
for (const token of field.tokens) {
|
|
5460
|
+
if (token.kind === "text") {
|
|
5461
|
+
const start = value.length;
|
|
5462
|
+
value += token.text;
|
|
5463
|
+
if (token.text.length > 0 && (token.style?.bold || token.style?.italic || token.style?.underline)) {
|
|
5464
|
+
formats.push({
|
|
5465
|
+
start,
|
|
5466
|
+
end: value.length,
|
|
5467
|
+
...token.style.bold ? { bold: true } : {},
|
|
5468
|
+
...token.style.italic ? { italic: true } : {},
|
|
5469
|
+
...token.style.underline ? { underline: true } : {}
|
|
5470
|
+
});
|
|
5471
|
+
}
|
|
5472
|
+
continue;
|
|
5473
|
+
}
|
|
5474
|
+
if (token.kind === "cite") {
|
|
5475
|
+
value += citeTokenLatex(token.keys);
|
|
5476
|
+
continue;
|
|
5477
|
+
}
|
|
5478
|
+
if (token.kind === "ref") {
|
|
5479
|
+
value += refTokenLatex(token.keys, token.refCommand);
|
|
5480
|
+
continue;
|
|
5481
|
+
}
|
|
5482
|
+
value += token.source;
|
|
5483
|
+
if (!token.math || token.sourceOwner === "raw") {
|
|
5484
|
+
if (token.labelEnabled !== void 0 || token.label !== void 0) {
|
|
5485
|
+
hasPersistedMath = true;
|
|
5486
|
+
mathObjects.push({
|
|
5487
|
+
node_type: "RawMathObject",
|
|
5488
|
+
...token.labelEnabled !== void 0 ? { label_enabled: token.labelEnabled } : {},
|
|
5489
|
+
...token.label !== void 0 ? { label: token.label } : {}
|
|
5490
|
+
});
|
|
5491
|
+
} else {
|
|
5492
|
+
mathObjects.push(null);
|
|
5493
|
+
}
|
|
5494
|
+
continue;
|
|
5495
|
+
}
|
|
5496
|
+
hasPersistedMath = true;
|
|
5497
|
+
mathObjects.push({
|
|
5498
|
+
...toMathObjectJson(token.math),
|
|
5499
|
+
...token.sourceSide ? { source_side: token.sourceSide } : {},
|
|
5500
|
+
source_owner: token.sourceOwner,
|
|
5501
|
+
...token.labelEnabled !== void 0 ? { label_enabled: token.labelEnabled } : {},
|
|
5502
|
+
...token.label !== void 0 ? { label: token.label } : {}
|
|
5503
|
+
});
|
|
5504
|
+
}
|
|
5505
|
+
return { value, formats, mathObjects, hasPersistedMath };
|
|
5506
|
+
}
|
|
5507
|
+
function fieldJson(field) {
|
|
5508
|
+
const serialized = serializeField(field);
|
|
5509
|
+
return {
|
|
5510
|
+
value: serialized.value,
|
|
5511
|
+
...serialized.formats.length > 0 ? { formats: serialized.formats } : {},
|
|
5512
|
+
...serialized.hasPersistedMath ? { math_objects: serialized.mathObjects } : {}
|
|
5513
|
+
};
|
|
5514
|
+
}
|
|
5515
|
+
function listItemJson(item) {
|
|
5516
|
+
const field = fieldJson(item.field);
|
|
5517
|
+
return {
|
|
5518
|
+
value: field.value ?? "",
|
|
5519
|
+
...field.formats ? { formats: field.formats } : {},
|
|
5520
|
+
...field.math_objects ? { math_objects: field.math_objects } : {},
|
|
5521
|
+
...item.blocks.length > 0 ? { blocks: item.blocks.map(blockJson) } : {}
|
|
5522
|
+
};
|
|
5523
|
+
}
|
|
5524
|
+
function blockJson(block) {
|
|
5525
|
+
if (block.kind === "textBlock") {
|
|
5526
|
+
return {
|
|
5527
|
+
id: block.id,
|
|
5528
|
+
command: block.command,
|
|
5529
|
+
...fieldJson(block.field),
|
|
5530
|
+
...block.command === "\\paragraph" ? { centered: block.centered === true } : {}
|
|
5531
|
+
};
|
|
5532
|
+
}
|
|
5533
|
+
if (block.kind === "list") {
|
|
5534
|
+
return {
|
|
5535
|
+
id: block.id,
|
|
5536
|
+
command: block.command,
|
|
5537
|
+
closing: block.closing,
|
|
5538
|
+
items: block.items.map(listItemJson)
|
|
5539
|
+
};
|
|
5540
|
+
}
|
|
5541
|
+
if (block.kind === "table") {
|
|
5542
|
+
const fields = block.rows.map((row) => row.map(serializeField));
|
|
5543
|
+
const hasPersistedMath = fields.some((row) => row.some((field) => field.hasPersistedMath));
|
|
5544
|
+
return {
|
|
5545
|
+
id: block.id,
|
|
5546
|
+
command: block.command,
|
|
5547
|
+
closing: block.closing,
|
|
5548
|
+
columns: block.columns,
|
|
5549
|
+
rows: fields.map((row) => row.map((field) => field.value)),
|
|
5550
|
+
...fields.some((row) => row.some((field) => field.formats.length > 0)) ? { cell_formats: fields.map((row) => row.map((field) => field.formats)) } : {},
|
|
5551
|
+
...hasPersistedMath ? { math_objects: fields.flatMap((row) => row.flatMap((field) => field.mathObjects)) } : {},
|
|
5552
|
+
centered: block.centered,
|
|
5553
|
+
caption_enabled: block.captionEnabled,
|
|
5554
|
+
caption: block.caption,
|
|
5555
|
+
label_enabled: block.labelEnabled,
|
|
5556
|
+
label: block.label
|
|
5557
|
+
};
|
|
5558
|
+
}
|
|
5559
|
+
if (block.kind === "image") {
|
|
5560
|
+
return {
|
|
5561
|
+
id: block.id,
|
|
5562
|
+
command: block.command,
|
|
5563
|
+
value: block.value,
|
|
5564
|
+
...block.assetId !== void 0 ? { asset_id: block.assetId } : {},
|
|
5565
|
+
options: { ...block.options },
|
|
5566
|
+
centered: block.centered,
|
|
5567
|
+
caption_enabled: block.captionEnabled,
|
|
5568
|
+
caption: block.caption,
|
|
5569
|
+
label_enabled: block.labelEnabled,
|
|
5570
|
+
label: block.label
|
|
5571
|
+
};
|
|
5572
|
+
}
|
|
5573
|
+
if (block.kind === "bibliography") {
|
|
5574
|
+
return { id: block.id, command: block.command, closing: block.closing };
|
|
5575
|
+
}
|
|
5576
|
+
return { id: block.id, command: block.command, value: block.value };
|
|
5577
|
+
}
|
|
5578
|
+
function referenceJson(reference) {
|
|
5579
|
+
return {
|
|
5580
|
+
key: reference.key,
|
|
5581
|
+
authors: reference.authors,
|
|
5582
|
+
title: reference.title,
|
|
5583
|
+
year: reference.year,
|
|
5584
|
+
url: reference.url,
|
|
5585
|
+
venue: reference.venue,
|
|
5586
|
+
field_separator: reference.fieldSeparator
|
|
5587
|
+
};
|
|
5588
|
+
}
|
|
5589
|
+
function toDocumentJson2(document2) {
|
|
5590
|
+
if (document2.nodeType !== "DocumentObject" || !Array.isArray(document2.blocks)) {
|
|
5591
|
+
throw new Error("toDocumentJson2 requires a live Document2Node");
|
|
5592
|
+
}
|
|
5593
|
+
return {
|
|
5594
|
+
node_type: "DocumentObject",
|
|
5595
|
+
meta: {
|
|
5596
|
+
title: document2.meta.title,
|
|
5597
|
+
authors: document2.meta.authors,
|
|
5598
|
+
date: { ...document2.meta.date },
|
|
5599
|
+
abstract: document2.meta.abstract
|
|
5600
|
+
},
|
|
5601
|
+
references: document2.references.map(referenceJson),
|
|
5602
|
+
blocks: document2.blocks.map(blockJson)
|
|
5603
|
+
};
|
|
5604
|
+
}
|
|
5605
|
+
|
|
5606
|
+
// src/document2/jsonCommands.ts
|
|
5607
|
+
var Document2CommandError = class extends Error {
|
|
5608
|
+
code;
|
|
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);
|
|
5617
|
+
}
|
|
5618
|
+
function requireString2(value, field, allowEmpty = true) {
|
|
5619
|
+
if (typeof value !== "string" || !allowEmpty && value.trim().length === 0) {
|
|
5620
|
+
throw new Document2CommandError("invalid_command", `${field} must be a${allowEmpty ? "" : " non-empty"} string`);
|
|
5621
|
+
}
|
|
5622
|
+
return value;
|
|
5623
|
+
}
|
|
5624
|
+
function parseAnchor(value) {
|
|
5625
|
+
if (!isObject3(value)) {
|
|
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];
|
|
5650
|
+
}
|
|
5651
|
+
function parseTextBlockKind(value) {
|
|
5652
|
+
if (value === "section" || value === "subsection" || value === "subsubsection" || value === "paragraph") {
|
|
5653
|
+
return value;
|
|
5654
|
+
}
|
|
5655
|
+
throw new Document2CommandError("invalid_command", "kind must be section, subsection, subsubsection, or paragraph");
|
|
5656
|
+
}
|
|
5657
|
+
function parseCommand2(value) {
|
|
5658
|
+
if (!isObject3(value) || typeof value.op !== "string") {
|
|
5659
|
+
throw new Document2CommandError("invalid_command", "command requires an op");
|
|
5660
|
+
}
|
|
5661
|
+
if (value.op === "insert_text_block") {
|
|
5662
|
+
return {
|
|
5663
|
+
op: value.op,
|
|
5664
|
+
kind: parseTextBlockKind(value.kind),
|
|
5665
|
+
text: requireString2(value.text, "text"),
|
|
5666
|
+
anchor: parseAnchor(value.anchor)
|
|
5667
|
+
};
|
|
5668
|
+
}
|
|
5669
|
+
if (value.op === "replace_text_block") {
|
|
5670
|
+
return {
|
|
5671
|
+
op: value.op,
|
|
5672
|
+
block_id: requireString2(value.block_id, "block_id", false).trim(),
|
|
5673
|
+
text: requireString2(value.text, "text")
|
|
5674
|
+
};
|
|
5675
|
+
}
|
|
5676
|
+
if (value.op === "remove_block") {
|
|
5677
|
+
return {
|
|
5678
|
+
op: value.op,
|
|
5679
|
+
block_id: requireString2(value.block_id, "block_id", false).trim()
|
|
5680
|
+
};
|
|
5681
|
+
}
|
|
5682
|
+
if (value.op === "insert_figure") {
|
|
5683
|
+
const figureValue = optionalString(value, "value");
|
|
5684
|
+
const caption = optionalString(value, "caption");
|
|
5685
|
+
const label = optionalString(value, "label");
|
|
5686
|
+
return {
|
|
5687
|
+
op: value.op,
|
|
5688
|
+
asset_id: requireString2(value.asset_id, "asset_id", false).trim(),
|
|
5689
|
+
...figureValue !== void 0 ? { value: figureValue } : {},
|
|
5690
|
+
...caption !== void 0 ? { caption } : {},
|
|
5691
|
+
...label !== void 0 ? { label } : {},
|
|
5692
|
+
anchor: parseAnchor(value.anchor)
|
|
5693
|
+
};
|
|
5694
|
+
}
|
|
5695
|
+
throw new Document2CommandError("invalid_command", `Unsupported document command: ${value.op}`);
|
|
5696
|
+
}
|
|
5697
|
+
function parseDocument(json) {
|
|
5698
|
+
try {
|
|
5699
|
+
return fromDocumentJson2(json);
|
|
5700
|
+
} catch (error) {
|
|
5701
|
+
const message = error instanceof Error ? error.message : "Invalid DocumentObject JSON";
|
|
5702
|
+
throw new Document2CommandError("invalid_document", message);
|
|
5703
|
+
}
|
|
5704
|
+
}
|
|
5705
|
+
function commandForKind(kind) {
|
|
5706
|
+
if (kind === "section") {
|
|
5707
|
+
return "\\section";
|
|
5708
|
+
}
|
|
5709
|
+
if (kind === "subsection") {
|
|
5710
|
+
return "\\subsection";
|
|
5711
|
+
}
|
|
5712
|
+
if (kind === "subsubsection") {
|
|
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;
|
|
5729
|
+
}
|
|
5730
|
+
function insertedBlock(document2, index) {
|
|
5731
|
+
const block = document2.blocks[index];
|
|
5732
|
+
if (!block) {
|
|
5733
|
+
throw new Document2CommandError("invalid_command", "Document command did not insert a block");
|
|
5734
|
+
}
|
|
5735
|
+
return block;
|
|
5736
|
+
}
|
|
5737
|
+
function insertTextBlock(document2, command) {
|
|
5738
|
+
const index = insertionIndex(document2, command.anchor);
|
|
5739
|
+
const next = addDocument2TextBlock(document2, commandForKind(command.kind), afterBlockId(document2, index));
|
|
5740
|
+
const block = insertedBlock(next, index);
|
|
5741
|
+
if (block.kind !== "textBlock") {
|
|
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");
|
|
5786
|
+
}
|
|
5787
|
+
if (command.caption !== void 0) {
|
|
5788
|
+
block.caption = command.caption;
|
|
5789
|
+
block.captionEnabled = command.caption.trim().length > 0;
|
|
5790
|
+
}
|
|
5791
|
+
if (command.label !== void 0) {
|
|
5792
|
+
block.label = command.label;
|
|
5793
|
+
block.labelEnabled = command.label.trim().length > 0;
|
|
5794
|
+
}
|
|
5795
|
+
return next;
|
|
5796
|
+
}
|
|
5797
|
+
function applyDocument2Command(json, commandInput) {
|
|
5798
|
+
const document2 = parseDocument(json);
|
|
5799
|
+
const command = parseCommand2(commandInput);
|
|
5800
|
+
let next;
|
|
5801
|
+
if (command.op === "insert_text_block") {
|
|
5802
|
+
next = insertTextBlock(document2, command);
|
|
5803
|
+
} else if (command.op === "replace_text_block") {
|
|
5804
|
+
next = replaceTextBlock(document2, command);
|
|
5805
|
+
} else if (command.op === "remove_block") {
|
|
5806
|
+
next = removeBlock(document2, command);
|
|
5807
|
+
} else {
|
|
5808
|
+
next = insertFigure(document2, command);
|
|
5809
|
+
}
|
|
5810
|
+
return toDocumentJson2(next);
|
|
5811
|
+
}
|
|
5812
|
+
|
|
5813
|
+
// src/document2/outline.ts
|
|
5814
|
+
var EXCERPT_LIMIT = 160;
|
|
5815
|
+
function normalizeExcerpt(value) {
|
|
5816
|
+
const normalized = value.replace(/\s+/g, " ").trim();
|
|
5817
|
+
if (normalized.length <= EXCERPT_LIMIT) {
|
|
5818
|
+
return normalized;
|
|
5819
|
+
}
|
|
5820
|
+
return `${normalized.slice(0, EXCERPT_LIMIT - 3)}...`;
|
|
5821
|
+
}
|
|
5822
|
+
function outlineKind(command) {
|
|
5823
|
+
if (command === "\\section") {
|
|
5824
|
+
return "section";
|
|
5825
|
+
}
|
|
5826
|
+
if (command === "\\subsection") {
|
|
5827
|
+
return "subsection";
|
|
5828
|
+
}
|
|
5829
|
+
if (command === "\\subsubsection") {
|
|
5830
|
+
return "subsubsection";
|
|
5831
|
+
}
|
|
5832
|
+
if (command === "\\paragraph") {
|
|
5833
|
+
return "paragraph";
|
|
5834
|
+
}
|
|
5835
|
+
if (command === "\\begin{itemize}" || command === "\\begin{enumerate}") {
|
|
5836
|
+
return "list";
|
|
5837
|
+
}
|
|
5838
|
+
if (command === "\\begin{tabular}") {
|
|
5839
|
+
return "table";
|
|
5840
|
+
}
|
|
5841
|
+
if (command === "\\includegraphics") {
|
|
5842
|
+
return "figure";
|
|
5843
|
+
}
|
|
5844
|
+
if (command === "\\begin{thebibliography}" || command === "\\bibliography") {
|
|
5845
|
+
return "bibliography";
|
|
5846
|
+
}
|
|
5847
|
+
return "raw";
|
|
5848
|
+
}
|
|
5849
|
+
function blockExcerpt(block) {
|
|
5850
|
+
if (block.command === "\\begin{itemize}" || block.command === "\\begin{enumerate}") {
|
|
5851
|
+
return normalizeExcerpt((block.items ?? []).map((item) => item.value).join(" "));
|
|
5852
|
+
}
|
|
5853
|
+
if (block.command === "\\begin{tabular}") {
|
|
5854
|
+
return normalizeExcerpt((block.rows ?? []).flat().join(" "));
|
|
5855
|
+
}
|
|
5856
|
+
if (block.command === "\\includegraphics") {
|
|
5857
|
+
return normalizeExcerpt(block.caption || block.asset_id || block.value || "");
|
|
5858
|
+
}
|
|
5859
|
+
return normalizeExcerpt(block.value ?? "");
|
|
5860
|
+
}
|
|
5861
|
+
function document2Outline(json) {
|
|
5862
|
+
if (!json || json.node_type !== "DocumentObject" || !Array.isArray(json.blocks)) {
|
|
5863
|
+
throw new Document2CommandError("invalid_document", "DocumentObject requires a blocks array");
|
|
5864
|
+
}
|
|
5865
|
+
const usedIds = /* @__PURE__ */ new Set();
|
|
5866
|
+
return json.blocks.map((block) => {
|
|
5867
|
+
if (!block || typeof block !== "object" || typeof block.command !== "string") {
|
|
5868
|
+
throw new Document2CommandError("invalid_document", "Document outline requires blocks with string commands");
|
|
5869
|
+
}
|
|
5870
|
+
const id = typeof block.id === "string" ? block.id.trim() : "";
|
|
5871
|
+
if (id.length === 0) {
|
|
5872
|
+
throw new Document2CommandError("missing_block_id", "Document outline requires canonical block IDs");
|
|
5873
|
+
}
|
|
5874
|
+
if (usedIds.has(id)) {
|
|
5875
|
+
throw new Document2CommandError("duplicate_block_id", `Duplicate document block ID: ${id}`);
|
|
5876
|
+
}
|
|
5877
|
+
usedIds.add(id);
|
|
5878
|
+
return {
|
|
5879
|
+
id,
|
|
5880
|
+
kind: outlineKind(block.command),
|
|
5881
|
+
command: block.command,
|
|
5882
|
+
excerpt: blockExcerpt(block)
|
|
5883
|
+
};
|
|
5884
|
+
});
|
|
5885
|
+
}
|
|
5886
|
+
|
|
5367
5887
|
// src/document2/keys.ts
|
|
5368
5888
|
var DOCUMENT2_KEY_PATTERN = /^[\p{L}\p{M}0-9:._-]+$/u;
|
|
5369
5889
|
function normalizeDocument2Key(key) {
|
|
@@ -5848,155 +6368,6 @@ ${body}
|
|
|
5848
6368
|
`;
|
|
5849
6369
|
}
|
|
5850
6370
|
|
|
5851
|
-
// src/document2/exportJson.ts
|
|
5852
|
-
function serializeField(field) {
|
|
5853
|
-
let value = "";
|
|
5854
|
-
let hasPersistedMath = false;
|
|
5855
|
-
const formats = [];
|
|
5856
|
-
const mathObjects = [];
|
|
5857
|
-
for (const token of field.tokens) {
|
|
5858
|
-
if (token.kind === "text") {
|
|
5859
|
-
const start = value.length;
|
|
5860
|
-
value += token.text;
|
|
5861
|
-
if (token.text.length > 0 && (token.style?.bold || token.style?.italic || token.style?.underline)) {
|
|
5862
|
-
formats.push({
|
|
5863
|
-
start,
|
|
5864
|
-
end: value.length,
|
|
5865
|
-
...token.style.bold ? { bold: true } : {},
|
|
5866
|
-
...token.style.italic ? { italic: true } : {},
|
|
5867
|
-
...token.style.underline ? { underline: true } : {}
|
|
5868
|
-
});
|
|
5869
|
-
}
|
|
5870
|
-
continue;
|
|
5871
|
-
}
|
|
5872
|
-
if (token.kind === "cite") {
|
|
5873
|
-
value += citeTokenLatex(token.keys);
|
|
5874
|
-
continue;
|
|
5875
|
-
}
|
|
5876
|
-
if (token.kind === "ref") {
|
|
5877
|
-
value += refTokenLatex(token.keys, token.refCommand);
|
|
5878
|
-
continue;
|
|
5879
|
-
}
|
|
5880
|
-
value += token.source;
|
|
5881
|
-
if (!token.math || token.sourceOwner === "raw") {
|
|
5882
|
-
if (token.labelEnabled !== void 0 || token.label !== void 0) {
|
|
5883
|
-
hasPersistedMath = true;
|
|
5884
|
-
mathObjects.push({
|
|
5885
|
-
node_type: "RawMathObject",
|
|
5886
|
-
...token.labelEnabled !== void 0 ? { label_enabled: token.labelEnabled } : {},
|
|
5887
|
-
...token.label !== void 0 ? { label: token.label } : {}
|
|
5888
|
-
});
|
|
5889
|
-
} else {
|
|
5890
|
-
mathObjects.push(null);
|
|
5891
|
-
}
|
|
5892
|
-
continue;
|
|
5893
|
-
}
|
|
5894
|
-
hasPersistedMath = true;
|
|
5895
|
-
mathObjects.push({
|
|
5896
|
-
...toMathObjectJson(token.math),
|
|
5897
|
-
...token.sourceSide ? { source_side: token.sourceSide } : {},
|
|
5898
|
-
source_owner: token.sourceOwner,
|
|
5899
|
-
...token.labelEnabled !== void 0 ? { label_enabled: token.labelEnabled } : {},
|
|
5900
|
-
...token.label !== void 0 ? { label: token.label } : {}
|
|
5901
|
-
});
|
|
5902
|
-
}
|
|
5903
|
-
return { value, formats, mathObjects, hasPersistedMath };
|
|
5904
|
-
}
|
|
5905
|
-
function fieldJson(field) {
|
|
5906
|
-
const serialized = serializeField(field);
|
|
5907
|
-
return {
|
|
5908
|
-
value: serialized.value,
|
|
5909
|
-
...serialized.formats.length > 0 ? { formats: serialized.formats } : {},
|
|
5910
|
-
...serialized.hasPersistedMath ? { math_objects: serialized.mathObjects } : {}
|
|
5911
|
-
};
|
|
5912
|
-
}
|
|
5913
|
-
function listItemJson(item) {
|
|
5914
|
-
const field = fieldJson(item.field);
|
|
5915
|
-
return {
|
|
5916
|
-
value: field.value ?? "",
|
|
5917
|
-
...field.formats ? { formats: field.formats } : {},
|
|
5918
|
-
...field.math_objects ? { math_objects: field.math_objects } : {},
|
|
5919
|
-
...item.blocks.length > 0 ? { blocks: item.blocks.map(blockJson) } : {}
|
|
5920
|
-
};
|
|
5921
|
-
}
|
|
5922
|
-
function blockJson(block) {
|
|
5923
|
-
if (block.kind === "textBlock") {
|
|
5924
|
-
return {
|
|
5925
|
-
command: block.command,
|
|
5926
|
-
...fieldJson(block.field),
|
|
5927
|
-
...block.command === "\\paragraph" ? { centered: block.centered === true } : {}
|
|
5928
|
-
};
|
|
5929
|
-
}
|
|
5930
|
-
if (block.kind === "list") {
|
|
5931
|
-
return {
|
|
5932
|
-
command: block.command,
|
|
5933
|
-
closing: block.closing,
|
|
5934
|
-
items: block.items.map(listItemJson)
|
|
5935
|
-
};
|
|
5936
|
-
}
|
|
5937
|
-
if (block.kind === "table") {
|
|
5938
|
-
const fields = block.rows.map((row) => row.map(serializeField));
|
|
5939
|
-
const hasPersistedMath = fields.some((row) => row.some((field) => field.hasPersistedMath));
|
|
5940
|
-
return {
|
|
5941
|
-
command: block.command,
|
|
5942
|
-
closing: block.closing,
|
|
5943
|
-
columns: block.columns,
|
|
5944
|
-
rows: fields.map((row) => row.map((field) => field.value)),
|
|
5945
|
-
...fields.some((row) => row.some((field) => field.formats.length > 0)) ? { cell_formats: fields.map((row) => row.map((field) => field.formats)) } : {},
|
|
5946
|
-
...hasPersistedMath ? { math_objects: fields.flatMap((row) => row.flatMap((field) => field.mathObjects)) } : {},
|
|
5947
|
-
centered: block.centered,
|
|
5948
|
-
caption_enabled: block.captionEnabled,
|
|
5949
|
-
caption: block.caption,
|
|
5950
|
-
label_enabled: block.labelEnabled,
|
|
5951
|
-
label: block.label
|
|
5952
|
-
};
|
|
5953
|
-
}
|
|
5954
|
-
if (block.kind === "image") {
|
|
5955
|
-
return {
|
|
5956
|
-
command: block.command,
|
|
5957
|
-
value: block.value,
|
|
5958
|
-
...block.assetId !== void 0 ? { asset_id: block.assetId } : {},
|
|
5959
|
-
options: { ...block.options },
|
|
5960
|
-
centered: block.centered,
|
|
5961
|
-
caption_enabled: block.captionEnabled,
|
|
5962
|
-
caption: block.caption,
|
|
5963
|
-
label_enabled: block.labelEnabled,
|
|
5964
|
-
label: block.label
|
|
5965
|
-
};
|
|
5966
|
-
}
|
|
5967
|
-
if (block.kind === "bibliography") {
|
|
5968
|
-
return { command: block.command, closing: block.closing };
|
|
5969
|
-
}
|
|
5970
|
-
return { command: block.command, value: block.value };
|
|
5971
|
-
}
|
|
5972
|
-
function referenceJson(reference) {
|
|
5973
|
-
return {
|
|
5974
|
-
key: reference.key,
|
|
5975
|
-
authors: reference.authors,
|
|
5976
|
-
title: reference.title,
|
|
5977
|
-
year: reference.year,
|
|
5978
|
-
url: reference.url,
|
|
5979
|
-
venue: reference.venue,
|
|
5980
|
-
field_separator: reference.fieldSeparator
|
|
5981
|
-
};
|
|
5982
|
-
}
|
|
5983
|
-
function toDocumentJson2(document2) {
|
|
5984
|
-
if (document2.nodeType !== "DocumentObject" || !Array.isArray(document2.blocks)) {
|
|
5985
|
-
throw new Error("toDocumentJson2 requires a live Document2Node");
|
|
5986
|
-
}
|
|
5987
|
-
return {
|
|
5988
|
-
node_type: "DocumentObject",
|
|
5989
|
-
meta: {
|
|
5990
|
-
title: document2.meta.title,
|
|
5991
|
-
authors: document2.meta.authors,
|
|
5992
|
-
date: { ...document2.meta.date },
|
|
5993
|
-
abstract: document2.meta.abstract
|
|
5994
|
-
},
|
|
5995
|
-
references: document2.references.map(referenceJson),
|
|
5996
|
-
blocks: document2.blocks.map(blockJson)
|
|
5997
|
-
};
|
|
5998
|
-
}
|
|
5999
|
-
|
|
6000
6371
|
// src/document2/history.ts
|
|
6001
6372
|
var DEFAULT_DOCUMENT2_HISTORY_MAX_DEPTH = 100;
|
|
6002
6373
|
function createDocument2History(maxDepth = DEFAULT_DOCUMENT2_HISTORY_MAX_DEPTH) {
|
|
@@ -6275,6 +6646,7 @@ function document2Preview(document2, output = "svg", equationSide = "arabic", pr
|
|
|
6275
6646
|
DEFAULT_DOCUMENT2_HISTORY_MAX_DEPTH,
|
|
6276
6647
|
DEFAULT_HIJRI_DATE,
|
|
6277
6648
|
DEFAULT_REFERENCE_FIELD_SEPARATOR,
|
|
6649
|
+
Document2CommandError,
|
|
6278
6650
|
HIJRI_MONTH_IDS,
|
|
6279
6651
|
HIJRI_YEAR_MAX,
|
|
6280
6652
|
HIJRI_YEAR_MIN,
|
|
@@ -6285,6 +6657,7 @@ function document2Preview(document2, output = "svg", equationSide = "arabic", pr
|
|
|
6285
6657
|
addDocument2Reference,
|
|
6286
6658
|
addDocument2TableBlock,
|
|
6287
6659
|
addDocument2TextBlock,
|
|
6660
|
+
applyDocument2Command,
|
|
6288
6661
|
applyFloatMetaPatch,
|
|
6289
6662
|
arabicXeLatexPreambleCmd,
|
|
6290
6663
|
arabicXeLatexPreambleFont,
|
|
@@ -6300,6 +6673,7 @@ function document2Preview(document2, output = "svg", equationSide = "arabic", pr
|
|
|
6300
6673
|
butexMaghribiDisplayLatex,
|
|
6301
6674
|
butexMaghribiDisplayTex,
|
|
6302
6675
|
citeTokenLatex,
|
|
6676
|
+
clearDocument2ImageAsset,
|
|
6303
6677
|
cloneDocument2Meta,
|
|
6304
6678
|
cloneDocument2Node,
|
|
6305
6679
|
collectDocument2Labels,
|
|
@@ -6319,6 +6693,7 @@ function document2Preview(document2, output = "svg", equationSide = "arabic", pr
|
|
|
6319
6693
|
document2HistoryCanUndo,
|
|
6320
6694
|
document2KeyError,
|
|
6321
6695
|
document2Latex,
|
|
6696
|
+
document2Outline,
|
|
6322
6697
|
document2Preview,
|
|
6323
6698
|
emptyBlockSelection,
|
|
6324
6699
|
emptyDocument2Meta,
|
|
@@ -6385,6 +6760,7 @@ function document2Preview(document2, output = "svg", equationSide = "arabic", pr
|
|
|
6385
6760
|
toggleBlockInSelection,
|
|
6386
6761
|
toggleTextTokenStyle,
|
|
6387
6762
|
updateCiteTokenKeys,
|
|
6763
|
+
updateDocument2ImageAsset,
|
|
6388
6764
|
updateDocument2ImageMeta,
|
|
6389
6765
|
updateDocument2ImageValue,
|
|
6390
6766
|
updateDocument2Meta,
|