bun-docx 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -5
- package/dist/index.js +1834 -381
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -13762,7 +13762,7 @@ var init_package = __esm(() => {
|
|
|
13762
13762
|
|
|
13763
13763
|
// src/core/ast/read.ts
|
|
13764
13764
|
function buildDoc(view, path) {
|
|
13765
|
-
|
|
13765
|
+
readRelationships(view);
|
|
13766
13766
|
const properties = readDocProperties(view);
|
|
13767
13767
|
const documentRoot = XmlNode2.findRoot(view.documentTree, "w:document");
|
|
13768
13768
|
if (!documentRoot) {
|
|
@@ -13774,12 +13774,23 @@ function buildDoc(view, path) {
|
|
|
13774
13774
|
}
|
|
13775
13775
|
const state = {
|
|
13776
13776
|
imageIndex: 0,
|
|
13777
|
+
hyperlinkIndex: 0,
|
|
13777
13778
|
commentAnchors: new Map,
|
|
13778
13779
|
openComments: new Map
|
|
13779
13780
|
};
|
|
13780
13781
|
const blocks = readBlocks(view, body, state);
|
|
13781
13782
|
const comments = readComments(view, state.commentAnchors);
|
|
13782
|
-
|
|
13783
|
+
const footnotes = readNotes(view.footnotesTree, "w:footnotes", "w:footnote", "fn");
|
|
13784
|
+
const endnotes = readNotes(view.endnotesTree, "w:endnotes", "w:endnote", "en");
|
|
13785
|
+
return {
|
|
13786
|
+
schemaVersion: 1,
|
|
13787
|
+
path,
|
|
13788
|
+
properties,
|
|
13789
|
+
blocks,
|
|
13790
|
+
comments,
|
|
13791
|
+
footnotes,
|
|
13792
|
+
endnotes
|
|
13793
|
+
};
|
|
13783
13794
|
}
|
|
13784
13795
|
function readBlocks(view, body, state) {
|
|
13785
13796
|
const blocks = [];
|
|
@@ -13813,17 +13824,30 @@ function readParagraph(view, node, id, state) {
|
|
|
13813
13824
|
if (paragraphProperties) {
|
|
13814
13825
|
applyParagraphProperties(paragraph, paragraphProperties);
|
|
13815
13826
|
}
|
|
13816
|
-
const
|
|
13817
|
-
|
|
13818
|
-
|
|
13827
|
+
const context = {
|
|
13828
|
+
view,
|
|
13829
|
+
blockId: id,
|
|
13830
|
+
paragraph,
|
|
13831
|
+
activeComments: new Set,
|
|
13832
|
+
state,
|
|
13833
|
+
offsetRef: { value: 0 }
|
|
13834
|
+
};
|
|
13835
|
+
walkRunContainer(context, node, undefined, undefined);
|
|
13836
|
+
return paragraph;
|
|
13837
|
+
}
|
|
13838
|
+
function walkRunContainer(context, container, trackedChange, hyperlink) {
|
|
13839
|
+
for (const child of container.children) {
|
|
13819
13840
|
if (child.tag === "w:pPr")
|
|
13820
13841
|
continue;
|
|
13821
13842
|
if (child.tag === "w:commentRangeStart") {
|
|
13822
13843
|
const commentId = child.getAttribute("w:id");
|
|
13823
13844
|
if (commentId) {
|
|
13824
13845
|
const key = `c${commentId}`;
|
|
13825
|
-
activeComments.add(key);
|
|
13826
|
-
state.openComments.set(key, {
|
|
13846
|
+
context.activeComments.add(key);
|
|
13847
|
+
context.state.openComments.set(key, {
|
|
13848
|
+
blockId: context.blockId,
|
|
13849
|
+
offset: context.offsetRef.value
|
|
13850
|
+
});
|
|
13827
13851
|
}
|
|
13828
13852
|
continue;
|
|
13829
13853
|
}
|
|
@@ -13831,26 +13855,48 @@ function readParagraph(view, node, id, state) {
|
|
|
13831
13855
|
const commentId = child.getAttribute("w:id");
|
|
13832
13856
|
if (commentId) {
|
|
13833
13857
|
const key = `c${commentId}`;
|
|
13834
|
-
activeComments.delete(key);
|
|
13835
|
-
const opened = state.openComments.get(key);
|
|
13858
|
+
context.activeComments.delete(key);
|
|
13859
|
+
const opened = context.state.openComments.get(key);
|
|
13836
13860
|
if (opened) {
|
|
13837
|
-
state.commentAnchors.set(key, {
|
|
13861
|
+
context.state.commentAnchors.set(key, {
|
|
13838
13862
|
startBlockId: opened.blockId,
|
|
13839
13863
|
startOffset: opened.offset,
|
|
13840
|
-
endBlockId:
|
|
13841
|
-
endOffset:
|
|
13864
|
+
endBlockId: context.blockId,
|
|
13865
|
+
endOffset: context.offsetRef.value
|
|
13842
13866
|
});
|
|
13843
|
-
state.openComments.delete(key);
|
|
13867
|
+
context.state.openComments.delete(key);
|
|
13844
13868
|
}
|
|
13845
13869
|
}
|
|
13846
13870
|
continue;
|
|
13847
13871
|
}
|
|
13848
13872
|
if (child.tag === "w:r") {
|
|
13849
|
-
const run = readRun(view, child, activeComments,
|
|
13873
|
+
const run = readRun(context.view, child, context.activeComments, trackedChange, hyperlink, context.state);
|
|
13850
13874
|
if (run) {
|
|
13851
13875
|
if (run.type === "text")
|
|
13852
|
-
|
|
13853
|
-
paragraph.runs.push(run);
|
|
13876
|
+
context.offsetRef.value += run.text.length;
|
|
13877
|
+
context.paragraph.runs.push(run);
|
|
13878
|
+
}
|
|
13879
|
+
continue;
|
|
13880
|
+
}
|
|
13881
|
+
if (child.tag === "m:oMath") {
|
|
13882
|
+
const text = collectMathText(child);
|
|
13883
|
+
if (text.length > 0) {
|
|
13884
|
+
context.paragraph.runs.push({
|
|
13885
|
+
type: "equation",
|
|
13886
|
+
text,
|
|
13887
|
+
display: false
|
|
13888
|
+
});
|
|
13889
|
+
}
|
|
13890
|
+
continue;
|
|
13891
|
+
}
|
|
13892
|
+
if (child.tag === "m:oMathPara") {
|
|
13893
|
+
const text = collectMathText(child);
|
|
13894
|
+
if (text.length > 0) {
|
|
13895
|
+
context.paragraph.runs.push({
|
|
13896
|
+
type: "equation",
|
|
13897
|
+
text,
|
|
13898
|
+
display: true
|
|
13899
|
+
});
|
|
13854
13900
|
}
|
|
13855
13901
|
continue;
|
|
13856
13902
|
}
|
|
@@ -13861,46 +13907,40 @@ function readParagraph(view, node, id, state) {
|
|
|
13861
13907
|
date: child.getAttribute("w:date") ?? "",
|
|
13862
13908
|
revisionId: child.getAttribute("w:id") ?? ""
|
|
13863
13909
|
};
|
|
13864
|
-
|
|
13865
|
-
|
|
13866
|
-
|
|
13867
|
-
|
|
13868
|
-
|
|
13869
|
-
|
|
13870
|
-
state.openComments.set(key, { blockId: id, offset });
|
|
13871
|
-
}
|
|
13872
|
-
continue;
|
|
13873
|
-
}
|
|
13874
|
-
if (inner.tag === "w:commentRangeEnd") {
|
|
13875
|
-
const commentId = inner.getAttribute("w:id");
|
|
13876
|
-
if (commentId) {
|
|
13877
|
-
const key = `c${commentId}`;
|
|
13878
|
-
activeComments.delete(key);
|
|
13879
|
-
const opened = state.openComments.get(key);
|
|
13880
|
-
if (opened) {
|
|
13881
|
-
state.commentAnchors.set(key, {
|
|
13882
|
-
startBlockId: opened.blockId,
|
|
13883
|
-
startOffset: opened.offset,
|
|
13884
|
-
endBlockId: id,
|
|
13885
|
-
endOffset: offset
|
|
13886
|
-
});
|
|
13887
|
-
state.openComments.delete(key);
|
|
13888
|
-
}
|
|
13889
|
-
}
|
|
13890
|
-
continue;
|
|
13891
|
-
}
|
|
13892
|
-
if (inner.tag !== "w:r")
|
|
13893
|
-
continue;
|
|
13894
|
-
const run = readRun(view, inner, activeComments, change, state);
|
|
13895
|
-
if (!run)
|
|
13896
|
-
continue;
|
|
13897
|
-
if (run.type === "text")
|
|
13898
|
-
offset += run.text.length;
|
|
13899
|
-
paragraph.runs.push(run);
|
|
13900
|
-
}
|
|
13910
|
+
walkRunContainer(context, child, change, hyperlink);
|
|
13911
|
+
continue;
|
|
13912
|
+
}
|
|
13913
|
+
if (child.tag === "w:hyperlink") {
|
|
13914
|
+
const link = readHyperlinkProperties(context.view, child, container.children, context.state);
|
|
13915
|
+
walkRunContainer(context, child, trackedChange, link);
|
|
13901
13916
|
}
|
|
13902
13917
|
}
|
|
13903
|
-
|
|
13918
|
+
}
|
|
13919
|
+
function readHyperlinkProperties(view, node, parent, state) {
|
|
13920
|
+
const id = `link${state.hyperlinkIndex++}`;
|
|
13921
|
+
const link = { id };
|
|
13922
|
+
const relationshipId = node.getAttribute("r:id");
|
|
13923
|
+
if (relationshipId) {
|
|
13924
|
+
const relationship = view.hyperlinksByRelationshipId.get(relationshipId);
|
|
13925
|
+
if (relationship?.url)
|
|
13926
|
+
link.url = relationship.url;
|
|
13927
|
+
}
|
|
13928
|
+
const anchor = node.getAttribute("w:anchor");
|
|
13929
|
+
if (anchor)
|
|
13930
|
+
link.anchor = anchor;
|
|
13931
|
+
const tooltip = node.getAttribute("w:tooltip");
|
|
13932
|
+
if (tooltip)
|
|
13933
|
+
link.tooltip = tooltip;
|
|
13934
|
+
if (!link.url && !link.anchor && !link.tooltip) {
|
|
13935
|
+
state.hyperlinkIndex--;
|
|
13936
|
+
return;
|
|
13937
|
+
}
|
|
13938
|
+
view.hyperlinkById.set(id, {
|
|
13939
|
+
node,
|
|
13940
|
+
parent,
|
|
13941
|
+
...relationshipId ? { relationshipId } : {}
|
|
13942
|
+
});
|
|
13943
|
+
return link;
|
|
13904
13944
|
}
|
|
13905
13945
|
function applyParagraphProperties(paragraph, paragraphProperties) {
|
|
13906
13946
|
const styleNode = paragraphProperties.findChild("w:pStyle");
|
|
@@ -13925,13 +13965,13 @@ function applyParagraphProperties(paragraph, paragraphProperties) {
|
|
|
13925
13965
|
paragraph.list = { level, numId: id };
|
|
13926
13966
|
}
|
|
13927
13967
|
}
|
|
13928
|
-
function readRun(view, node, activeComments, trackedChange, state) {
|
|
13968
|
+
function readRun(view, node, activeComments, trackedChange, hyperlink, state) {
|
|
13929
13969
|
const runProperties = node.findChild("w:rPr");
|
|
13930
13970
|
for (const child of node.children) {
|
|
13931
13971
|
if (child.tag === "w:drawing") {
|
|
13932
|
-
const
|
|
13933
|
-
if (
|
|
13934
|
-
return
|
|
13972
|
+
const drawing = readDrawing(view, child, state);
|
|
13973
|
+
if (drawing)
|
|
13974
|
+
return drawing;
|
|
13935
13975
|
}
|
|
13936
13976
|
if (child.tag === "w:br") {
|
|
13937
13977
|
const kind = child.getAttribute("w:type") ?? "line";
|
|
@@ -13940,6 +13980,16 @@ function readRun(view, node, activeComments, trackedChange, state) {
|
|
|
13940
13980
|
if (child.tag === "w:tab") {
|
|
13941
13981
|
return { type: "tab" };
|
|
13942
13982
|
}
|
|
13983
|
+
if (child.tag === "w:footnoteReference") {
|
|
13984
|
+
const id = child.getAttribute("w:id");
|
|
13985
|
+
if (id)
|
|
13986
|
+
return { type: "footnoteRef", kind: "footnote", id: `fn${id}` };
|
|
13987
|
+
}
|
|
13988
|
+
if (child.tag === "w:endnoteReference") {
|
|
13989
|
+
const id = child.getAttribute("w:id");
|
|
13990
|
+
if (id)
|
|
13991
|
+
return { type: "footnoteRef", kind: "endnote", id: `en${id}` };
|
|
13992
|
+
}
|
|
13943
13993
|
}
|
|
13944
13994
|
let combinedText = "";
|
|
13945
13995
|
for (const child of node.children) {
|
|
@@ -13956,8 +14006,33 @@ function readRun(view, node, activeComments, trackedChange, state) {
|
|
|
13956
14006
|
run.comments = [...activeComments];
|
|
13957
14007
|
if (trackedChange)
|
|
13958
14008
|
run.trackedChange = trackedChange;
|
|
14009
|
+
if (hyperlink)
|
|
14010
|
+
run.hyperlink = hyperlink;
|
|
13959
14011
|
return run;
|
|
13960
14012
|
}
|
|
14013
|
+
function readDrawing(view, drawing, state) {
|
|
14014
|
+
const image = readImageFromDrawing(view, drawing, state);
|
|
14015
|
+
if (image)
|
|
14016
|
+
return image;
|
|
14017
|
+
if (drawing.findDescendant("c:chart"))
|
|
14018
|
+
return { type: "chart", kind: "chart" };
|
|
14019
|
+
if (drawing.findDescendant("dgm:relIds"))
|
|
14020
|
+
return { type: "chart", kind: "smartart" };
|
|
14021
|
+
if (drawing.findDescendant("wps:wsp"))
|
|
14022
|
+
return { type: "chart", kind: "shape" };
|
|
14023
|
+
return { type: "chart", kind: "drawing" };
|
|
14024
|
+
}
|
|
14025
|
+
function collectMathText(node) {
|
|
14026
|
+
let out = "";
|
|
14027
|
+
for (const child of node.children) {
|
|
14028
|
+
if (child.tag === "m:t") {
|
|
14029
|
+
out += child.collectText();
|
|
14030
|
+
continue;
|
|
14031
|
+
}
|
|
14032
|
+
out += collectMathText(child);
|
|
14033
|
+
}
|
|
14034
|
+
return out;
|
|
14035
|
+
}
|
|
13961
14036
|
function applyRunProperties(run, runProperties) {
|
|
13962
14037
|
const colorNode = runProperties.findChild("w:color");
|
|
13963
14038
|
if (colorNode) {
|
|
@@ -14060,22 +14135,30 @@ function readCellBlocks(view, cell, tableId, rowIndex, columnIndex, state) {
|
|
|
14060
14135
|
}
|
|
14061
14136
|
return blocks;
|
|
14062
14137
|
}
|
|
14063
|
-
function
|
|
14138
|
+
function readRelationships(view) {
|
|
14064
14139
|
const relationships = XmlNode2.findRoot(view.relationshipsTree, "Relationships");
|
|
14065
14140
|
if (!relationships)
|
|
14066
14141
|
return;
|
|
14067
14142
|
for (const child of relationships.children) {
|
|
14068
14143
|
if (child.tag !== "Relationship")
|
|
14069
14144
|
continue;
|
|
14070
|
-
|
|
14071
|
-
continue;
|
|
14145
|
+
const type = child.getAttribute("Type");
|
|
14072
14146
|
const relationshipId = child.getAttribute("Id");
|
|
14073
14147
|
const target = child.getAttribute("Target");
|
|
14074
14148
|
if (!relationshipId || !target)
|
|
14075
14149
|
continue;
|
|
14076
|
-
|
|
14077
|
-
|
|
14078
|
-
|
|
14150
|
+
if (type === RELATIONSHIP_NAMESPACE_IMAGE) {
|
|
14151
|
+
const partName = target.startsWith("/") ? target.slice(1) : `word/${target}`;
|
|
14152
|
+
const contentType = lookupContentType(view, partName);
|
|
14153
|
+
view.imagesByRelationshipId.set(relationshipId, {
|
|
14154
|
+
partName,
|
|
14155
|
+
contentType
|
|
14156
|
+
});
|
|
14157
|
+
continue;
|
|
14158
|
+
}
|
|
14159
|
+
if (type === RELATIONSHIP_NAMESPACE_HYPERLINK) {
|
|
14160
|
+
view.hyperlinksByRelationshipId.set(relationshipId, { url: target });
|
|
14161
|
+
}
|
|
14079
14162
|
}
|
|
14080
14163
|
}
|
|
14081
14164
|
function lookupContentType(view, partName) {
|
|
@@ -14204,7 +14287,27 @@ function readCommentsExtended(view) {
|
|
|
14204
14287
|
}
|
|
14205
14288
|
return out;
|
|
14206
14289
|
}
|
|
14207
|
-
|
|
14290
|
+
function readNotes(tree, rootTag, itemTag, idPrefix) {
|
|
14291
|
+
if (!tree)
|
|
14292
|
+
return [];
|
|
14293
|
+
const root = XmlNode2.findRoot(tree, rootTag);
|
|
14294
|
+
if (!root)
|
|
14295
|
+
return [];
|
|
14296
|
+
const out = [];
|
|
14297
|
+
for (const child of root.children) {
|
|
14298
|
+
if (child.tag !== itemTag)
|
|
14299
|
+
continue;
|
|
14300
|
+
if (child.getAttribute("w:type"))
|
|
14301
|
+
continue;
|
|
14302
|
+
const numericId = child.getAttribute("w:id");
|
|
14303
|
+
if (numericId == null)
|
|
14304
|
+
continue;
|
|
14305
|
+
const text = child.collectText().replace(/\s+/g, " ").trim();
|
|
14306
|
+
out.push({ id: `${idPrefix}${numericId}`, text });
|
|
14307
|
+
}
|
|
14308
|
+
return out;
|
|
14309
|
+
}
|
|
14310
|
+
var RELATIONSHIP_NAMESPACE_IMAGE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", RELATIONSHIP_NAMESPACE_HYPERLINK = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
|
|
14208
14311
|
var init_read = __esm(() => {
|
|
14209
14312
|
init_parser();
|
|
14210
14313
|
});
|
|
@@ -14219,11 +14322,15 @@ async function openDocView(path) {
|
|
|
14219
14322
|
const commentsExtTree = pkg.hasPart("word/commentsExtended.xml") ? XmlNode2.parse(await pkg.readText("word/commentsExtended.xml")) : undefined;
|
|
14220
14323
|
const corePropertiesTree = pkg.hasPart("docProps/core.xml") ? XmlNode2.parse(await pkg.readText("docProps/core.xml")) : undefined;
|
|
14221
14324
|
const settingsTree = pkg.hasPart("word/settings.xml") ? XmlNode2.parse(await pkg.readText("word/settings.xml")) : undefined;
|
|
14325
|
+
const footnotesTree = pkg.hasPart("word/footnotes.xml") ? XmlNode2.parse(await pkg.readText("word/footnotes.xml")) : undefined;
|
|
14326
|
+
const endnotesTree = pkg.hasPart("word/endnotes.xml") ? XmlNode2.parse(await pkg.readText("word/endnotes.xml")) : undefined;
|
|
14222
14327
|
const view = {
|
|
14223
14328
|
pkg,
|
|
14224
14329
|
documentTree,
|
|
14225
14330
|
commentsTree,
|
|
14226
14331
|
commentsExtTree,
|
|
14332
|
+
footnotesTree,
|
|
14333
|
+
endnotesTree,
|
|
14227
14334
|
relationshipsTree,
|
|
14228
14335
|
contentTypesTree,
|
|
14229
14336
|
corePropertiesTree,
|
|
@@ -14232,7 +14339,9 @@ async function openDocView(path) {
|
|
|
14232
14339
|
blockReferences: new Map,
|
|
14233
14340
|
commentReferences: new Map,
|
|
14234
14341
|
imagesByRelationshipId: new Map,
|
|
14235
|
-
imageById: new Map
|
|
14342
|
+
imageById: new Map,
|
|
14343
|
+
hyperlinksByRelationshipId: new Map,
|
|
14344
|
+
hyperlinkById: new Map
|
|
14236
14345
|
};
|
|
14237
14346
|
view.doc = buildDoc(view, pkg.path);
|
|
14238
14347
|
return view;
|
|
@@ -14302,6 +14411,49 @@ var init_doc_view = __esm(() => {
|
|
|
14302
14411
|
init_read();
|
|
14303
14412
|
});
|
|
14304
14413
|
|
|
14414
|
+
// src/core/ast/text.ts
|
|
14415
|
+
function paragraphText(paragraph) {
|
|
14416
|
+
let out = "";
|
|
14417
|
+
for (const run of paragraph.runs) {
|
|
14418
|
+
if (run.type === "text")
|
|
14419
|
+
out += run.text;
|
|
14420
|
+
}
|
|
14421
|
+
return out;
|
|
14422
|
+
}
|
|
14423
|
+
function flattenParagraphs(blocks) {
|
|
14424
|
+
const out = [];
|
|
14425
|
+
for (const block of blocks) {
|
|
14426
|
+
if (block.type === "paragraph") {
|
|
14427
|
+
out.push(block);
|
|
14428
|
+
continue;
|
|
14429
|
+
}
|
|
14430
|
+
if (block.type === "table") {
|
|
14431
|
+
for (const row of block.rows) {
|
|
14432
|
+
for (const cell of row.cells) {
|
|
14433
|
+
out.push(...flattenParagraphs(cell.blocks));
|
|
14434
|
+
}
|
|
14435
|
+
}
|
|
14436
|
+
}
|
|
14437
|
+
}
|
|
14438
|
+
return out;
|
|
14439
|
+
}
|
|
14440
|
+
function findBlockById(blocks, blockId) {
|
|
14441
|
+
for (const block of blocks) {
|
|
14442
|
+
if (block.id === blockId)
|
|
14443
|
+
return block;
|
|
14444
|
+
if (block.type === "table") {
|
|
14445
|
+
for (const row of block.rows) {
|
|
14446
|
+
for (const cell of row.cells) {
|
|
14447
|
+
const inner = findBlockById(cell.blocks, blockId);
|
|
14448
|
+
if (inner)
|
|
14449
|
+
return inner;
|
|
14450
|
+
}
|
|
14451
|
+
}
|
|
14452
|
+
}
|
|
14453
|
+
}
|
|
14454
|
+
return null;
|
|
14455
|
+
}
|
|
14456
|
+
|
|
14305
14457
|
// src/core/ast/index.ts
|
|
14306
14458
|
var init_ast = __esm(() => {
|
|
14307
14459
|
init_doc_view();
|
|
@@ -14319,6 +14471,10 @@ function parseLocator(input) {
|
|
|
14319
14471
|
const imageMatch = trimmed.match(IMAGE_RE);
|
|
14320
14472
|
if (imageMatch)
|
|
14321
14473
|
return { kind: "image", imageId: `img${imageMatch[1]}` };
|
|
14474
|
+
const linkMatch = trimmed.match(LINK_RE);
|
|
14475
|
+
if (linkMatch) {
|
|
14476
|
+
return { kind: "hyperlink", hyperlinkId: `link${linkMatch[1]}` };
|
|
14477
|
+
}
|
|
14322
14478
|
const cellMatch = trimmed.match(CELL_RE);
|
|
14323
14479
|
if (cellMatch) {
|
|
14324
14480
|
const [, tableIndex, rowIndex, columnIndex, rest] = cellMatch;
|
|
@@ -14367,7 +14523,7 @@ function validateOffsets(input, start, end, crossBlock) {
|
|
|
14367
14523
|
throw new LocatorParseError(input, "end offset precedes start");
|
|
14368
14524
|
}
|
|
14369
14525
|
}
|
|
14370
|
-
var LocatorParseError, BLOCK_RE, SPAN_RE, RANGE_RE, COMMENT_RE, IMAGE_RE, CELL_RE;
|
|
14526
|
+
var LocatorParseError, BLOCK_RE, SPAN_RE, RANGE_RE, COMMENT_RE, IMAGE_RE, LINK_RE, CELL_RE;
|
|
14371
14527
|
var init_parse = __esm(() => {
|
|
14372
14528
|
LocatorParseError = class LocatorParseError extends Error {
|
|
14373
14529
|
input;
|
|
@@ -14382,6 +14538,7 @@ var init_parse = __esm(() => {
|
|
|
14382
14538
|
RANGE_RE = /^p(\d+):(\d+)-p(\d+):(\d+)$/;
|
|
14383
14539
|
COMMENT_RE = /^c(\d+)$/;
|
|
14384
14540
|
IMAGE_RE = /^img(\d+)$/;
|
|
14541
|
+
LINK_RE = /^link(\d+)$/;
|
|
14385
14542
|
CELL_RE = /^t(\d+):r(\d+)c(\d+)(?::(.+))?$/;
|
|
14386
14543
|
});
|
|
14387
14544
|
|
|
@@ -14431,6 +14588,39 @@ var init_locators = __esm(() => {
|
|
|
14431
14588
|
init_resolve();
|
|
14432
14589
|
});
|
|
14433
14590
|
|
|
14591
|
+
// src/core/relationships.ts
|
|
14592
|
+
function mintRelationshipId(relationshipsRoot) {
|
|
14593
|
+
let highest = 0;
|
|
14594
|
+
for (const child of relationshipsRoot.children) {
|
|
14595
|
+
if (child.tag !== "Relationship")
|
|
14596
|
+
continue;
|
|
14597
|
+
const id = child.getAttribute("Id");
|
|
14598
|
+
if (!id)
|
|
14599
|
+
continue;
|
|
14600
|
+
const match = id.match(/^rId(\d+)$/);
|
|
14601
|
+
if (match?.[1]) {
|
|
14602
|
+
const number = Number(match[1]);
|
|
14603
|
+
if (number > highest)
|
|
14604
|
+
highest = number;
|
|
14605
|
+
}
|
|
14606
|
+
}
|
|
14607
|
+
return `rId${highest + 1}`;
|
|
14608
|
+
}
|
|
14609
|
+
function addHyperlinkRelationship(relationshipsRoot, url) {
|
|
14610
|
+
const id = mintRelationshipId(relationshipsRoot);
|
|
14611
|
+
relationshipsRoot.children.push(new XmlNode2("Relationship", {
|
|
14612
|
+
Id: id,
|
|
14613
|
+
Type: HYPERLINK_RELATIONSHIP_TYPE,
|
|
14614
|
+
Target: url,
|
|
14615
|
+
TargetMode: "External"
|
|
14616
|
+
}));
|
|
14617
|
+
return id;
|
|
14618
|
+
}
|
|
14619
|
+
var HYPERLINK_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
|
|
14620
|
+
var init_relationships = __esm(() => {
|
|
14621
|
+
init_parser();
|
|
14622
|
+
});
|
|
14623
|
+
|
|
14434
14624
|
// src/core/track-changes/index.ts
|
|
14435
14625
|
function isTrackChangesEnabled(view) {
|
|
14436
14626
|
if (!view.settingsTree)
|
|
@@ -14607,7 +14797,8 @@ var init_jsx = __esm(() => {
|
|
|
14607
14797
|
"comments",
|
|
14608
14798
|
"comment",
|
|
14609
14799
|
"settings",
|
|
14610
|
-
"trackChanges"
|
|
14800
|
+
"trackChanges",
|
|
14801
|
+
"hyperlink"
|
|
14611
14802
|
];
|
|
14612
14803
|
R_TAGS = ["embed", "link", "id"];
|
|
14613
14804
|
A_TAGS = [
|
|
@@ -14722,6 +14913,7 @@ var init_core = __esm(() => {
|
|
|
14722
14913
|
init_locators();
|
|
14723
14914
|
init_package();
|
|
14724
14915
|
init_parser();
|
|
14916
|
+
init_relationships();
|
|
14725
14917
|
init_track_changes();
|
|
14726
14918
|
init_emit();
|
|
14727
14919
|
});
|
|
@@ -14755,6 +14947,7 @@ function exitCodeFor(code) {
|
|
|
14755
14947
|
case "BLOCK_NOT_FOUND":
|
|
14756
14948
|
case "COMMENT_NOT_FOUND":
|
|
14757
14949
|
case "IMAGE_NOT_FOUND":
|
|
14950
|
+
case "HYPERLINK_NOT_FOUND":
|
|
14758
14951
|
case "MATCH_NOT_FOUND":
|
|
14759
14952
|
return EXIT.NOT_FOUND;
|
|
14760
14953
|
case "NOT_A_ZIP":
|
|
@@ -16124,7 +16317,7 @@ function RunElement({ run: run9 }) {
|
|
|
16124
16317
|
children: /* @__PURE__ */ jsxDEV(w.tab, {}, undefined, false, undefined, this)
|
|
16125
16318
|
}, undefined, false, undefined, this);
|
|
16126
16319
|
}
|
|
16127
|
-
|
|
16320
|
+
return null;
|
|
16128
16321
|
}
|
|
16129
16322
|
function TextRunElement({ run: run9 }) {
|
|
16130
16323
|
return /* @__PURE__ */ jsxDEV(w.r, {
|
|
@@ -16426,15 +16619,15 @@ function literalMatcher(query, ignoreCase) {
|
|
|
16426
16619
|
throw new Error("query cannot be empty");
|
|
16427
16620
|
}
|
|
16428
16621
|
const needle = ignoreCase ? query.toLowerCase() : query;
|
|
16429
|
-
return (
|
|
16430
|
-
const haystack = ignoreCase ?
|
|
16622
|
+
return (paragraphText2) => {
|
|
16623
|
+
const haystack = ignoreCase ? paragraphText2.toLowerCase() : paragraphText2;
|
|
16431
16624
|
const matches = [];
|
|
16432
16625
|
let cursor = haystack.indexOf(needle);
|
|
16433
16626
|
while (cursor !== -1) {
|
|
16434
16627
|
matches.push({
|
|
16435
16628
|
start: cursor,
|
|
16436
16629
|
end: cursor + needle.length,
|
|
16437
|
-
text:
|
|
16630
|
+
text: paragraphText2.slice(cursor, cursor + needle.length)
|
|
16438
16631
|
});
|
|
16439
16632
|
cursor = haystack.indexOf(needle, cursor + needle.length);
|
|
16440
16633
|
}
|
|
@@ -16444,15 +16637,15 @@ function literalMatcher(query, ignoreCase) {
|
|
|
16444
16637
|
function regexMatcher(pattern, ignoreCase) {
|
|
16445
16638
|
const flags = `g${ignoreCase ? "i" : ""}`;
|
|
16446
16639
|
const regex = new RegExp(pattern, flags);
|
|
16447
|
-
return (
|
|
16640
|
+
return (paragraphText2) => {
|
|
16448
16641
|
const matches = [];
|
|
16449
16642
|
regex.lastIndex = 0;
|
|
16450
|
-
let result = regex.exec(
|
|
16643
|
+
let result = regex.exec(paragraphText2);
|
|
16451
16644
|
while (result !== null) {
|
|
16452
16645
|
const matched = result[0];
|
|
16453
16646
|
if (matched.length === 0) {
|
|
16454
16647
|
regex.lastIndex += 1;
|
|
16455
|
-
result = regex.exec(
|
|
16648
|
+
result = regex.exec(paragraphText2);
|
|
16456
16649
|
continue;
|
|
16457
16650
|
}
|
|
16458
16651
|
matches.push({
|
|
@@ -16460,7 +16653,7 @@ function regexMatcher(pattern, ignoreCase) {
|
|
|
16460
16653
|
end: result.index + matched.length,
|
|
16461
16654
|
text: matched
|
|
16462
16655
|
});
|
|
16463
|
-
result = regex.exec(
|
|
16656
|
+
result = regex.exec(paragraphText2);
|
|
16464
16657
|
}
|
|
16465
16658
|
return matches;
|
|
16466
16659
|
};
|
|
@@ -16468,8 +16661,8 @@ function regexMatcher(pattern, ignoreCase) {
|
|
|
16468
16661
|
function collectMatches(blocks, matcher, out) {
|
|
16469
16662
|
for (const block of blocks) {
|
|
16470
16663
|
if (block.type === "paragraph") {
|
|
16471
|
-
const
|
|
16472
|
-
for (const span of matcher(
|
|
16664
|
+
const paragraphText2 = block.runs.map((run10) => run10.type === "text" ? run10.text : "").join("");
|
|
16665
|
+
for (const span of matcher(paragraphText2)) {
|
|
16473
16666
|
const match = {
|
|
16474
16667
|
blockId: block.id,
|
|
16475
16668
|
start: span.start,
|
|
@@ -16629,12 +16822,107 @@ var init_find = __esm(() => {
|
|
|
16629
16822
|
init_respond();
|
|
16630
16823
|
});
|
|
16631
16824
|
|
|
16632
|
-
// src/cli/
|
|
16633
|
-
|
|
16634
|
-
|
|
16825
|
+
// src/cli/hyperlinks/wrap.tsx
|
|
16826
|
+
function wrapSpanInHyperlink(paragraph, span, relationshipId) {
|
|
16827
|
+
if (span.start >= span.end) {
|
|
16828
|
+
throw new HyperlinkWrapError(`Empty or inverted span ${span.start}-${span.end}`);
|
|
16829
|
+
}
|
|
16830
|
+
const newChildren = [];
|
|
16831
|
+
const wrappedRuns = [];
|
|
16832
|
+
let offset = 0;
|
|
16833
|
+
let placed = false;
|
|
16834
|
+
const placeWrapper = () => {
|
|
16835
|
+
if (placed || wrappedRuns.length === 0)
|
|
16836
|
+
return;
|
|
16837
|
+
newChildren.push(hyperlinkWrapper(relationshipId, wrappedRuns));
|
|
16838
|
+
wrappedRuns.length = 0;
|
|
16839
|
+
placed = true;
|
|
16840
|
+
};
|
|
16841
|
+
for (const child of paragraph.children) {
|
|
16842
|
+
if (child.tag === "w:r") {
|
|
16843
|
+
const length = runTextLength(child);
|
|
16844
|
+
const runStart = offset;
|
|
16845
|
+
const runEnd = offset + length;
|
|
16846
|
+
offset = runEnd;
|
|
16847
|
+
if (runEnd <= span.start || runStart >= span.end) {
|
|
16848
|
+
placeWrapper();
|
|
16849
|
+
newChildren.push(child);
|
|
16850
|
+
continue;
|
|
16851
|
+
}
|
|
16852
|
+
const sliceStartInRun = Math.max(0, span.start - runStart);
|
|
16853
|
+
const sliceEndInRun = Math.min(length, span.end - runStart);
|
|
16854
|
+
if (sliceStartInRun > 0) {
|
|
16855
|
+
newChildren.push(sliceRun(child, 0, sliceStartInRun));
|
|
16856
|
+
}
|
|
16857
|
+
wrappedRuns.push(sliceRun(child, sliceStartInRun, sliceEndInRun));
|
|
16858
|
+
if (runEnd >= span.end)
|
|
16859
|
+
placeWrapper();
|
|
16860
|
+
if (sliceEndInRun < length) {
|
|
16861
|
+
newChildren.push(sliceRun(child, sliceEndInRun, length));
|
|
16862
|
+
}
|
|
16863
|
+
continue;
|
|
16864
|
+
}
|
|
16865
|
+
if (child.tag === "w:hyperlink") {
|
|
16866
|
+
const hyperlinkLength = sumInnerRunLengths(child);
|
|
16867
|
+
const hyperlinkStart = offset;
|
|
16868
|
+
const hyperlinkEnd = offset + hyperlinkLength;
|
|
16869
|
+
offset = hyperlinkEnd;
|
|
16870
|
+
if (hyperlinkEnd <= span.start || hyperlinkStart >= span.end) {
|
|
16871
|
+
placeWrapper();
|
|
16872
|
+
newChildren.push(child);
|
|
16873
|
+
continue;
|
|
16874
|
+
}
|
|
16875
|
+
throw new HyperlinkWrapError(`Span ${span.start}-${span.end} overlaps an existing hyperlink at ${hyperlinkStart}-${hyperlinkEnd}; nested hyperlinks are not allowed`);
|
|
16876
|
+
}
|
|
16877
|
+
if (child.tag === "w:ins" || child.tag === "w:del") {
|
|
16878
|
+
const innerLength = sumInnerRunLengths(child);
|
|
16879
|
+
const wrapperStart = offset;
|
|
16880
|
+
const wrapperEnd = offset + innerLength;
|
|
16881
|
+
offset = wrapperEnd;
|
|
16882
|
+
if (wrapperEnd <= span.start || wrapperStart >= span.end) {
|
|
16883
|
+
placeWrapper();
|
|
16884
|
+
newChildren.push(child);
|
|
16885
|
+
continue;
|
|
16886
|
+
}
|
|
16887
|
+
throw new HyperlinkWrapError(`Span ${span.start}-${span.end} crosses a tracked-change wrapper at ${wrapperStart}-${wrapperEnd}; resolve or accept the change first`);
|
|
16888
|
+
}
|
|
16889
|
+
newChildren.push(child);
|
|
16890
|
+
}
|
|
16891
|
+
placeWrapper();
|
|
16892
|
+
paragraph.children = newChildren;
|
|
16893
|
+
}
|
|
16894
|
+
function hyperlinkWrapper(relationshipId, runs) {
|
|
16895
|
+
return /* @__PURE__ */ jsxDEV(w.hyperlink, {
|
|
16896
|
+
"r:id": relationshipId,
|
|
16897
|
+
children: runs
|
|
16898
|
+
}, undefined, false, undefined, this);
|
|
16899
|
+
}
|
|
16900
|
+
function sumInnerRunLengths(wrapper) {
|
|
16901
|
+
let total = 0;
|
|
16902
|
+
for (const inner of wrapper.children) {
|
|
16903
|
+
if (inner.tag === "w:r")
|
|
16904
|
+
total += runTextLength(inner);
|
|
16905
|
+
}
|
|
16906
|
+
return total;
|
|
16907
|
+
}
|
|
16908
|
+
var HyperlinkWrapError;
|
|
16909
|
+
var init_wrap = __esm(() => {
|
|
16910
|
+
init_jsx();
|
|
16911
|
+
init_parser();
|
|
16912
|
+
init_jsx_dev_runtime();
|
|
16913
|
+
HyperlinkWrapError = class HyperlinkWrapError extends Error {
|
|
16914
|
+
constructor(message) {
|
|
16915
|
+
super(message);
|
|
16916
|
+
this.name = "HyperlinkWrapError";
|
|
16917
|
+
}
|
|
16918
|
+
};
|
|
16919
|
+
});
|
|
16920
|
+
|
|
16921
|
+
// src/cli/hyperlinks/add.tsx
|
|
16922
|
+
var exports_add2 = {};
|
|
16923
|
+
__export(exports_add2, {
|
|
16635
16924
|
run: () => run11
|
|
16636
16925
|
});
|
|
16637
|
-
import { join } from "path";
|
|
16638
16926
|
import { parseArgs as parseArgs10 } from "util";
|
|
16639
16927
|
async function run11(args) {
|
|
16640
16928
|
let parsed;
|
|
@@ -16643,8 +16931,10 @@ async function run11(args) {
|
|
|
16643
16931
|
args,
|
|
16644
16932
|
allowPositionals: true,
|
|
16645
16933
|
options: {
|
|
16646
|
-
|
|
16647
|
-
|
|
16934
|
+
at: { type: "string" },
|
|
16935
|
+
url: { type: "string" },
|
|
16936
|
+
output: { type: "string", short: "o" },
|
|
16937
|
+
"dry-run": { type: "boolean" },
|
|
16648
16938
|
help: { type: "boolean", short: "h" }
|
|
16649
16939
|
}
|
|
16650
16940
|
});
|
|
@@ -16659,49 +16949,569 @@ async function run11(args) {
|
|
|
16659
16949
|
const path = parsed.positionals[0];
|
|
16660
16950
|
if (!path)
|
|
16661
16951
|
return fail("USAGE", "Missing FILE argument", HELP11);
|
|
16662
|
-
const
|
|
16663
|
-
|
|
16664
|
-
|
|
16665
|
-
|
|
16952
|
+
const atInput = parsed.values.at;
|
|
16953
|
+
const url = parsed.values.url;
|
|
16954
|
+
if (!atInput)
|
|
16955
|
+
return fail("USAGE", "Missing --at LOCATOR", HELP11);
|
|
16956
|
+
if (!url)
|
|
16957
|
+
return fail("USAGE", "Missing --url URL", HELP11);
|
|
16958
|
+
let locator;
|
|
16959
|
+
try {
|
|
16960
|
+
locator = parseLocator(atInput);
|
|
16961
|
+
} catch (error) {
|
|
16962
|
+
if (error instanceof LocatorParseError) {
|
|
16963
|
+
return fail("INVALID_LOCATOR", error.message);
|
|
16964
|
+
}
|
|
16965
|
+
throw error;
|
|
16966
|
+
}
|
|
16967
|
+
const target = locatorToBlockTarget(locator);
|
|
16968
|
+
if (!target?.span) {
|
|
16969
|
+
return fail("INVALID_LOCATOR", "hyperlinks add requires a span locator like pN:S-E or tT:rRcC:pK:S-E");
|
|
16970
|
+
}
|
|
16666
16971
|
const view = await openOrFail(path);
|
|
16667
16972
|
if (typeof view === "number")
|
|
16668
16973
|
return view;
|
|
16669
|
-
await
|
|
16670
|
-
|
|
16671
|
-
|
|
16672
|
-
const
|
|
16673
|
-
if (
|
|
16674
|
-
|
|
16974
|
+
const paragraphRef = await resolveBlockOrFail(view, target.blockId);
|
|
16975
|
+
if (typeof paragraphRef === "number")
|
|
16976
|
+
return paragraphRef;
|
|
16977
|
+
const outputPath = parsed.values.output;
|
|
16978
|
+
if (parsed.values["dry-run"]) {
|
|
16979
|
+
await respond({
|
|
16980
|
+
ok: true,
|
|
16981
|
+
operation: "hyperlinks.add",
|
|
16982
|
+
dryRun: true,
|
|
16983
|
+
path,
|
|
16984
|
+
at: atInput,
|
|
16985
|
+
url,
|
|
16986
|
+
...outputPath ? { output: outputPath } : {}
|
|
16987
|
+
});
|
|
16988
|
+
return EXIT.OK;
|
|
16675
16989
|
}
|
|
16676
|
-
const
|
|
16677
|
-
|
|
16678
|
-
|
|
16679
|
-
|
|
16680
|
-
|
|
16681
|
-
|
|
16682
|
-
|
|
16683
|
-
|
|
16684
|
-
|
|
16685
|
-
|
|
16686
|
-
const bytes = await view.pkg.readBytes(reference.partName);
|
|
16687
|
-
await Bun.write(outputPath, bytes);
|
|
16688
|
-
seenHashes.add(image.hash);
|
|
16990
|
+
const relationships = XmlNode2.findRoot(view.relationshipsTree, "Relationships");
|
|
16991
|
+
if (!relationships) {
|
|
16992
|
+
return fail("UNHANDLED", "Missing <Relationships> root in document rels");
|
|
16993
|
+
}
|
|
16994
|
+
const relationshipId = addHyperlinkRelationship(relationships, url);
|
|
16995
|
+
try {
|
|
16996
|
+
wrapSpanInHyperlink(paragraphRef.node, target.span, relationshipId);
|
|
16997
|
+
} catch (error) {
|
|
16998
|
+
if (error instanceof HyperlinkWrapError) {
|
|
16999
|
+
return fail("USAGE", error.message);
|
|
16689
17000
|
}
|
|
16690
|
-
|
|
16691
|
-
id: image.id,
|
|
16692
|
-
path: outputPath,
|
|
16693
|
-
bytes: (await Bun.file(outputPath).arrayBuffer()).byteLength
|
|
16694
|
-
});
|
|
17001
|
+
throw error;
|
|
16695
17002
|
}
|
|
16696
|
-
|
|
17003
|
+
view.hyperlinksByRelationshipId.set(relationshipId, { url });
|
|
17004
|
+
await saveDocView(view, outputPath);
|
|
17005
|
+
await respond({
|
|
17006
|
+
ok: true,
|
|
17007
|
+
operation: "hyperlinks.add",
|
|
17008
|
+
path: outputPath ?? path,
|
|
17009
|
+
at: atInput,
|
|
17010
|
+
url
|
|
17011
|
+
});
|
|
16697
17012
|
return EXIT.OK;
|
|
16698
17013
|
}
|
|
16699
|
-
|
|
16700
|
-
|
|
17014
|
+
var HELP11 = `docx hyperlinks add \u2014 wrap an existing span in a hyperlink
|
|
17015
|
+
|
|
17016
|
+
Usage:
|
|
17017
|
+
docx hyperlinks add FILE --at LOCATOR --url URL [options]
|
|
17018
|
+
|
|
17019
|
+
Required:
|
|
17020
|
+
--at LOCATOR Where to wrap. Supports:
|
|
17021
|
+
pN:S-E chars S..E of pN
|
|
17022
|
+
tT:rRcC:pK:S-E chars S..E of a cell paragraph
|
|
17023
|
+
--url URL Target URL
|
|
17024
|
+
|
|
17025
|
+
Optional:
|
|
17026
|
+
-o, --output PATH Write to PATH instead of overwriting FILE
|
|
17027
|
+
--dry-run Print what would change; do not write the file
|
|
17028
|
+
-h, --help Show this help
|
|
17029
|
+
|
|
17030
|
+
The span must lie inside a single paragraph and must not overlap an existing
|
|
17031
|
+
hyperlink or a tracked-change wrapper.
|
|
17032
|
+
|
|
17033
|
+
Examples:
|
|
17034
|
+
docx hyperlinks add doc.docx --at p3:5-20 --url https://example.com
|
|
17035
|
+
`;
|
|
17036
|
+
var init_add2 = __esm(() => {
|
|
17037
|
+
init_core();
|
|
17038
|
+
init_parser();
|
|
17039
|
+
init_respond();
|
|
17040
|
+
init_wrap();
|
|
17041
|
+
});
|
|
17042
|
+
|
|
17043
|
+
// src/cli/hyperlinks/delete.ts
|
|
17044
|
+
var exports_delete3 = {};
|
|
17045
|
+
__export(exports_delete3, {
|
|
17046
|
+
run: () => run12
|
|
17047
|
+
});
|
|
17048
|
+
import { parseArgs as parseArgs11 } from "util";
|
|
17049
|
+
async function run12(args) {
|
|
17050
|
+
let parsed;
|
|
17051
|
+
try {
|
|
17052
|
+
parsed = parseArgs11({
|
|
17053
|
+
args,
|
|
17054
|
+
allowPositionals: true,
|
|
17055
|
+
options: {
|
|
17056
|
+
at: { type: "string" },
|
|
17057
|
+
output: { type: "string", short: "o" },
|
|
17058
|
+
"dry-run": { type: "boolean" },
|
|
17059
|
+
help: { type: "boolean", short: "h" }
|
|
17060
|
+
}
|
|
17061
|
+
});
|
|
17062
|
+
} catch (parseError) {
|
|
17063
|
+
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
17064
|
+
return fail("USAGE", message, HELP12);
|
|
17065
|
+
}
|
|
17066
|
+
if (parsed.values.help) {
|
|
17067
|
+
await writeStdout(HELP12);
|
|
17068
|
+
return EXIT.OK;
|
|
17069
|
+
}
|
|
17070
|
+
const path = parsed.positionals[0];
|
|
17071
|
+
if (!path)
|
|
17072
|
+
return fail("USAGE", "Missing FILE argument", HELP12);
|
|
17073
|
+
const targetId = parsed.values.at;
|
|
17074
|
+
if (!targetId)
|
|
17075
|
+
return fail("USAGE", "Missing --at LINK_ID", HELP12);
|
|
17076
|
+
const view = await openOrFail(path);
|
|
17077
|
+
if (typeof view === "number")
|
|
17078
|
+
return view;
|
|
17079
|
+
const reference = view.hyperlinkById.get(targetId);
|
|
17080
|
+
if (!reference) {
|
|
17081
|
+
return fail("HYPERLINK_NOT_FOUND", `Hyperlink not found: ${targetId}`);
|
|
17082
|
+
}
|
|
17083
|
+
const oldUrl = reference.relationshipId ? view.hyperlinksByRelationshipId.get(reference.relationshipId)?.url : undefined;
|
|
17084
|
+
const outputPath = parsed.values.output;
|
|
17085
|
+
if (parsed.values["dry-run"]) {
|
|
17086
|
+
await respond({
|
|
17087
|
+
ok: true,
|
|
17088
|
+
operation: "hyperlinks.delete",
|
|
17089
|
+
dryRun: true,
|
|
17090
|
+
path,
|
|
17091
|
+
hyperlinkId: targetId,
|
|
17092
|
+
from: oldUrl,
|
|
17093
|
+
...outputPath ? { output: outputPath } : {}
|
|
17094
|
+
});
|
|
17095
|
+
return EXIT.OK;
|
|
17096
|
+
}
|
|
17097
|
+
const index = reference.parent.indexOf(reference.node);
|
|
17098
|
+
if (index === -1) {
|
|
17099
|
+
return fail("HYPERLINK_NOT_FOUND", `Hyperlink reference is stale (parent does not contain it): ${targetId}`);
|
|
17100
|
+
}
|
|
17101
|
+
reference.parent.splice(index, 1, ...reference.node.children);
|
|
17102
|
+
view.hyperlinkById.delete(targetId);
|
|
17103
|
+
if (reference.relationshipId) {
|
|
17104
|
+
const remaining = countHyperlinkUsages(view.documentTree, reference.relationshipId);
|
|
17105
|
+
if (remaining === 0) {
|
|
17106
|
+
pruneRelationship(view.relationshipsTree, reference.relationshipId);
|
|
17107
|
+
view.hyperlinksByRelationshipId.delete(reference.relationshipId);
|
|
17108
|
+
}
|
|
17109
|
+
}
|
|
17110
|
+
await saveDocView(view, outputPath);
|
|
17111
|
+
await respond({
|
|
17112
|
+
ok: true,
|
|
17113
|
+
operation: "hyperlinks.delete",
|
|
17114
|
+
path: outputPath ?? path,
|
|
17115
|
+
hyperlinkId: targetId,
|
|
17116
|
+
from: oldUrl
|
|
17117
|
+
});
|
|
17118
|
+
return EXIT.OK;
|
|
17119
|
+
}
|
|
17120
|
+
function countHyperlinkUsages(documentTree, relationshipId) {
|
|
17121
|
+
let count = 0;
|
|
17122
|
+
for (const root of documentTree) {
|
|
17123
|
+
count += countInNode(root, relationshipId);
|
|
17124
|
+
}
|
|
17125
|
+
return count;
|
|
17126
|
+
}
|
|
17127
|
+
function countInNode(node, relationshipId) {
|
|
17128
|
+
let count = 0;
|
|
17129
|
+
if (node.tag === "w:hyperlink" && node.getAttribute("r:id") === relationshipId) {
|
|
17130
|
+
count++;
|
|
17131
|
+
}
|
|
17132
|
+
for (const child of node.children) {
|
|
17133
|
+
count += countInNode(child, relationshipId);
|
|
17134
|
+
}
|
|
17135
|
+
return count;
|
|
17136
|
+
}
|
|
17137
|
+
function pruneRelationship(relationshipsTree, relationshipId) {
|
|
17138
|
+
const relationships = XmlNode2.findRoot(relationshipsTree, "Relationships");
|
|
17139
|
+
if (!relationships)
|
|
17140
|
+
return;
|
|
17141
|
+
relationships.children = relationships.children.filter((child) => !(child.tag === "Relationship" && child.getAttribute("Id") === relationshipId));
|
|
17142
|
+
}
|
|
17143
|
+
var HELP12 = `docx hyperlinks delete \u2014 unwrap a hyperlink (keep the text)
|
|
17144
|
+
|
|
17145
|
+
Usage:
|
|
17146
|
+
docx hyperlinks delete FILE --at LINK_ID [options]
|
|
17147
|
+
|
|
17148
|
+
Required:
|
|
17149
|
+
--at LINK_ID Existing hyperlink to remove (e.g., link0)
|
|
17150
|
+
|
|
17151
|
+
Optional:
|
|
17152
|
+
-o, --output PATH Write to PATH instead of overwriting FILE
|
|
17153
|
+
--dry-run Print what would change; do not write the file
|
|
17154
|
+
-h, --help Show this help
|
|
17155
|
+
|
|
17156
|
+
The display text stays in place; only the <w:hyperlink> wrapper is removed.
|
|
17157
|
+
If the underlying relationship is no longer referenced, it is pruned from the
|
|
17158
|
+
rels file too.
|
|
17159
|
+
|
|
17160
|
+
Examples:
|
|
17161
|
+
docx hyperlinks delete doc.docx --at link0
|
|
17162
|
+
`;
|
|
17163
|
+
var init_delete3 = __esm(() => {
|
|
17164
|
+
init_core();
|
|
17165
|
+
init_parser();
|
|
17166
|
+
init_respond();
|
|
17167
|
+
});
|
|
17168
|
+
|
|
17169
|
+
// src/cli/hyperlinks/list.ts
|
|
17170
|
+
var exports_list2 = {};
|
|
17171
|
+
__export(exports_list2, {
|
|
17172
|
+
run: () => run13
|
|
17173
|
+
});
|
|
17174
|
+
import { parseArgs as parseArgs12 } from "util";
|
|
17175
|
+
async function run13(args) {
|
|
17176
|
+
let parsed;
|
|
17177
|
+
try {
|
|
17178
|
+
parsed = parseArgs12({
|
|
17179
|
+
args,
|
|
17180
|
+
allowPositionals: true,
|
|
17181
|
+
options: {
|
|
17182
|
+
help: { type: "boolean", short: "h" }
|
|
17183
|
+
}
|
|
17184
|
+
});
|
|
17185
|
+
} catch (parseError) {
|
|
17186
|
+
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
17187
|
+
return fail("USAGE", message, HELP13);
|
|
17188
|
+
}
|
|
17189
|
+
if (parsed.values.help) {
|
|
17190
|
+
await writeStdout(HELP13);
|
|
17191
|
+
return EXIT.OK;
|
|
17192
|
+
}
|
|
17193
|
+
const path = parsed.positionals[0];
|
|
17194
|
+
if (!path)
|
|
17195
|
+
return fail("USAGE", "Missing FILE argument", HELP13);
|
|
17196
|
+
const view = await openOrFail(path);
|
|
17197
|
+
if (typeof view === "number")
|
|
17198
|
+
return view;
|
|
17199
|
+
const entries = new Map;
|
|
17200
|
+
collectHyperlinks(view.doc.blocks, entries);
|
|
17201
|
+
await respond([...entries.values()]);
|
|
17202
|
+
return EXIT.OK;
|
|
17203
|
+
}
|
|
17204
|
+
function collectHyperlinks(blocks, entries) {
|
|
17205
|
+
for (const block of blocks) {
|
|
16701
17206
|
if (block.type === "paragraph") {
|
|
16702
|
-
for (const
|
|
16703
|
-
if (
|
|
16704
|
-
|
|
17207
|
+
for (const run14 of block.runs) {
|
|
17208
|
+
if (run14.type !== "text" || !run14.hyperlink)
|
|
17209
|
+
continue;
|
|
17210
|
+
addToEntry(entries, run14.hyperlink, block.id, run14.text);
|
|
17211
|
+
}
|
|
17212
|
+
continue;
|
|
17213
|
+
}
|
|
17214
|
+
if (block.type === "table") {
|
|
17215
|
+
for (const row of block.rows) {
|
|
17216
|
+
for (const cell of row.cells) {
|
|
17217
|
+
collectHyperlinks(cell.blocks, entries);
|
|
17218
|
+
}
|
|
17219
|
+
}
|
|
17220
|
+
}
|
|
17221
|
+
}
|
|
17222
|
+
}
|
|
17223
|
+
function addToEntry(entries, hyperlink, blockId, text) {
|
|
17224
|
+
const existing = entries.get(hyperlink.id);
|
|
17225
|
+
if (existing) {
|
|
17226
|
+
existing.text += text;
|
|
17227
|
+
return;
|
|
17228
|
+
}
|
|
17229
|
+
const entry = {
|
|
17230
|
+
id: hyperlink.id,
|
|
17231
|
+
text,
|
|
17232
|
+
blockId
|
|
17233
|
+
};
|
|
17234
|
+
if (hyperlink.url)
|
|
17235
|
+
entry.url = hyperlink.url;
|
|
17236
|
+
if (hyperlink.anchor)
|
|
17237
|
+
entry.anchor = hyperlink.anchor;
|
|
17238
|
+
if (hyperlink.tooltip)
|
|
17239
|
+
entry.tooltip = hyperlink.tooltip;
|
|
17240
|
+
entries.set(hyperlink.id, entry);
|
|
17241
|
+
}
|
|
17242
|
+
var HELP13 = `docx hyperlinks list \u2014 print hyperlink manifest as JSON
|
|
17243
|
+
|
|
17244
|
+
Usage:
|
|
17245
|
+
docx hyperlinks list FILE [options]
|
|
17246
|
+
|
|
17247
|
+
Options:
|
|
17248
|
+
-h, --help Show this help
|
|
17249
|
+
|
|
17250
|
+
Each entry has: id, url (or anchor), tooltip (if set), text (display text),
|
|
17251
|
+
and blockId (the paragraph containing the link).
|
|
17252
|
+
|
|
17253
|
+
Examples:
|
|
17254
|
+
docx hyperlinks list doc.docx | jq -c '.[] | {id, url, text}'
|
|
17255
|
+
`;
|
|
17256
|
+
var init_list2 = __esm(() => {
|
|
17257
|
+
init_respond();
|
|
17258
|
+
});
|
|
17259
|
+
|
|
17260
|
+
// src/cli/hyperlinks/replace.ts
|
|
17261
|
+
var exports_replace = {};
|
|
17262
|
+
__export(exports_replace, {
|
|
17263
|
+
run: () => run14
|
|
17264
|
+
});
|
|
17265
|
+
import { parseArgs as parseArgs13 } from "util";
|
|
17266
|
+
async function run14(args) {
|
|
17267
|
+
let parsed;
|
|
17268
|
+
try {
|
|
17269
|
+
parsed = parseArgs13({
|
|
17270
|
+
args,
|
|
17271
|
+
allowPositionals: true,
|
|
17272
|
+
options: {
|
|
17273
|
+
at: { type: "string" },
|
|
17274
|
+
with: { type: "string" },
|
|
17275
|
+
output: { type: "string", short: "o" },
|
|
17276
|
+
"dry-run": { type: "boolean" },
|
|
17277
|
+
help: { type: "boolean", short: "h" }
|
|
17278
|
+
}
|
|
17279
|
+
});
|
|
17280
|
+
} catch (parseError) {
|
|
17281
|
+
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
17282
|
+
return fail("USAGE", message, HELP14);
|
|
17283
|
+
}
|
|
17284
|
+
if (parsed.values.help) {
|
|
17285
|
+
await writeStdout(HELP14);
|
|
17286
|
+
return EXIT.OK;
|
|
17287
|
+
}
|
|
17288
|
+
const path = parsed.positionals[0];
|
|
17289
|
+
if (!path)
|
|
17290
|
+
return fail("USAGE", "Missing FILE argument", HELP14);
|
|
17291
|
+
const targetId = parsed.values.at;
|
|
17292
|
+
if (!targetId)
|
|
17293
|
+
return fail("USAGE", "Missing --at LINK_ID", HELP14);
|
|
17294
|
+
const newUrl = parsed.values.with;
|
|
17295
|
+
if (!newUrl)
|
|
17296
|
+
return fail("USAGE", "Missing --with URL", HELP14);
|
|
17297
|
+
const view = await openOrFail(path);
|
|
17298
|
+
if (typeof view === "number")
|
|
17299
|
+
return view;
|
|
17300
|
+
const reference = view.hyperlinkById.get(targetId);
|
|
17301
|
+
if (!reference) {
|
|
17302
|
+
return fail("HYPERLINK_NOT_FOUND", `Hyperlink not found: ${targetId}`);
|
|
17303
|
+
}
|
|
17304
|
+
const relationships = XmlNode2.findRoot(view.relationshipsTree, "Relationships");
|
|
17305
|
+
if (!relationships) {
|
|
17306
|
+
return fail("UNHANDLED", "Missing <Relationships> root in document rels");
|
|
17307
|
+
}
|
|
17308
|
+
const existingId = reference.relationshipId;
|
|
17309
|
+
const oldUrl = existingId ? view.hyperlinksByRelationshipId.get(existingId)?.url : undefined;
|
|
17310
|
+
const sharedCount = existingId ? countHyperlinkUsages2(view.documentTree, existingId) : 0;
|
|
17311
|
+
const willAllocateNew = !existingId || sharedCount > 1;
|
|
17312
|
+
const outputPath = parsed.values.output;
|
|
17313
|
+
if (parsed.values["dry-run"]) {
|
|
17314
|
+
await respond({
|
|
17315
|
+
ok: true,
|
|
17316
|
+
operation: "hyperlinks.replace",
|
|
17317
|
+
dryRun: true,
|
|
17318
|
+
path,
|
|
17319
|
+
hyperlinkId: targetId,
|
|
17320
|
+
from: oldUrl,
|
|
17321
|
+
to: newUrl,
|
|
17322
|
+
sharedRelationship: sharedCount > 1,
|
|
17323
|
+
...outputPath ? { output: outputPath } : {}
|
|
17324
|
+
});
|
|
17325
|
+
return EXIT.OK;
|
|
17326
|
+
}
|
|
17327
|
+
if (willAllocateNew) {
|
|
17328
|
+
const newRelationshipId = addHyperlinkRelationship(relationships, newUrl);
|
|
17329
|
+
reference.node.setAttribute("r:id", newRelationshipId);
|
|
17330
|
+
reference.relationshipId = newRelationshipId;
|
|
17331
|
+
view.hyperlinksByRelationshipId.set(newRelationshipId, { url: newUrl });
|
|
17332
|
+
} else if (existingId) {
|
|
17333
|
+
updateRelationshipTarget(relationships, existingId, newUrl);
|
|
17334
|
+
view.hyperlinksByRelationshipId.set(existingId, { url: newUrl });
|
|
17335
|
+
}
|
|
17336
|
+
await saveDocView(view, outputPath);
|
|
17337
|
+
await respond({
|
|
17338
|
+
ok: true,
|
|
17339
|
+
operation: "hyperlinks.replace",
|
|
17340
|
+
path: outputPath ?? path,
|
|
17341
|
+
hyperlinkId: targetId,
|
|
17342
|
+
from: oldUrl,
|
|
17343
|
+
to: newUrl
|
|
17344
|
+
});
|
|
17345
|
+
return EXIT.OK;
|
|
17346
|
+
}
|
|
17347
|
+
function updateRelationshipTarget(relationships, relationshipId, newTarget) {
|
|
17348
|
+
for (const child of relationships.children) {
|
|
17349
|
+
if (child.tag !== "Relationship")
|
|
17350
|
+
continue;
|
|
17351
|
+
if (child.getAttribute("Id") === relationshipId) {
|
|
17352
|
+
child.setAttribute("Target", newTarget);
|
|
17353
|
+
return;
|
|
17354
|
+
}
|
|
17355
|
+
}
|
|
17356
|
+
}
|
|
17357
|
+
function countHyperlinkUsages2(documentTree, relationshipId) {
|
|
17358
|
+
let count = 0;
|
|
17359
|
+
for (const root of documentTree) {
|
|
17360
|
+
count += countInNode2(root, relationshipId);
|
|
17361
|
+
}
|
|
17362
|
+
return count;
|
|
17363
|
+
}
|
|
17364
|
+
function countInNode2(node, relationshipId) {
|
|
17365
|
+
let count = 0;
|
|
17366
|
+
if (node.tag === "w:hyperlink" && node.getAttribute("r:id") === relationshipId) {
|
|
17367
|
+
count++;
|
|
17368
|
+
}
|
|
17369
|
+
for (const child of node.children) {
|
|
17370
|
+
count += countInNode2(child, relationshipId);
|
|
17371
|
+
}
|
|
17372
|
+
return count;
|
|
17373
|
+
}
|
|
17374
|
+
var HELP14 = `docx hyperlinks replace \u2014 change a hyperlink's URL
|
|
17375
|
+
|
|
17376
|
+
Usage:
|
|
17377
|
+
docx hyperlinks replace FILE --at LINK_ID --with URL [options]
|
|
17378
|
+
|
|
17379
|
+
Required:
|
|
17380
|
+
--at LINK_ID Existing hyperlink to update (e.g., link0)
|
|
17381
|
+
--with URL New target URL
|
|
17382
|
+
|
|
17383
|
+
Optional:
|
|
17384
|
+
-o, --output PATH Write to PATH instead of overwriting FILE
|
|
17385
|
+
--dry-run Print what would change; do not write the file
|
|
17386
|
+
-h, --help Show this help
|
|
17387
|
+
|
|
17388
|
+
Replaces only the targeted hyperlink. If multiple hyperlinks shared the same
|
|
17389
|
+
underlying relationship, a new relationship is allocated so the others are
|
|
17390
|
+
unaffected.
|
|
17391
|
+
|
|
17392
|
+
Examples:
|
|
17393
|
+
docx hyperlinks replace doc.docx --at link0 --with https://example.com
|
|
17394
|
+
`;
|
|
17395
|
+
var init_replace = __esm(() => {
|
|
17396
|
+
init_core();
|
|
17397
|
+
init_parser();
|
|
17398
|
+
init_respond();
|
|
17399
|
+
});
|
|
17400
|
+
|
|
17401
|
+
// src/cli/hyperlinks/index.ts
|
|
17402
|
+
var exports_hyperlinks = {};
|
|
17403
|
+
__export(exports_hyperlinks, {
|
|
17404
|
+
run: () => run15
|
|
17405
|
+
});
|
|
17406
|
+
async function run15(args) {
|
|
17407
|
+
const verb = args[0];
|
|
17408
|
+
if (!verb || verb === "--help" || verb === "-h" || verb === "help") {
|
|
17409
|
+
await writeStdout(HELP15);
|
|
17410
|
+
return verb ? 0 : 2;
|
|
17411
|
+
}
|
|
17412
|
+
const loader = SUBCOMMANDS2[verb];
|
|
17413
|
+
if (!loader) {
|
|
17414
|
+
return fail("USAGE", `Unknown hyperlinks subcommand: ${verb}`, 'Run "docx hyperlinks --help".');
|
|
17415
|
+
}
|
|
17416
|
+
const module_ = await loader();
|
|
17417
|
+
return module_.run(args.slice(1));
|
|
17418
|
+
}
|
|
17419
|
+
var SUBCOMMANDS2, HELP15 = `docx hyperlinks \u2014 manage hyperlinks
|
|
17420
|
+
|
|
17421
|
+
Usage:
|
|
17422
|
+
docx hyperlinks <verb> FILE [options]
|
|
17423
|
+
|
|
17424
|
+
Verbs:
|
|
17425
|
+
add Wrap an existing span in a hyperlink
|
|
17426
|
+
delete Unwrap a hyperlink (keep the text)
|
|
17427
|
+
list Print hyperlink manifest as JSON
|
|
17428
|
+
replace Change a hyperlink's URL
|
|
17429
|
+
|
|
17430
|
+
Run "docx hyperlinks <verb> --help" for verb-specific help.
|
|
17431
|
+
`;
|
|
17432
|
+
var init_hyperlinks = __esm(() => {
|
|
17433
|
+
init_respond();
|
|
17434
|
+
SUBCOMMANDS2 = {
|
|
17435
|
+
add: () => Promise.resolve().then(() => (init_add2(), exports_add2)),
|
|
17436
|
+
delete: () => Promise.resolve().then(() => (init_delete3(), exports_delete3)),
|
|
17437
|
+
list: () => Promise.resolve().then(() => (init_list2(), exports_list2)),
|
|
17438
|
+
replace: () => Promise.resolve().then(() => (init_replace(), exports_replace))
|
|
17439
|
+
};
|
|
17440
|
+
});
|
|
17441
|
+
|
|
17442
|
+
// src/cli/images/extract.ts
|
|
17443
|
+
var exports_extract = {};
|
|
17444
|
+
__export(exports_extract, {
|
|
17445
|
+
run: () => run16
|
|
17446
|
+
});
|
|
17447
|
+
import { join } from "path";
|
|
17448
|
+
import { parseArgs as parseArgs14 } from "util";
|
|
17449
|
+
async function run16(args) {
|
|
17450
|
+
let parsed;
|
|
17451
|
+
try {
|
|
17452
|
+
parsed = parseArgs14({
|
|
17453
|
+
args,
|
|
17454
|
+
allowPositionals: true,
|
|
17455
|
+
options: {
|
|
17456
|
+
to: { type: "string" },
|
|
17457
|
+
id: { type: "string" },
|
|
17458
|
+
help: { type: "boolean", short: "h" }
|
|
17459
|
+
}
|
|
17460
|
+
});
|
|
17461
|
+
} catch (parseError) {
|
|
17462
|
+
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
17463
|
+
return fail("USAGE", message, HELP16);
|
|
17464
|
+
}
|
|
17465
|
+
if (parsed.values.help) {
|
|
17466
|
+
await writeStdout(HELP16);
|
|
17467
|
+
return EXIT.OK;
|
|
17468
|
+
}
|
|
17469
|
+
const path = parsed.positionals[0];
|
|
17470
|
+
if (!path)
|
|
17471
|
+
return fail("USAGE", "Missing FILE argument", HELP16);
|
|
17472
|
+
const outputDir = parsed.values.to;
|
|
17473
|
+
if (!outputDir)
|
|
17474
|
+
return fail("USAGE", "Missing --to DIR", HELP16);
|
|
17475
|
+
const targetId = parsed.values.id;
|
|
17476
|
+
const view = await openOrFail(path);
|
|
17477
|
+
if (typeof view === "number")
|
|
17478
|
+
return view;
|
|
17479
|
+
await enrichImageHashes(view);
|
|
17480
|
+
const allImages = [];
|
|
17481
|
+
collectImages(view.doc.blocks, allImages);
|
|
17482
|
+
const targets = targetId ? allImages.filter((image) => image.id === targetId) : allImages;
|
|
17483
|
+
if (targetId && targets.length === 0) {
|
|
17484
|
+
return fail("IMAGE_NOT_FOUND", `Image not found: ${targetId}`);
|
|
17485
|
+
}
|
|
17486
|
+
const manifest = [];
|
|
17487
|
+
const seenHashes = new Set;
|
|
17488
|
+
for (const image of targets) {
|
|
17489
|
+
const reference = view.imageById.get(image.id);
|
|
17490
|
+
if (!reference)
|
|
17491
|
+
continue;
|
|
17492
|
+
const extension = extensionFor(image.contentType, reference.partName);
|
|
17493
|
+
const fileName = `${image.hash}.${extension}`;
|
|
17494
|
+
const outputPath = join(outputDir, fileName);
|
|
17495
|
+
if (!seenHashes.has(image.hash)) {
|
|
17496
|
+
const bytes = await view.pkg.readBytes(reference.partName);
|
|
17497
|
+
await Bun.write(outputPath, bytes);
|
|
17498
|
+
seenHashes.add(image.hash);
|
|
17499
|
+
}
|
|
17500
|
+
manifest.push({
|
|
17501
|
+
id: image.id,
|
|
17502
|
+
path: outputPath,
|
|
17503
|
+
bytes: (await Bun.file(outputPath).arrayBuffer()).byteLength
|
|
17504
|
+
});
|
|
17505
|
+
}
|
|
17506
|
+
await respond({ ok: true, operation: "images.extract", path, manifest });
|
|
17507
|
+
return EXIT.OK;
|
|
17508
|
+
}
|
|
17509
|
+
function collectImages(blocks, out) {
|
|
17510
|
+
for (const block of blocks) {
|
|
17511
|
+
if (block.type === "paragraph") {
|
|
17512
|
+
for (const run17 of block.runs) {
|
|
17513
|
+
if (run17.type === "image")
|
|
17514
|
+
out.push(run17);
|
|
16705
17515
|
}
|
|
16706
17516
|
continue;
|
|
16707
17517
|
}
|
|
@@ -16721,7 +17531,7 @@ function extensionFor(contentType, partName) {
|
|
|
16721
17531
|
const fromName = partName.split(".").pop()?.toLowerCase();
|
|
16722
17532
|
return fromName ?? "bin";
|
|
16723
17533
|
}
|
|
16724
|
-
var
|
|
17534
|
+
var HELP16 = `docx images extract \u2014 dump image bytes to a directory
|
|
16725
17535
|
|
|
16726
17536
|
Usage:
|
|
16727
17537
|
docx images extract FILE --to DIR [options]
|
|
@@ -16760,15 +17570,15 @@ var init_extract = __esm(() => {
|
|
|
16760
17570
|
});
|
|
16761
17571
|
|
|
16762
17572
|
// src/cli/images/list.ts
|
|
16763
|
-
var
|
|
16764
|
-
__export(
|
|
16765
|
-
run: () =>
|
|
17573
|
+
var exports_list3 = {};
|
|
17574
|
+
__export(exports_list3, {
|
|
17575
|
+
run: () => run17
|
|
16766
17576
|
});
|
|
16767
|
-
import { parseArgs as
|
|
16768
|
-
async function
|
|
17577
|
+
import { parseArgs as parseArgs15 } from "util";
|
|
17578
|
+
async function run17(args) {
|
|
16769
17579
|
let parsed;
|
|
16770
17580
|
try {
|
|
16771
|
-
parsed =
|
|
17581
|
+
parsed = parseArgs15({
|
|
16772
17582
|
args,
|
|
16773
17583
|
allowPositionals: true,
|
|
16774
17584
|
options: {
|
|
@@ -16777,15 +17587,15 @@ async function run12(args) {
|
|
|
16777
17587
|
});
|
|
16778
17588
|
} catch (parseError) {
|
|
16779
17589
|
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
16780
|
-
return fail("USAGE", message,
|
|
17590
|
+
return fail("USAGE", message, HELP17);
|
|
16781
17591
|
}
|
|
16782
17592
|
if (parsed.values.help) {
|
|
16783
|
-
await writeStdout(
|
|
17593
|
+
await writeStdout(HELP17);
|
|
16784
17594
|
return EXIT.OK;
|
|
16785
17595
|
}
|
|
16786
17596
|
const path = parsed.positionals[0];
|
|
16787
17597
|
if (!path)
|
|
16788
|
-
return fail("USAGE", "Missing FILE argument",
|
|
17598
|
+
return fail("USAGE", "Missing FILE argument", HELP17);
|
|
16789
17599
|
const view = await openOrFail(path);
|
|
16790
17600
|
if (typeof view === "number")
|
|
16791
17601
|
return view;
|
|
@@ -16798,9 +17608,9 @@ async function run12(args) {
|
|
|
16798
17608
|
function collectImages2(blocks, out) {
|
|
16799
17609
|
for (const block of blocks) {
|
|
16800
17610
|
if (block.type === "paragraph") {
|
|
16801
|
-
for (const
|
|
16802
|
-
if (
|
|
16803
|
-
out.push(
|
|
17611
|
+
for (const run18 of block.runs) {
|
|
17612
|
+
if (run18.type === "image")
|
|
17613
|
+
out.push(run18);
|
|
16804
17614
|
}
|
|
16805
17615
|
continue;
|
|
16806
17616
|
}
|
|
@@ -16813,7 +17623,7 @@ function collectImages2(blocks, out) {
|
|
|
16813
17623
|
}
|
|
16814
17624
|
}
|
|
16815
17625
|
}
|
|
16816
|
-
var
|
|
17626
|
+
var HELP17 = `docx images list \u2014 print image manifest as JSON
|
|
16817
17627
|
|
|
16818
17628
|
Usage:
|
|
16819
17629
|
docx images list FILE [options]
|
|
@@ -16824,21 +17634,21 @@ Options:
|
|
|
16824
17634
|
Examples:
|
|
16825
17635
|
docx images list doc.docx | jq -c '.[] | {id, contentType, hash}'
|
|
16826
17636
|
`;
|
|
16827
|
-
var
|
|
17637
|
+
var init_list3 = __esm(() => {
|
|
16828
17638
|
init_core();
|
|
16829
17639
|
init_respond();
|
|
16830
17640
|
});
|
|
16831
17641
|
|
|
16832
17642
|
// src/cli/images/replace.ts
|
|
16833
|
-
var
|
|
16834
|
-
__export(
|
|
16835
|
-
run: () =>
|
|
17643
|
+
var exports_replace2 = {};
|
|
17644
|
+
__export(exports_replace2, {
|
|
17645
|
+
run: () => run18
|
|
16836
17646
|
});
|
|
16837
|
-
import { parseArgs as
|
|
16838
|
-
async function
|
|
17647
|
+
import { parseArgs as parseArgs16 } from "util";
|
|
17648
|
+
async function run18(args) {
|
|
16839
17649
|
let parsed;
|
|
16840
17650
|
try {
|
|
16841
|
-
parsed =
|
|
17651
|
+
parsed = parseArgs16({
|
|
16842
17652
|
args,
|
|
16843
17653
|
allowPositionals: true,
|
|
16844
17654
|
options: {
|
|
@@ -16851,21 +17661,21 @@ async function run13(args) {
|
|
|
16851
17661
|
});
|
|
16852
17662
|
} catch (parseError) {
|
|
16853
17663
|
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
16854
|
-
return fail("USAGE", message,
|
|
17664
|
+
return fail("USAGE", message, HELP18);
|
|
16855
17665
|
}
|
|
16856
17666
|
if (parsed.values.help) {
|
|
16857
|
-
await writeStdout(
|
|
17667
|
+
await writeStdout(HELP18);
|
|
16858
17668
|
return EXIT.OK;
|
|
16859
17669
|
}
|
|
16860
17670
|
const path = parsed.positionals[0];
|
|
16861
17671
|
if (!path)
|
|
16862
|
-
return fail("USAGE", "Missing FILE argument",
|
|
17672
|
+
return fail("USAGE", "Missing FILE argument", HELP18);
|
|
16863
17673
|
const targetId = parsed.values.at;
|
|
16864
17674
|
if (!targetId)
|
|
16865
|
-
return fail("USAGE", "Missing --at IMG_ID",
|
|
17675
|
+
return fail("USAGE", "Missing --at IMG_ID", HELP18);
|
|
16866
17676
|
const sourcePath = parsed.values.with;
|
|
16867
17677
|
if (!sourcePath)
|
|
16868
|
-
return fail("USAGE", "Missing --with PATH",
|
|
17678
|
+
return fail("USAGE", "Missing --with PATH", HELP18);
|
|
16869
17679
|
const sourceFile = Bun.file(sourcePath);
|
|
16870
17680
|
if (!await sourceFile.exists()) {
|
|
16871
17681
|
return fail("FILE_NOT_FOUND", `Replacement file not found: ${sourcePath}`);
|
|
@@ -16904,7 +17714,7 @@ async function run13(args) {
|
|
|
16904
17714
|
} else {
|
|
16905
17715
|
view.pkg.writeBytes(newPartName, bytes);
|
|
16906
17716
|
view.pkg.deletePart(originalPartName);
|
|
16907
|
-
|
|
17717
|
+
updateRelationshipTarget2(view.relationshipsTree, reference.relationshipId, relativeTargetFor(newPartName));
|
|
16908
17718
|
ensureContentTypeDefault(view.contentTypesTree, newExtension, newMimeType);
|
|
16909
17719
|
reference.partName = newPartName;
|
|
16910
17720
|
reference.contentType = newMimeType;
|
|
@@ -16932,7 +17742,7 @@ function renameExtension(partName, newExtension) {
|
|
|
16932
17742
|
function relativeTargetFor(partName) {
|
|
16933
17743
|
return partName.startsWith("word/") ? partName.slice("word/".length) : partName;
|
|
16934
17744
|
}
|
|
16935
|
-
function
|
|
17745
|
+
function updateRelationshipTarget2(relationshipsTree, relationshipId, newTarget) {
|
|
16936
17746
|
const relationships = XmlNode2.findRoot(relationshipsTree, "Relationships");
|
|
16937
17747
|
if (!relationships)
|
|
16938
17748
|
return;
|
|
@@ -16957,7 +17767,7 @@ function ensureContentTypeDefault(contentTypesTree, extension, mimeType) {
|
|
|
16957
17767
|
}
|
|
16958
17768
|
types.children.push(new XmlNode2("Default", { Extension: extension, ContentType: mimeType }));
|
|
16959
17769
|
}
|
|
16960
|
-
var
|
|
17770
|
+
var HELP18 = `docx images replace \u2014 swap an image's bytes
|
|
16961
17771
|
|
|
16962
17772
|
Usage:
|
|
16963
17773
|
docx images replace FILE --at IMG_ID --with PATH [options]
|
|
@@ -16979,7 +17789,7 @@ Examples:
|
|
|
16979
17789
|
docx images replace doc.docx --at img2 --with ./new-photo.png
|
|
16980
17790
|
docx images replace doc.docx --at img0 --with ./diagram.svg
|
|
16981
17791
|
`, EXTENSION_BY_MIME;
|
|
16982
|
-
var
|
|
17792
|
+
var init_replace2 = __esm(() => {
|
|
16983
17793
|
init_core();
|
|
16984
17794
|
init_parser();
|
|
16985
17795
|
init_respond();
|
|
@@ -17000,22 +17810,22 @@ var init_replace = __esm(() => {
|
|
|
17000
17810
|
// src/cli/images/index.ts
|
|
17001
17811
|
var exports_images = {};
|
|
17002
17812
|
__export(exports_images, {
|
|
17003
|
-
run: () =>
|
|
17813
|
+
run: () => run19
|
|
17004
17814
|
});
|
|
17005
|
-
async function
|
|
17815
|
+
async function run19(args) {
|
|
17006
17816
|
const verb = args[0];
|
|
17007
17817
|
if (!verb || verb === "--help" || verb === "-h" || verb === "help") {
|
|
17008
|
-
await writeStdout(
|
|
17818
|
+
await writeStdout(HELP19);
|
|
17009
17819
|
return verb ? 0 : 2;
|
|
17010
17820
|
}
|
|
17011
|
-
const loader =
|
|
17821
|
+
const loader = SUBCOMMANDS3[verb];
|
|
17012
17822
|
if (!loader) {
|
|
17013
17823
|
return fail("USAGE", `Unknown images subcommand: ${verb}`, 'Run "docx images --help".');
|
|
17014
17824
|
}
|
|
17015
17825
|
const module_ = await loader();
|
|
17016
17826
|
return module_.run(args.slice(1));
|
|
17017
17827
|
}
|
|
17018
|
-
var
|
|
17828
|
+
var SUBCOMMANDS3, HELP19 = `docx images \u2014 manage embedded images
|
|
17019
17829
|
|
|
17020
17830
|
Usage:
|
|
17021
17831
|
docx images <verb> FILE [options]
|
|
@@ -17029,10 +17839,10 @@ Run "docx images <verb> --help" for verb-specific help.
|
|
|
17029
17839
|
`;
|
|
17030
17840
|
var init_images = __esm(() => {
|
|
17031
17841
|
init_respond();
|
|
17032
|
-
|
|
17842
|
+
SUBCOMMANDS3 = {
|
|
17033
17843
|
extract: () => Promise.resolve().then(() => (init_extract(), exports_extract)),
|
|
17034
|
-
list: () => Promise.resolve().then(() => (
|
|
17035
|
-
replace: () => Promise.resolve().then(() => (
|
|
17844
|
+
list: () => Promise.resolve().then(() => (init_list3(), exports_list3)),
|
|
17845
|
+
replace: () => Promise.resolve().then(() => (init_replace2(), exports_replace2))
|
|
17036
17846
|
};
|
|
17037
17847
|
});
|
|
17038
17848
|
|
|
@@ -17043,6 +17853,8 @@ var types_default = `export type Doc = {
|
|
|
17043
17853
|
properties: DocProperties;
|
|
17044
17854
|
blocks: Block[];
|
|
17045
17855
|
comments: Comment[];
|
|
17856
|
+
footnotes: Footnote[];
|
|
17857
|
+
endnotes: Footnote[];
|
|
17046
17858
|
};
|
|
17047
17859
|
|
|
17048
17860
|
export type DocProperties = {
|
|
@@ -17082,7 +17894,14 @@ export type SectionBreak = {
|
|
|
17082
17894
|
type: "sectionBreak";
|
|
17083
17895
|
};
|
|
17084
17896
|
|
|
17085
|
-
export type Run =
|
|
17897
|
+
export type Run =
|
|
17898
|
+
| TextRun
|
|
17899
|
+
| ImageRun
|
|
17900
|
+
| BreakRun
|
|
17901
|
+
| TabRun
|
|
17902
|
+
| EquationRun
|
|
17903
|
+
| FootnoteRefRun
|
|
17904
|
+
| ChartRun;
|
|
17086
17905
|
|
|
17087
17906
|
export type TextRun = {
|
|
17088
17907
|
type: "text";
|
|
@@ -17097,6 +17916,14 @@ export type TextRun = {
|
|
|
17097
17916
|
sizeHalfPoints?: number;
|
|
17098
17917
|
comments?: string[];
|
|
17099
17918
|
trackedChange?: TrackedChange;
|
|
17919
|
+
hyperlink?: Hyperlink;
|
|
17920
|
+
};
|
|
17921
|
+
|
|
17922
|
+
export type Hyperlink = {
|
|
17923
|
+
id: string;
|
|
17924
|
+
url?: string;
|
|
17925
|
+
anchor?: string;
|
|
17926
|
+
tooltip?: string;
|
|
17100
17927
|
};
|
|
17101
17928
|
|
|
17102
17929
|
export type ImageRun = {
|
|
@@ -17118,6 +17945,37 @@ export type TabRun = {
|
|
|
17118
17945
|
type: "tab";
|
|
17119
17946
|
};
|
|
17120
17947
|
|
|
17948
|
+
/** A math equation surfaced as concatenated <m:t> plaintext. The structural
|
|
17949
|
+
* OOMath markup (subscripts, fractions, etc.) is collapsed to literal characters,
|
|
17950
|
+
* so the rendering is degraded. \`display\` distinguishes inline equations
|
|
17951
|
+
* (<m:oMath>) from block-level display equations (<m:oMathPara>). */
|
|
17952
|
+
export type EquationRun = {
|
|
17953
|
+
type: "equation";
|
|
17954
|
+
text: string;
|
|
17955
|
+
display: boolean;
|
|
17956
|
+
};
|
|
17957
|
+
|
|
17958
|
+
/** Reference to a footnote or endnote whose body lives in Doc.footnotes or
|
|
17959
|
+
* Doc.endnotes. The id matches the footnote/endnote id (\`fn1\`, \`en1\`). */
|
|
17960
|
+
export type FootnoteRefRun = {
|
|
17961
|
+
type: "footnoteRef";
|
|
17962
|
+
kind: "footnote" | "endnote";
|
|
17963
|
+
id: string;
|
|
17964
|
+
};
|
|
17965
|
+
|
|
17966
|
+
/** Placeholder for a non-picture drawing (chart, shape, SmartArt, etc.). The
|
|
17967
|
+
* full content is preserved in the underlying XML; the run is a marker so
|
|
17968
|
+
* callers can know "something visual lives here." */
|
|
17969
|
+
export type ChartRun = {
|
|
17970
|
+
type: "chart";
|
|
17971
|
+
kind: "chart" | "shape" | "smartart" | "drawing";
|
|
17972
|
+
};
|
|
17973
|
+
|
|
17974
|
+
export type Footnote = {
|
|
17975
|
+
id: string;
|
|
17976
|
+
text: string;
|
|
17977
|
+
};
|
|
17978
|
+
|
|
17121
17979
|
export type TrackedChange = {
|
|
17122
17980
|
kind: "ins" | "del";
|
|
17123
17981
|
author: string;
|
|
@@ -17148,13 +18006,13 @@ var init_types = () => {};
|
|
|
17148
18006
|
// src/cli/info/schema.ts
|
|
17149
18007
|
var exports_schema = {};
|
|
17150
18008
|
__export(exports_schema, {
|
|
17151
|
-
run: () =>
|
|
18009
|
+
run: () => run20
|
|
17152
18010
|
});
|
|
17153
|
-
import { parseArgs as
|
|
17154
|
-
async function
|
|
18011
|
+
import { parseArgs as parseArgs17 } from "util";
|
|
18012
|
+
async function run20(args) {
|
|
17155
18013
|
let parsed;
|
|
17156
18014
|
try {
|
|
17157
|
-
parsed =
|
|
18015
|
+
parsed = parseArgs17({
|
|
17158
18016
|
args,
|
|
17159
18017
|
allowPositionals: true,
|
|
17160
18018
|
options: {
|
|
@@ -17165,10 +18023,10 @@ async function run15(args) {
|
|
|
17165
18023
|
});
|
|
17166
18024
|
} catch (parseError) {
|
|
17167
18025
|
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
17168
|
-
return fail("USAGE", message,
|
|
18026
|
+
return fail("USAGE", message, HELP20);
|
|
17169
18027
|
}
|
|
17170
18028
|
if (parsed.values.help) {
|
|
17171
|
-
await writeStdout(
|
|
18029
|
+
await writeStdout(HELP20);
|
|
17172
18030
|
return EXIT.OK;
|
|
17173
18031
|
}
|
|
17174
18032
|
if (parsed.values.ts) {
|
|
@@ -17178,7 +18036,7 @@ async function run15(args) {
|
|
|
17178
18036
|
await respond(JSON_SCHEMA);
|
|
17179
18037
|
return EXIT.OK;
|
|
17180
18038
|
}
|
|
17181
|
-
var
|
|
18039
|
+
var HELP20 = `docx schema \u2014 print the AST type definitions
|
|
17182
18040
|
|
|
17183
18041
|
Usage:
|
|
17184
18042
|
docx schema [options]
|
|
@@ -17200,7 +18058,15 @@ var init_schema = __esm(() => {
|
|
|
17200
18058
|
$id: "https://github.com/kklimuk/docx-cli/schema",
|
|
17201
18059
|
title: "docx-cli AST",
|
|
17202
18060
|
type: "object",
|
|
17203
|
-
required: [
|
|
18061
|
+
required: [
|
|
18062
|
+
"schemaVersion",
|
|
18063
|
+
"path",
|
|
18064
|
+
"properties",
|
|
18065
|
+
"blocks",
|
|
18066
|
+
"comments",
|
|
18067
|
+
"footnotes",
|
|
18068
|
+
"endnotes"
|
|
18069
|
+
],
|
|
17204
18070
|
properties: {
|
|
17205
18071
|
schemaVersion: { const: 1 },
|
|
17206
18072
|
path: { type: "string" },
|
|
@@ -17214,7 +18080,9 @@ var init_schema = __esm(() => {
|
|
|
17214
18080
|
}
|
|
17215
18081
|
},
|
|
17216
18082
|
blocks: { type: "array", items: { $ref: "#/$defs/Block" } },
|
|
17217
|
-
comments: { type: "array", items: { $ref: "#/$defs/Comment" } }
|
|
18083
|
+
comments: { type: "array", items: { $ref: "#/$defs/Comment" } },
|
|
18084
|
+
footnotes: { type: "array", items: { $ref: "#/$defs/Footnote" } },
|
|
18085
|
+
endnotes: { type: "array", items: { $ref: "#/$defs/Footnote" } }
|
|
17218
18086
|
},
|
|
17219
18087
|
$defs: {
|
|
17220
18088
|
Block: {
|
|
@@ -17248,7 +18116,10 @@ var init_schema = __esm(() => {
|
|
|
17248
18116
|
{ $ref: "#/$defs/TextRun" },
|
|
17249
18117
|
{ $ref: "#/$defs/ImageRun" },
|
|
17250
18118
|
{ $ref: "#/$defs/BreakRun" },
|
|
17251
|
-
{ $ref: "#/$defs/TabRun" }
|
|
18119
|
+
{ $ref: "#/$defs/TabRun" },
|
|
18120
|
+
{ $ref: "#/$defs/EquationRun" },
|
|
18121
|
+
{ $ref: "#/$defs/FootnoteRefRun" },
|
|
18122
|
+
{ $ref: "#/$defs/ChartRun" }
|
|
17252
18123
|
]
|
|
17253
18124
|
},
|
|
17254
18125
|
TextRun: {
|
|
@@ -17275,7 +18146,18 @@ var init_schema = __esm(() => {
|
|
|
17275
18146
|
date: { type: "string" },
|
|
17276
18147
|
revisionId: { type: "string" }
|
|
17277
18148
|
}
|
|
17278
|
-
}
|
|
18149
|
+
},
|
|
18150
|
+
hyperlink: { $ref: "#/$defs/Hyperlink" }
|
|
18151
|
+
}
|
|
18152
|
+
},
|
|
18153
|
+
Hyperlink: {
|
|
18154
|
+
type: "object",
|
|
18155
|
+
required: ["id"],
|
|
18156
|
+
properties: {
|
|
18157
|
+
id: { type: "string" },
|
|
18158
|
+
url: { type: "string" },
|
|
18159
|
+
anchor: { type: "string" },
|
|
18160
|
+
tooltip: { type: "string" }
|
|
17279
18161
|
}
|
|
17280
18162
|
},
|
|
17281
18163
|
ImageRun: {
|
|
@@ -17304,6 +18186,40 @@ var init_schema = __esm(() => {
|
|
|
17304
18186
|
required: ["type"],
|
|
17305
18187
|
properties: { type: { const: "tab" } }
|
|
17306
18188
|
},
|
|
18189
|
+
EquationRun: {
|
|
18190
|
+
type: "object",
|
|
18191
|
+
required: ["type", "text", "display"],
|
|
18192
|
+
properties: {
|
|
18193
|
+
type: { const: "equation" },
|
|
18194
|
+
text: { type: "string" },
|
|
18195
|
+
display: { type: "boolean" }
|
|
18196
|
+
}
|
|
18197
|
+
},
|
|
18198
|
+
FootnoteRefRun: {
|
|
18199
|
+
type: "object",
|
|
18200
|
+
required: ["type", "kind", "id"],
|
|
18201
|
+
properties: {
|
|
18202
|
+
type: { const: "footnoteRef" },
|
|
18203
|
+
kind: { enum: ["footnote", "endnote"] },
|
|
18204
|
+
id: { type: "string" }
|
|
18205
|
+
}
|
|
18206
|
+
},
|
|
18207
|
+
ChartRun: {
|
|
18208
|
+
type: "object",
|
|
18209
|
+
required: ["type", "kind"],
|
|
18210
|
+
properties: {
|
|
18211
|
+
type: { const: "chart" },
|
|
18212
|
+
kind: { enum: ["chart", "shape", "smartart", "drawing"] }
|
|
18213
|
+
}
|
|
18214
|
+
},
|
|
18215
|
+
Footnote: {
|
|
18216
|
+
type: "object",
|
|
18217
|
+
required: ["id", "text"],
|
|
18218
|
+
properties: {
|
|
18219
|
+
id: { type: "string" },
|
|
18220
|
+
text: { type: "string" }
|
|
18221
|
+
}
|
|
18222
|
+
},
|
|
17307
18223
|
Table: {
|
|
17308
18224
|
type: "object",
|
|
17309
18225
|
required: ["id", "type", "rows"],
|
|
@@ -17370,13 +18286,13 @@ var init_schema = __esm(() => {
|
|
|
17370
18286
|
// src/cli/info/locators.ts
|
|
17371
18287
|
var exports_locators = {};
|
|
17372
18288
|
__export(exports_locators, {
|
|
17373
|
-
run: () =>
|
|
18289
|
+
run: () => run21
|
|
17374
18290
|
});
|
|
17375
|
-
import { parseArgs as
|
|
17376
|
-
async function
|
|
18291
|
+
import { parseArgs as parseArgs18 } from "util";
|
|
18292
|
+
async function run21(args) {
|
|
17377
18293
|
let parsed;
|
|
17378
18294
|
try {
|
|
17379
|
-
parsed =
|
|
18295
|
+
parsed = parseArgs18({
|
|
17380
18296
|
args,
|
|
17381
18297
|
allowPositionals: true,
|
|
17382
18298
|
options: {
|
|
@@ -17386,10 +18302,10 @@ async function run16(args) {
|
|
|
17386
18302
|
});
|
|
17387
18303
|
} catch (parseError) {
|
|
17388
18304
|
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
17389
|
-
return fail("USAGE", message,
|
|
18305
|
+
return fail("USAGE", message, HELP21);
|
|
17390
18306
|
}
|
|
17391
18307
|
if (parsed.values.help) {
|
|
17392
|
-
await writeStdout(
|
|
18308
|
+
await writeStdout(HELP21);
|
|
17393
18309
|
return EXIT.OK;
|
|
17394
18310
|
}
|
|
17395
18311
|
if (parsed.values.json) {
|
|
@@ -17400,7 +18316,7 @@ async function run16(args) {
|
|
|
17400
18316
|
await writeStdout(REFERENCE);
|
|
17401
18317
|
return EXIT.OK;
|
|
17402
18318
|
}
|
|
17403
|
-
var
|
|
18319
|
+
var HELP21 = `docx locators \u2014 print the locator grammar reference
|
|
17404
18320
|
|
|
17405
18321
|
Usage:
|
|
17406
18322
|
docx locators [options]
|
|
@@ -17426,6 +18342,7 @@ Range locators (across blocks):
|
|
|
17426
18342
|
Entity locators:
|
|
17427
18343
|
cN Comment id (e.g., c0)
|
|
17428
18344
|
imgN Image id (e.g., img2)
|
|
18345
|
+
linkN Hyperlink id (e.g., link0)
|
|
17429
18346
|
tN:rRcC Cell at row R, column C of table tN
|
|
17430
18347
|
|
|
17431
18348
|
Examples:
|
|
@@ -17434,6 +18351,7 @@ Examples:
|
|
|
17434
18351
|
p3:5-p5:10 -> from char 5 of p3 to char 10 of p5
|
|
17435
18352
|
c1 -> comment c1
|
|
17436
18353
|
img0 -> image img0
|
|
18354
|
+
link0 -> hyperlink link0
|
|
17437
18355
|
t0:r1c2 -> cell at row 1, col 2 of table t0
|
|
17438
18356
|
t0:r1c2:p0 -> first paragraph of that cell
|
|
17439
18357
|
t0:r1c2:p0:5-10 -> chars 5..10 of that paragraph
|
|
@@ -17466,6 +18384,7 @@ var init_locators2 = __esm(() => {
|
|
|
17466
18384
|
entityLocators: {
|
|
17467
18385
|
comment: { syntax: "cN", example: "c1" },
|
|
17468
18386
|
image: { syntax: "imgN", example: "img0" },
|
|
18387
|
+
hyperlink: { syntax: "linkN", example: "link0" },
|
|
17469
18388
|
cell: { syntax: "tN:rRcC", example: "t0:r1c2" },
|
|
17470
18389
|
nestedCell: { syntax: "tN:rRcC:pK", example: "t0:r1c2:p0" }
|
|
17471
18390
|
},
|
|
@@ -17480,22 +18399,22 @@ var init_locators2 = __esm(() => {
|
|
|
17480
18399
|
// src/cli/info/index.ts
|
|
17481
18400
|
var exports_info = {};
|
|
17482
18401
|
__export(exports_info, {
|
|
17483
|
-
run: () =>
|
|
18402
|
+
run: () => run22
|
|
17484
18403
|
});
|
|
17485
|
-
async function
|
|
18404
|
+
async function run22(args) {
|
|
17486
18405
|
const topic = args[0];
|
|
17487
18406
|
if (!topic || topic === "--help" || topic === "-h" || topic === "help") {
|
|
17488
|
-
await writeStdout(
|
|
18407
|
+
await writeStdout(HELP22);
|
|
17489
18408
|
return topic ? 0 : 2;
|
|
17490
18409
|
}
|
|
17491
|
-
const loader =
|
|
18410
|
+
const loader = SUBCOMMANDS4[topic];
|
|
17492
18411
|
if (!loader) {
|
|
17493
18412
|
return fail("USAGE", `Unknown info topic: ${topic}`, 'Run "docx info --help".');
|
|
17494
18413
|
}
|
|
17495
18414
|
const module_ = await loader();
|
|
17496
18415
|
return module_.run(args.slice(1));
|
|
17497
18416
|
}
|
|
17498
|
-
var
|
|
18417
|
+
var SUBCOMMANDS4, HELP22 = `docx info \u2014 print reference material about the CLI
|
|
17499
18418
|
|
|
17500
18419
|
Usage:
|
|
17501
18420
|
docx info <topic> [options]
|
|
@@ -17508,7 +18427,7 @@ Run "docx info <topic> --help" for topic-specific help.
|
|
|
17508
18427
|
`;
|
|
17509
18428
|
var init_info = __esm(() => {
|
|
17510
18429
|
init_respond();
|
|
17511
|
-
|
|
18430
|
+
SUBCOMMANDS4 = {
|
|
17512
18431
|
schema: () => Promise.resolve().then(() => (init_schema(), exports_schema)),
|
|
17513
18432
|
locators: () => Promise.resolve().then(() => (init_locators2(), exports_locators))
|
|
17514
18433
|
};
|
|
@@ -17517,13 +18436,13 @@ var init_info = __esm(() => {
|
|
|
17517
18436
|
// src/cli/insert/index.tsx
|
|
17518
18437
|
var exports_insert = {};
|
|
17519
18438
|
__export(exports_insert, {
|
|
17520
|
-
run: () =>
|
|
18439
|
+
run: () => run23
|
|
17521
18440
|
});
|
|
17522
|
-
import { parseArgs as
|
|
17523
|
-
async function
|
|
18441
|
+
import { parseArgs as parseArgs19 } from "util";
|
|
18442
|
+
async function run23(args) {
|
|
17524
18443
|
let parsed;
|
|
17525
18444
|
try {
|
|
17526
|
-
parsed =
|
|
18445
|
+
parsed = parseArgs19({
|
|
17527
18446
|
args,
|
|
17528
18447
|
allowPositionals: true,
|
|
17529
18448
|
options: {
|
|
@@ -17536,6 +18455,7 @@ async function run18(args) {
|
|
|
17536
18455
|
color: { type: "string" },
|
|
17537
18456
|
bold: { type: "boolean" },
|
|
17538
18457
|
italic: { type: "boolean" },
|
|
18458
|
+
url: { type: "string" },
|
|
17539
18459
|
output: { type: "string", short: "o" },
|
|
17540
18460
|
"dry-run": { type: "boolean" },
|
|
17541
18461
|
help: { type: "boolean", short: "h" }
|
|
@@ -17543,30 +18463,34 @@ async function run18(args) {
|
|
|
17543
18463
|
});
|
|
17544
18464
|
} catch (parseError) {
|
|
17545
18465
|
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
17546
|
-
return fail("USAGE", message,
|
|
18466
|
+
return fail("USAGE", message, HELP23);
|
|
17547
18467
|
}
|
|
17548
18468
|
if (parsed.values.help) {
|
|
17549
|
-
await writeStdout(
|
|
18469
|
+
await writeStdout(HELP23);
|
|
17550
18470
|
return EXIT.OK;
|
|
17551
18471
|
}
|
|
17552
18472
|
const path = parsed.positionals[0];
|
|
17553
18473
|
if (!path)
|
|
17554
|
-
return fail("USAGE", "Missing FILE argument",
|
|
18474
|
+
return fail("USAGE", "Missing FILE argument", HELP23);
|
|
17555
18475
|
const after = parsed.values.after;
|
|
17556
18476
|
const before = parsed.values.before;
|
|
17557
18477
|
if (!after && !before) {
|
|
17558
|
-
return fail("USAGE", "Missing locator: pass --after or --before",
|
|
18478
|
+
return fail("USAGE", "Missing locator: pass --after or --before", HELP23);
|
|
17559
18479
|
}
|
|
17560
18480
|
if (after && before) {
|
|
17561
|
-
return fail("USAGE", "Pass either --after or --before, not both",
|
|
18481
|
+
return fail("USAGE", "Pass either --after or --before, not both", HELP23);
|
|
17562
18482
|
}
|
|
17563
18483
|
const text = parsed.values.text;
|
|
17564
18484
|
const runsJson = parsed.values.runs;
|
|
18485
|
+
const url = parsed.values.url;
|
|
17565
18486
|
if (!text && !runsJson) {
|
|
17566
|
-
return fail("USAGE", "Missing content: pass --text or --runs",
|
|
18487
|
+
return fail("USAGE", "Missing content: pass --text or --runs", HELP23);
|
|
17567
18488
|
}
|
|
17568
18489
|
if (text && runsJson) {
|
|
17569
|
-
return fail("USAGE", "Pass either --text or --runs, not both",
|
|
18490
|
+
return fail("USAGE", "Pass either --text or --runs, not both", HELP23);
|
|
18491
|
+
}
|
|
18492
|
+
if (url && !text) {
|
|
18493
|
+
return fail("USAGE", "--url requires --text", HELP23);
|
|
17570
18494
|
}
|
|
17571
18495
|
const paragraphOptions = {};
|
|
17572
18496
|
const styleValue = parsed.values.style;
|
|
@@ -17596,6 +18520,8 @@ async function run18(args) {
|
|
|
17596
18520
|
...parsed.values.bold ? { bold: true } : {},
|
|
17597
18521
|
...parsed.values.italic ? { italic: true } : {}
|
|
17598
18522
|
}, undefined, false, undefined, this);
|
|
18523
|
+
if (url)
|
|
18524
|
+
wrapFirstRunInHyperlink(view, paragraphNode, url);
|
|
17599
18525
|
} else {
|
|
17600
18526
|
let runsValue;
|
|
17601
18527
|
try {
|
|
@@ -17644,6 +18570,29 @@ async function run18(args) {
|
|
|
17644
18570
|
});
|
|
17645
18571
|
return EXIT.OK;
|
|
17646
18572
|
}
|
|
18573
|
+
function wrapFirstRunInHyperlink(view, paragraph, url) {
|
|
18574
|
+
const relationships = XmlNode2.findRoot(view.relationshipsTree, "Relationships");
|
|
18575
|
+
if (!relationships) {
|
|
18576
|
+
throw new Error("Missing <Relationships> root in document rels");
|
|
18577
|
+
}
|
|
18578
|
+
const relationshipId = addHyperlinkRelationship(relationships, url);
|
|
18579
|
+
view.hyperlinksByRelationshipId.set(relationshipId, { url });
|
|
18580
|
+
const newChildren = [];
|
|
18581
|
+
let wrapped = false;
|
|
18582
|
+
for (const child of paragraph.children) {
|
|
18583
|
+
if (!wrapped && child.tag === "w:r") {
|
|
18584
|
+
const wrapper = /* @__PURE__ */ jsxDEV(w.hyperlink, {
|
|
18585
|
+
"r:id": relationshipId,
|
|
18586
|
+
children: child
|
|
18587
|
+
}, undefined, false, undefined, this);
|
|
18588
|
+
newChildren.push(wrapper);
|
|
18589
|
+
wrapped = true;
|
|
18590
|
+
continue;
|
|
18591
|
+
}
|
|
18592
|
+
newChildren.push(child);
|
|
18593
|
+
}
|
|
18594
|
+
paragraph.children = newChildren;
|
|
18595
|
+
}
|
|
17647
18596
|
function applyTrackedInsertion(paragraph, view) {
|
|
17648
18597
|
const allocator = createRevisionAllocator(view);
|
|
17649
18598
|
const baseMeta = { author: resolveAuthor(), date: resolveDate() };
|
|
@@ -17674,7 +18623,7 @@ function applyTrackedInsertion(paragraph, view) {
|
|
|
17674
18623
|
paragraph.children = newChildren;
|
|
17675
18624
|
markParagraphMarkAs(paragraph, "ins", mintMeta());
|
|
17676
18625
|
}
|
|
17677
|
-
var
|
|
18626
|
+
var HELP23 = `docx insert \u2014 insert a paragraph at a locator
|
|
17678
18627
|
|
|
17679
18628
|
Usage:
|
|
17680
18629
|
docx insert FILE [options]
|
|
@@ -17695,6 +18644,7 @@ Run options (only with --text):
|
|
|
17695
18644
|
--color HEX Run color, hex (e.g., 800080 for purple)
|
|
17696
18645
|
--bold Bold
|
|
17697
18646
|
--italic Italic
|
|
18647
|
+
--url URL Wrap the inserted text in a hyperlink to URL
|
|
17698
18648
|
|
|
17699
18649
|
-o, --output PATH Write to PATH instead of overwriting FILE
|
|
17700
18650
|
--dry-run Print what would be inserted; do not write the file
|
|
@@ -17704,9 +18654,12 @@ Examples:
|
|
|
17704
18654
|
docx insert doc.docx --after p3 --text "Section header" --style Heading2
|
|
17705
18655
|
docx insert doc.docx --before p0 --text "ALERT" --color CC0000 --bold
|
|
17706
18656
|
docx insert doc.docx --after p2 --runs '[{"type":"text","text":"X","bold":true}]'
|
|
18657
|
+
docx insert doc.docx --after p3 --text "click here" --url https://example.com
|
|
17707
18658
|
`;
|
|
17708
18659
|
var init_insert = __esm(() => {
|
|
17709
18660
|
init_core();
|
|
18661
|
+
init_jsx();
|
|
18662
|
+
init_parser();
|
|
17710
18663
|
init_respond();
|
|
17711
18664
|
init_emit2();
|
|
17712
18665
|
init_jsx_dev_runtime();
|
|
@@ -17744,159 +18697,620 @@ function buildOutline(doc, options = {}) {
|
|
|
17744
18697
|
}
|
|
17745
18698
|
return root.children;
|
|
17746
18699
|
}
|
|
17747
|
-
function headingLevel(style, stylePrefix) {
|
|
17748
|
-
if (!style)
|
|
18700
|
+
function headingLevel(style, stylePrefix) {
|
|
18701
|
+
if (!style)
|
|
18702
|
+
return null;
|
|
18703
|
+
if (!style.startsWith(stylePrefix))
|
|
18704
|
+
return null;
|
|
18705
|
+
const remainder = style.slice(stylePrefix.length).trim();
|
|
18706
|
+
if (remainder === "")
|
|
18707
|
+
return 1;
|
|
18708
|
+
const parsed = Number(remainder);
|
|
18709
|
+
if (!Number.isInteger(parsed) || parsed < 1)
|
|
18710
|
+
return null;
|
|
18711
|
+
return parsed;
|
|
18712
|
+
}
|
|
18713
|
+
function* headingParagraphs(blocks, stylePrefix) {
|
|
18714
|
+
for (const block of blocks) {
|
|
18715
|
+
if (block.type !== "paragraph")
|
|
18716
|
+
continue;
|
|
18717
|
+
if (headingLevel(block.style, stylePrefix) === null)
|
|
18718
|
+
continue;
|
|
18719
|
+
yield block;
|
|
18720
|
+
}
|
|
18721
|
+
}
|
|
18722
|
+
var init_build = __esm(() => {
|
|
18723
|
+
init_core();
|
|
18724
|
+
});
|
|
18725
|
+
|
|
18726
|
+
// src/cli/outline/index.ts
|
|
18727
|
+
var exports_outline = {};
|
|
18728
|
+
__export(exports_outline, {
|
|
18729
|
+
run: () => run24
|
|
18730
|
+
});
|
|
18731
|
+
import { parseArgs as parseArgs20 } from "util";
|
|
18732
|
+
async function run24(args) {
|
|
18733
|
+
let parsed;
|
|
18734
|
+
try {
|
|
18735
|
+
parsed = parseArgs20({
|
|
18736
|
+
args,
|
|
18737
|
+
allowPositionals: true,
|
|
18738
|
+
options: {
|
|
18739
|
+
"style-prefix": { type: "string" },
|
|
18740
|
+
help: { type: "boolean", short: "h" }
|
|
18741
|
+
}
|
|
18742
|
+
});
|
|
18743
|
+
} catch (parseError) {
|
|
18744
|
+
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
18745
|
+
return fail("USAGE", message, HELP24);
|
|
18746
|
+
}
|
|
18747
|
+
if (parsed.values.help) {
|
|
18748
|
+
await writeStdout(HELP24);
|
|
18749
|
+
return EXIT.OK;
|
|
18750
|
+
}
|
|
18751
|
+
const path = parsed.positionals[0];
|
|
18752
|
+
if (!path)
|
|
18753
|
+
return fail("USAGE", "Missing FILE argument", HELP24);
|
|
18754
|
+
const stylePrefix = parsed.values["style-prefix"] ?? "Heading";
|
|
18755
|
+
if (stylePrefix.length === 0) {
|
|
18756
|
+
return fail("USAGE", "--style-prefix cannot be empty");
|
|
18757
|
+
}
|
|
18758
|
+
const view = await openOrFail(path);
|
|
18759
|
+
if (typeof view === "number")
|
|
18760
|
+
return view;
|
|
18761
|
+
const outline = buildOutline(view.doc, { stylePrefix });
|
|
18762
|
+
await respond({
|
|
18763
|
+
ok: true,
|
|
18764
|
+
operation: "outline",
|
|
18765
|
+
path,
|
|
18766
|
+
stylePrefix,
|
|
18767
|
+
outline
|
|
18768
|
+
});
|
|
18769
|
+
return EXIT.OK;
|
|
18770
|
+
}
|
|
18771
|
+
var HELP24 = `docx outline \u2014 list headings as a hierarchical tree
|
|
18772
|
+
|
|
18773
|
+
Usage:
|
|
18774
|
+
docx outline FILE [options]
|
|
18775
|
+
|
|
18776
|
+
Options:
|
|
18777
|
+
--style-prefix S paragraph-style prefix that marks a heading (default: "Heading")
|
|
18778
|
+
-h, --help show this help
|
|
18779
|
+
|
|
18780
|
+
Walks top-level paragraphs whose style starts with the prefix and parses the
|
|
18781
|
+
trailing number as the heading level (e.g. "Heading1" \u2192 1, "Heading 2" \u2192 2).
|
|
18782
|
+
Paragraphs nested inside table cells are skipped \u2014 outlines reflect the
|
|
18783
|
+
document's structural skeleton, not embedded labels. Lower levels nest under
|
|
18784
|
+
higher ones; missing intermediate levels nest directly (H1 \u2192 H3 is fine).
|
|
18785
|
+
|
|
18786
|
+
Output is JSON: an array of entries, each shaped like
|
|
18787
|
+
{ id, locator, level, style, text, children }.
|
|
18788
|
+
|
|
18789
|
+
Examples:
|
|
18790
|
+
docx outline doc.docx
|
|
18791
|
+
docx outline doc.docx --style-prefix "Section"
|
|
18792
|
+
docx outline doc.docx | jq '.outline[].text'
|
|
18793
|
+
`;
|
|
18794
|
+
var init_outline = __esm(() => {
|
|
18795
|
+
init_respond();
|
|
18796
|
+
init_build();
|
|
18797
|
+
});
|
|
18798
|
+
|
|
18799
|
+
// src/cli/read/markdown.ts
|
|
18800
|
+
function renderMarkdown(doc, options = {}) {
|
|
18801
|
+
const blocks = sliceBlocks(doc.blocks, options.from, options.to);
|
|
18802
|
+
const commentIndex = options.showComments ? buildCommentIndex(blocks, options) : emptyCommentIndex();
|
|
18803
|
+
const ctx = {
|
|
18804
|
+
options,
|
|
18805
|
+
commentIndex,
|
|
18806
|
+
referencedFootnoteIds: new Set,
|
|
18807
|
+
referencedEndnoteIds: new Set
|
|
18808
|
+
};
|
|
18809
|
+
const parts = [];
|
|
18810
|
+
for (const block of blocks) {
|
|
18811
|
+
const rendered = renderBlock(block, ctx);
|
|
18812
|
+
if (rendered !== null)
|
|
18813
|
+
parts.push(rendered);
|
|
18814
|
+
}
|
|
18815
|
+
const definitions = [];
|
|
18816
|
+
if (options.showComments) {
|
|
18817
|
+
const commentFootnotes = renderCommentFootnotes(commentIndex, doc.comments);
|
|
18818
|
+
if (commentFootnotes.length > 0)
|
|
18819
|
+
definitions.push(commentFootnotes);
|
|
18820
|
+
}
|
|
18821
|
+
const footnoteDefs = renderNoteDefinitions(doc.footnotes, ctx.referencedFootnoteIds);
|
|
18822
|
+
if (footnoteDefs.length > 0)
|
|
18823
|
+
definitions.push(footnoteDefs);
|
|
18824
|
+
const endnoteDefs = renderNoteDefinitions(doc.endnotes, ctx.referencedEndnoteIds);
|
|
18825
|
+
if (endnoteDefs.length > 0)
|
|
18826
|
+
definitions.push(endnoteDefs);
|
|
18827
|
+
if (definitions.length > 0)
|
|
18828
|
+
parts.push(definitions.join(`
|
|
18829
|
+
`));
|
|
18830
|
+
if (parts.length === 0)
|
|
18831
|
+
return "";
|
|
18832
|
+
return `${parts.join(`
|
|
18833
|
+
|
|
18834
|
+
`)}
|
|
18835
|
+
`;
|
|
18836
|
+
}
|
|
18837
|
+
function emptyCommentIndex() {
|
|
18838
|
+
return {
|
|
18839
|
+
endingsByRun: new Map,
|
|
18840
|
+
spanText: new Map,
|
|
18841
|
+
orderedIds: []
|
|
18842
|
+
};
|
|
18843
|
+
}
|
|
18844
|
+
function buildCommentIndex(blocks, options) {
|
|
18845
|
+
const showChanges = options.showChanges ?? false;
|
|
18846
|
+
const lastSlot = new Map;
|
|
18847
|
+
const spanText = new Map;
|
|
18848
|
+
const orderedIds = [];
|
|
18849
|
+
for (const paragraph of flattenParagraphs(blocks)) {
|
|
18850
|
+
paragraph.runs.forEach((run25, index) => {
|
|
18851
|
+
if (run25.type !== "text")
|
|
18852
|
+
return;
|
|
18853
|
+
if (!showChanges && run25.trackedChange?.kind === "del")
|
|
18854
|
+
return;
|
|
18855
|
+
for (const commentId of run25.comments ?? []) {
|
|
18856
|
+
if (!spanText.has(commentId))
|
|
18857
|
+
orderedIds.push(commentId);
|
|
18858
|
+
spanText.set(commentId, (spanText.get(commentId) ?? "") + run25.text);
|
|
18859
|
+
lastSlot.set(commentId, slotKey(paragraph.id, index));
|
|
18860
|
+
}
|
|
18861
|
+
});
|
|
18862
|
+
}
|
|
18863
|
+
const endingsByRun = new Map;
|
|
18864
|
+
for (const commentId of orderedIds) {
|
|
18865
|
+
const slot = lastSlot.get(commentId);
|
|
18866
|
+
if (!slot)
|
|
18867
|
+
continue;
|
|
18868
|
+
const list = endingsByRun.get(slot) ?? [];
|
|
18869
|
+
list.push(commentId);
|
|
18870
|
+
endingsByRun.set(slot, list);
|
|
18871
|
+
}
|
|
18872
|
+
return { endingsByRun, spanText, orderedIds };
|
|
18873
|
+
}
|
|
18874
|
+
function slotKey(paragraphId, runIndex) {
|
|
18875
|
+
return `${paragraphId}#${runIndex}`;
|
|
18876
|
+
}
|
|
18877
|
+
function renderBlock(block, ctx) {
|
|
18878
|
+
if (block.type === "paragraph")
|
|
18879
|
+
return renderParagraph(block, ctx);
|
|
18880
|
+
if (block.type === "table")
|
|
18881
|
+
return renderTable(block, ctx);
|
|
18882
|
+
if (block.type === "sectionBreak")
|
|
18883
|
+
return `--- <!-- ${block.id} -->`;
|
|
18884
|
+
return null;
|
|
18885
|
+
}
|
|
18886
|
+
function renderParagraph(paragraph, ctx) {
|
|
18887
|
+
const body = renderRuns(paragraph.id, paragraph.runs, ctx);
|
|
18888
|
+
if (body.length === 0)
|
|
18889
|
+
return null;
|
|
18890
|
+
const prefix = paragraphPrefix(paragraph);
|
|
18891
|
+
return `${prefix}${body} <!-- ${paragraph.id} -->`;
|
|
18892
|
+
}
|
|
18893
|
+
function paragraphPrefix(paragraph) {
|
|
18894
|
+
const headingLevel2 = headingLevelFor(paragraph.style);
|
|
18895
|
+
if (headingLevel2 !== null)
|
|
18896
|
+
return `${"#".repeat(headingLevel2)} `;
|
|
18897
|
+
if (paragraph.list) {
|
|
18898
|
+
const indent = " ".repeat(paragraph.list.level);
|
|
18899
|
+
return `${indent}- `;
|
|
18900
|
+
}
|
|
18901
|
+
return "";
|
|
18902
|
+
}
|
|
18903
|
+
function headingLevelFor(style) {
|
|
18904
|
+
if (!style)
|
|
18905
|
+
return null;
|
|
18906
|
+
if (!style.startsWith("Heading"))
|
|
18907
|
+
return null;
|
|
18908
|
+
const remainder = style.slice("Heading".length).trim();
|
|
18909
|
+
if (remainder === "")
|
|
18910
|
+
return 1;
|
|
18911
|
+
const parsed = Number(remainder);
|
|
18912
|
+
if (!Number.isInteger(parsed) || parsed < 1 || parsed > 6)
|
|
18913
|
+
return null;
|
|
18914
|
+
return parsed;
|
|
18915
|
+
}
|
|
18916
|
+
function renderRuns(paragraphId, runs, ctx) {
|
|
18917
|
+
const showChanges = ctx.options.showChanges ?? false;
|
|
18918
|
+
const visibleEntries = [];
|
|
18919
|
+
runs.forEach((run25, index) => {
|
|
18920
|
+
if (!showChanges && run25.type === "text" && run25.trackedChange?.kind === "del") {
|
|
18921
|
+
return;
|
|
18922
|
+
}
|
|
18923
|
+
visibleEntries.push({ run: run25, originalIndex: index });
|
|
18924
|
+
});
|
|
18925
|
+
let out = "";
|
|
18926
|
+
let cursor = 0;
|
|
18927
|
+
while (cursor < visibleEntries.length) {
|
|
18928
|
+
const entry = visibleEntries[cursor];
|
|
18929
|
+
if (!entry) {
|
|
18930
|
+
cursor++;
|
|
18931
|
+
continue;
|
|
18932
|
+
}
|
|
18933
|
+
const { run: run25 } = entry;
|
|
18934
|
+
if (run25.type === "text") {
|
|
18935
|
+
let lookahead = cursor + 1;
|
|
18936
|
+
while (lookahead < visibleEntries.length) {
|
|
18937
|
+
const next = visibleEntries[lookahead];
|
|
18938
|
+
if (!next || next.run.type !== "text")
|
|
18939
|
+
break;
|
|
18940
|
+
if (!sameDecoration(run25, next.run))
|
|
18941
|
+
break;
|
|
18942
|
+
lookahead++;
|
|
18943
|
+
}
|
|
18944
|
+
const segment = visibleEntries.slice(cursor, lookahead);
|
|
18945
|
+
out += renderTextSegment(segment.map((entry2) => entry2.run), showChanges);
|
|
18946
|
+
out += commentEndingsFor(paragraphId, segment, ctx.commentIndex);
|
|
18947
|
+
cursor = lookahead;
|
|
18948
|
+
continue;
|
|
18949
|
+
}
|
|
18950
|
+
if (run25.type === "image") {
|
|
18951
|
+
const alt = sanitizeAltText(run25.alt ?? run25.id);
|
|
18952
|
+
out += ``;
|
|
18953
|
+
} else if (run25.type === "break") {
|
|
18954
|
+
if (run25.kind === "line")
|
|
18955
|
+
out += "<br>";
|
|
18956
|
+
} else if (run25.type === "tab") {
|
|
18957
|
+
out += "\t";
|
|
18958
|
+
} else if (run25.type === "equation") {
|
|
18959
|
+
const escaped = run25.text.replace(/`/g, "\\`");
|
|
18960
|
+
out += `\`equation: ${escaped}\``;
|
|
18961
|
+
} else if (run25.type === "footnoteRef") {
|
|
18962
|
+
if (run25.kind === "footnote")
|
|
18963
|
+
ctx.referencedFootnoteIds.add(run25.id);
|
|
18964
|
+
else
|
|
18965
|
+
ctx.referencedEndnoteIds.add(run25.id);
|
|
18966
|
+
out += `[^${run25.id}]`;
|
|
18967
|
+
} else if (run25.type === "chart") {
|
|
18968
|
+
out += `\`[${run25.kind}]\``;
|
|
18969
|
+
}
|
|
18970
|
+
cursor++;
|
|
18971
|
+
}
|
|
18972
|
+
return out;
|
|
18973
|
+
}
|
|
18974
|
+
function commentEndingsFor(paragraphId, segment, commentIndex) {
|
|
18975
|
+
if (commentIndex.endingsByRun.size === 0)
|
|
18976
|
+
return "";
|
|
18977
|
+
let out = "";
|
|
18978
|
+
for (const entry of segment) {
|
|
18979
|
+
const ids = commentIndex.endingsByRun.get(slotKey(paragraphId, entry.originalIndex));
|
|
18980
|
+
if (!ids)
|
|
18981
|
+
continue;
|
|
18982
|
+
for (const commentId of ids)
|
|
18983
|
+
out += `[^${commentId}]`;
|
|
18984
|
+
}
|
|
18985
|
+
return out;
|
|
18986
|
+
}
|
|
18987
|
+
function sameDecoration(a2, b) {
|
|
18988
|
+
return (a2.bold ?? false) === (b.bold ?? false) && (a2.italic ?? false) === (b.italic ?? false) && (a2.strike ?? false) === (b.strike ?? false) && (a2.underline ?? "") === (b.underline ?? "") && (a2.color ?? "") === (b.color ?? "") && (a2.highlight ?? "") === (b.highlight ?? "") && a2.hyperlink?.id === b.hyperlink?.id && a2.trackedChange?.kind === b.trackedChange?.kind && sameCommentSet(a2.comments, b.comments);
|
|
18989
|
+
}
|
|
18990
|
+
function sameCommentSet(left, right) {
|
|
18991
|
+
const a2 = left ?? [];
|
|
18992
|
+
const b = right ?? [];
|
|
18993
|
+
if (a2.length !== b.length)
|
|
18994
|
+
return false;
|
|
18995
|
+
for (let i = 0;i < a2.length; i++) {
|
|
18996
|
+
if (a2[i] !== b[i])
|
|
18997
|
+
return false;
|
|
18998
|
+
}
|
|
18999
|
+
return true;
|
|
19000
|
+
}
|
|
19001
|
+
function renderTextSegment(runs, showChanges) {
|
|
19002
|
+
const text = runs.map((run25) => run25.text).join("");
|
|
19003
|
+
if (text.length === 0)
|
|
19004
|
+
return "";
|
|
19005
|
+
const first = runs[0];
|
|
19006
|
+
if (!first)
|
|
19007
|
+
return "";
|
|
19008
|
+
let out = text;
|
|
19009
|
+
if (first.bold)
|
|
19010
|
+
out = `**${out}**`;
|
|
19011
|
+
if (first.italic)
|
|
19012
|
+
out = `*${out}*`;
|
|
19013
|
+
if (first.strike)
|
|
19014
|
+
out = `~~${out}~~`;
|
|
19015
|
+
if (first.underline)
|
|
19016
|
+
out = `<u>${out}</u>`;
|
|
19017
|
+
const color = colorAttrFor(first.color);
|
|
19018
|
+
if (color)
|
|
19019
|
+
out = `<span style="color:${color}">${out}</span>`;
|
|
19020
|
+
const highlight = highlightCssFor(first.highlight);
|
|
19021
|
+
if (highlight)
|
|
19022
|
+
out = `<span style="background-color:${highlight}">${out}</span>`;
|
|
19023
|
+
if (first.hyperlink) {
|
|
19024
|
+
const target = first.hyperlink.url ?? `#${first.hyperlink.anchor ?? ""}`;
|
|
19025
|
+
out = `[${out}](${target})`;
|
|
19026
|
+
}
|
|
19027
|
+
if (showChanges && first.trackedChange) {
|
|
19028
|
+
out = `<${first.trackedChange.kind}>${out}</${first.trackedChange.kind}>`;
|
|
19029
|
+
}
|
|
19030
|
+
return out;
|
|
19031
|
+
}
|
|
19032
|
+
function colorAttrFor(value) {
|
|
19033
|
+
if (!value)
|
|
17749
19034
|
return null;
|
|
17750
|
-
|
|
19035
|
+
const lowered = value.toLowerCase();
|
|
19036
|
+
if (lowered === "auto")
|
|
17751
19037
|
return null;
|
|
17752
|
-
|
|
17753
|
-
|
|
17754
|
-
|
|
17755
|
-
|
|
17756
|
-
|
|
19038
|
+
if (/^[0-9a-f]{6}$/.test(lowered))
|
|
19039
|
+
return `#${lowered}`;
|
|
19040
|
+
return value;
|
|
19041
|
+
}
|
|
19042
|
+
function highlightCssFor(value) {
|
|
19043
|
+
if (!value)
|
|
17757
19044
|
return null;
|
|
17758
|
-
|
|
19045
|
+
if (value === "none")
|
|
19046
|
+
return null;
|
|
19047
|
+
return value.replace(/[A-Z]/g, (letter) => letter.toLowerCase());
|
|
17759
19048
|
}
|
|
17760
|
-
function
|
|
17761
|
-
|
|
17762
|
-
|
|
19049
|
+
function renderTable(table, ctx) {
|
|
19050
|
+
if (table.rows.length === 0)
|
|
19051
|
+
return null;
|
|
19052
|
+
const colCount = Math.max(...table.rows.map((row) => row.cells.length));
|
|
19053
|
+
if (colCount === 0)
|
|
19054
|
+
return null;
|
|
19055
|
+
const renderedRows = table.rows.map((row) => {
|
|
19056
|
+
const cells = [];
|
|
19057
|
+
for (let columnIndex = 0;columnIndex < colCount; columnIndex++) {
|
|
19058
|
+
const cell = row.cells[columnIndex];
|
|
19059
|
+
cells.push(cell ? renderCell(cell, ctx) : "");
|
|
19060
|
+
}
|
|
19061
|
+
return cells;
|
|
19062
|
+
});
|
|
19063
|
+
const lines = [];
|
|
19064
|
+
const headerRow = renderedRows[0];
|
|
19065
|
+
if (!headerRow)
|
|
19066
|
+
return null;
|
|
19067
|
+
lines.push(rowToLine(headerRow));
|
|
19068
|
+
lines.push(`| ${Array(colCount).fill("---").join(" | ")} |`);
|
|
19069
|
+
for (let rowIndex = 1;rowIndex < renderedRows.length; rowIndex++) {
|
|
19070
|
+
const row = renderedRows[rowIndex];
|
|
19071
|
+
if (row)
|
|
19072
|
+
lines.push(rowToLine(row));
|
|
19073
|
+
}
|
|
19074
|
+
return lines.join(`
|
|
19075
|
+
`);
|
|
19076
|
+
}
|
|
19077
|
+
function rowToLine(cells) {
|
|
19078
|
+
return `| ${cells.join(" | ")} |`;
|
|
19079
|
+
}
|
|
19080
|
+
function renderCell(cell, ctx) {
|
|
19081
|
+
const parts = [];
|
|
19082
|
+
for (const block of cell.blocks) {
|
|
19083
|
+
if (block.type === "paragraph") {
|
|
19084
|
+
const body = renderRuns(block.id, block.runs, ctx);
|
|
19085
|
+
if (body.length === 0)
|
|
19086
|
+
continue;
|
|
19087
|
+
parts.push(`${body} <!-- ${block.id} -->`);
|
|
17763
19088
|
continue;
|
|
17764
|
-
|
|
19089
|
+
}
|
|
19090
|
+
if (block.type === "table") {
|
|
19091
|
+
parts.push(renderNestedTable(block, ctx));
|
|
19092
|
+
}
|
|
19093
|
+
}
|
|
19094
|
+
return escapeCell(parts.join("<br>"));
|
|
19095
|
+
}
|
|
19096
|
+
function renderNestedTable(table, ctx) {
|
|
19097
|
+
const rows = table.rows.map((row) => row.cells.map((cell) => renderCell(cell, ctx)).join(" / "));
|
|
19098
|
+
return rows.join(" // ");
|
|
19099
|
+
}
|
|
19100
|
+
function escapeCell(text) {
|
|
19101
|
+
return text.replace(/\|/g, "\\|");
|
|
19102
|
+
}
|
|
19103
|
+
function sanitizeAltText(text) {
|
|
19104
|
+
return text.replace(/[\r\n]+/g, " ").replace(/\]/g, "\\]");
|
|
19105
|
+
}
|
|
19106
|
+
function renderCommentFootnotes(commentIndex, comments) {
|
|
19107
|
+
if (commentIndex.orderedIds.length === 0)
|
|
19108
|
+
return "";
|
|
19109
|
+
const byId = new Map(comments.map((comment) => [comment.id, comment]));
|
|
19110
|
+
const sorted = [...commentIndex.orderedIds].sort(commentIdCompare);
|
|
19111
|
+
const lines = [];
|
|
19112
|
+
for (const commentId of sorted) {
|
|
19113
|
+
const comment = byId.get(commentId);
|
|
19114
|
+
if (!comment)
|
|
17765
19115
|
continue;
|
|
17766
|
-
|
|
19116
|
+
const span = commentIndex.spanText.get(commentId) ?? "";
|
|
19117
|
+
lines.push(formatFootnote(comment, span));
|
|
17767
19118
|
}
|
|
19119
|
+
return lines.join(`
|
|
19120
|
+
`);
|
|
17768
19121
|
}
|
|
17769
|
-
function
|
|
17770
|
-
|
|
17771
|
-
|
|
17772
|
-
|
|
17773
|
-
|
|
19122
|
+
function renderNoteDefinitions(notes, referenced) {
|
|
19123
|
+
if (referenced.size === 0)
|
|
19124
|
+
return "";
|
|
19125
|
+
const byId = new Map(notes.map((note) => [note.id, note]));
|
|
19126
|
+
const sorted = [...referenced].sort(noteIdCompare);
|
|
19127
|
+
const lines = [];
|
|
19128
|
+
for (const id of sorted) {
|
|
19129
|
+
const note = byId.get(id);
|
|
19130
|
+
const body = (note?.text ?? "").replace(/\s+/g, " ").trim();
|
|
19131
|
+
lines.push(`[^${id}]: ${body}`);
|
|
19132
|
+
}
|
|
19133
|
+
return lines.join(`
|
|
19134
|
+
`);
|
|
19135
|
+
}
|
|
19136
|
+
function noteIdCompare(left, right) {
|
|
19137
|
+
return numericIdCompare(left, right, /(\d+)$/);
|
|
19138
|
+
}
|
|
19139
|
+
function commentIdCompare(left, right) {
|
|
19140
|
+
return numericIdCompare(left, right, /^c(\d+)$/);
|
|
19141
|
+
}
|
|
19142
|
+
function numericIdCompare(left, right, pattern) {
|
|
19143
|
+
const leftMatch = left.match(pattern);
|
|
19144
|
+
const rightMatch = right.match(pattern);
|
|
19145
|
+
if (leftMatch?.[1] && rightMatch?.[1]) {
|
|
19146
|
+
return Number(leftMatch[1]) - Number(rightMatch[1]);
|
|
17774
19147
|
}
|
|
17775
|
-
return
|
|
19148
|
+
return left.localeCompare(right);
|
|
17776
19149
|
}
|
|
17777
|
-
|
|
17778
|
-
|
|
17779
|
-
|
|
17780
|
-
|
|
17781
|
-
|
|
17782
|
-
})
|
|
17783
|
-
|
|
17784
|
-
|
|
19150
|
+
function formatFootnote(comment, spanText) {
|
|
19151
|
+
const quoted = quoteSpan(spanText);
|
|
19152
|
+
const reply = comment.parentId ? ` \u21B3 ${comment.parentId}` : "";
|
|
19153
|
+
const resolved = comment.resolved ? "\u2713 " : "";
|
|
19154
|
+
const body = comment.text.replace(/\s+/g, " ").trim();
|
|
19155
|
+
return `[^${comment.id}]: ${quoted} \u2014 ${resolved}${comment.author} (${comment.date})${reply}: ${body}`;
|
|
19156
|
+
}
|
|
19157
|
+
function quoteSpan(text) {
|
|
19158
|
+
const collapsed = text.replace(/\s+/g, " ").trim();
|
|
19159
|
+
const escaped = collapsed.replace(/"/g, "\\\"");
|
|
19160
|
+
return `"${escaped}"`;
|
|
19161
|
+
}
|
|
19162
|
+
function sliceBlocks(blocks, from, to) {
|
|
19163
|
+
if (!from && !to)
|
|
19164
|
+
return blocks;
|
|
19165
|
+
const fromId = from ? blockIdForLocator(from, "from") : null;
|
|
19166
|
+
const toId = to ? blockIdForLocator(to, "to") : null;
|
|
19167
|
+
const fromIndex = fromId ? blocks.findIndex((b) => b.id === fromId) : 0;
|
|
19168
|
+
if (from && fromId && fromIndex === -1) {
|
|
19169
|
+
throw new MarkdownLocatorError(from, `--from ${from} not found at document top level`);
|
|
19170
|
+
}
|
|
19171
|
+
const toIndex = toId ? blocks.findIndex((b) => b.id === toId) : blocks.length - 1;
|
|
19172
|
+
if (to && toId && toIndex === -1) {
|
|
19173
|
+
throw new MarkdownLocatorError(to, `--to ${to} not found at document top level`);
|
|
19174
|
+
}
|
|
19175
|
+
if (toIndex < fromIndex)
|
|
19176
|
+
return [];
|
|
19177
|
+
return blocks.slice(fromIndex, toIndex + 1);
|
|
19178
|
+
}
|
|
19179
|
+
function blockIdForLocator(input, position) {
|
|
17785
19180
|
let parsed;
|
|
17786
19181
|
try {
|
|
17787
|
-
parsed =
|
|
17788
|
-
|
|
17789
|
-
|
|
17790
|
-
|
|
17791
|
-
|
|
17792
|
-
|
|
17793
|
-
}
|
|
17794
|
-
});
|
|
17795
|
-
} catch (parseError) {
|
|
17796
|
-
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
17797
|
-
return fail("USAGE", message, HELP19);
|
|
17798
|
-
}
|
|
17799
|
-
if (parsed.values.help) {
|
|
17800
|
-
await writeStdout(HELP19);
|
|
17801
|
-
return EXIT.OK;
|
|
19182
|
+
parsed = parseLocator(input);
|
|
19183
|
+
} catch (err) {
|
|
19184
|
+
if (err instanceof LocatorParseError) {
|
|
19185
|
+
throw new MarkdownLocatorError(input, err.message);
|
|
19186
|
+
}
|
|
19187
|
+
throw err;
|
|
17802
19188
|
}
|
|
17803
|
-
|
|
17804
|
-
|
|
17805
|
-
|
|
17806
|
-
|
|
17807
|
-
|
|
17808
|
-
|
|
19189
|
+
switch (parsed.kind) {
|
|
19190
|
+
case "block":
|
|
19191
|
+
return parsed.blockId;
|
|
19192
|
+
case "blockSpan":
|
|
19193
|
+
return parsed.blockId;
|
|
19194
|
+
case "range":
|
|
19195
|
+
return position === "from" ? parsed.start.blockId : parsed.end.blockId;
|
|
19196
|
+
case "cell":
|
|
19197
|
+
return parsed.tableId;
|
|
19198
|
+
case "comment":
|
|
19199
|
+
case "image":
|
|
19200
|
+
case "hyperlink":
|
|
19201
|
+
throw new MarkdownLocatorError(input, `--${position} does not accept a ${parsed.kind} locator \u2014 use a paragraph or table locator`);
|
|
17809
19202
|
}
|
|
17810
|
-
const view = await openOrFail(path);
|
|
17811
|
-
if (typeof view === "number")
|
|
17812
|
-
return view;
|
|
17813
|
-
const outline = buildOutline(view.doc, { stylePrefix });
|
|
17814
|
-
await respond({
|
|
17815
|
-
ok: true,
|
|
17816
|
-
operation: "outline",
|
|
17817
|
-
path,
|
|
17818
|
-
stylePrefix,
|
|
17819
|
-
outline
|
|
17820
|
-
});
|
|
17821
|
-
return EXIT.OK;
|
|
17822
19203
|
}
|
|
17823
|
-
var
|
|
17824
|
-
|
|
17825
|
-
|
|
17826
|
-
|
|
17827
|
-
|
|
17828
|
-
|
|
17829
|
-
|
|
17830
|
-
|
|
17831
|
-
|
|
17832
|
-
|
|
17833
|
-
|
|
17834
|
-
Paragraphs nested inside table cells are skipped \u2014 outlines reflect the
|
|
17835
|
-
document's structural skeleton, not embedded labels. Lower levels nest under
|
|
17836
|
-
higher ones; missing intermediate levels nest directly (H1 \u2192 H3 is fine).
|
|
17837
|
-
|
|
17838
|
-
Output is JSON: an array of entries, each shaped like
|
|
17839
|
-
{ id, locator, level, style, text, children }.
|
|
17840
|
-
|
|
17841
|
-
Examples:
|
|
17842
|
-
docx outline doc.docx
|
|
17843
|
-
docx outline doc.docx --style-prefix "Section"
|
|
17844
|
-
docx outline doc.docx | jq '.outline[].text'
|
|
17845
|
-
`;
|
|
17846
|
-
var init_outline = __esm(() => {
|
|
17847
|
-
init_respond();
|
|
19204
|
+
var MarkdownLocatorError;
|
|
19205
|
+
var init_markdown = __esm(() => {
|
|
19206
|
+
init_core();
|
|
19207
|
+
MarkdownLocatorError = class MarkdownLocatorError extends Error {
|
|
19208
|
+
input;
|
|
19209
|
+
constructor(input, message) {
|
|
19210
|
+
super(message);
|
|
19211
|
+
this.input = input;
|
|
19212
|
+
this.name = "MarkdownLocatorError";
|
|
19213
|
+
}
|
|
19214
|
+
};
|
|
17848
19215
|
});
|
|
17849
19216
|
|
|
17850
19217
|
// src/cli/read/index.ts
|
|
17851
19218
|
var exports_read = {};
|
|
17852
19219
|
__export(exports_read, {
|
|
17853
|
-
run: () =>
|
|
19220
|
+
run: () => run25
|
|
17854
19221
|
});
|
|
17855
|
-
import { parseArgs as
|
|
17856
|
-
async function
|
|
19222
|
+
import { parseArgs as parseArgs21 } from "util";
|
|
19223
|
+
async function run25(args) {
|
|
17857
19224
|
let parsed;
|
|
17858
19225
|
try {
|
|
17859
|
-
parsed =
|
|
19226
|
+
parsed = parseArgs21({
|
|
17860
19227
|
args,
|
|
17861
19228
|
allowPositionals: true,
|
|
17862
19229
|
options: {
|
|
17863
|
-
|
|
19230
|
+
markdown: { type: "boolean" },
|
|
19231
|
+
from: { type: "string" },
|
|
19232
|
+
to: { type: "string" },
|
|
19233
|
+
changes: { type: "boolean" },
|
|
19234
|
+
comments: { type: "boolean" },
|
|
17864
19235
|
help: { type: "boolean", short: "h" }
|
|
17865
19236
|
}
|
|
17866
19237
|
});
|
|
17867
19238
|
} catch (e) {
|
|
17868
|
-
return fail("USAGE", e instanceof Error ? e.message : String(e),
|
|
19239
|
+
return fail("USAGE", e instanceof Error ? e.message : String(e), HELP25);
|
|
17869
19240
|
}
|
|
17870
19241
|
if (parsed.values.help) {
|
|
17871
|
-
await writeStdout(
|
|
19242
|
+
await writeStdout(HELP25);
|
|
17872
19243
|
return EXIT.OK;
|
|
17873
19244
|
}
|
|
17874
19245
|
const path = parsed.positionals[0];
|
|
17875
19246
|
if (!path)
|
|
17876
|
-
return fail("USAGE", "Missing FILE argument",
|
|
19247
|
+
return fail("USAGE", "Missing FILE argument", HELP25);
|
|
19248
|
+
const markdown = Boolean(parsed.values.markdown);
|
|
19249
|
+
const from = parsed.values.from;
|
|
19250
|
+
const to = parsed.values.to;
|
|
19251
|
+
const showChanges = Boolean(parsed.values.changes);
|
|
19252
|
+
const showComments = Boolean(parsed.values.comments);
|
|
19253
|
+
if (!markdown && (from || to || showChanges || showComments)) {
|
|
19254
|
+
return fail("USAGE", "--from, --to, --changes, and --comments require --markdown", HELP25);
|
|
19255
|
+
}
|
|
17877
19256
|
const view = await openOrFail(path);
|
|
17878
19257
|
if (typeof view === "number")
|
|
17879
19258
|
return view;
|
|
19259
|
+
if (markdown) {
|
|
19260
|
+
try {
|
|
19261
|
+
const rendered = renderMarkdown(view.doc, {
|
|
19262
|
+
from,
|
|
19263
|
+
to,
|
|
19264
|
+
showChanges,
|
|
19265
|
+
showComments
|
|
19266
|
+
});
|
|
19267
|
+
await writeStdout(rendered);
|
|
19268
|
+
return EXIT.OK;
|
|
19269
|
+
} catch (err) {
|
|
19270
|
+
if (err instanceof MarkdownLocatorError) {
|
|
19271
|
+
return fail("INVALID_LOCATOR", err.message);
|
|
19272
|
+
}
|
|
19273
|
+
throw err;
|
|
19274
|
+
}
|
|
19275
|
+
}
|
|
17880
19276
|
await enrichImageHashes(view);
|
|
17881
19277
|
await respond(view.doc);
|
|
17882
19278
|
return EXIT.OK;
|
|
17883
19279
|
}
|
|
17884
|
-
var
|
|
19280
|
+
var HELP25 = `docx read \u2014 print AST as JSON, or render document body as Markdown
|
|
17885
19281
|
|
|
17886
19282
|
Usage:
|
|
17887
19283
|
docx read FILE [options]
|
|
17888
19284
|
|
|
17889
19285
|
Options:
|
|
17890
|
-
--
|
|
17891
|
-
|
|
19286
|
+
--markdown Render the body as GitHub-flavored Markdown
|
|
19287
|
+
(instead of JSON). Locators are emitted as
|
|
19288
|
+
<!-- pN --> HTML comments after each paragraph and
|
|
19289
|
+
inside cell content (invisible in rendered view,
|
|
19290
|
+
but parseable from raw markdown).
|
|
19291
|
+
--from LOC Start markdown rendering at top-level block LOC (inclusive)
|
|
19292
|
+
--to LOC End markdown rendering at top-level block LOC (inclusive)
|
|
19293
|
+
Accepts pN, tN, tN:rRcC[:pK[:S-E]], pN:S-E, pN:S-pM:E.
|
|
19294
|
+
Cell/span/range locators collapse to their enclosing
|
|
19295
|
+
top-level block (the table or paragraph).
|
|
19296
|
+
--changes With --markdown, render tracked insertions/deletions as
|
|
19297
|
+
<ins>/<del> instead of producing the accepted view.
|
|
19298
|
+
--comments With --markdown, append [^cN] after each commented span
|
|
19299
|
+
and emit a footnote definition for each comment at the
|
|
19300
|
+
end of the output (author, date, body).
|
|
19301
|
+
-h, --help Show this help
|
|
17892
19302
|
|
|
17893
19303
|
Examples:
|
|
17894
19304
|
docx read input.docx
|
|
19305
|
+
docx read input.docx --markdown
|
|
19306
|
+
docx read input.docx --markdown --from p3 --to p20
|
|
19307
|
+
docx read input.docx --markdown --changes --comments
|
|
17895
19308
|
docx read input.docx | jq '.blocks[] | select(.type == "paragraph")'
|
|
17896
19309
|
`;
|
|
17897
19310
|
var init_read2 = __esm(() => {
|
|
17898
19311
|
init_core();
|
|
17899
19312
|
init_respond();
|
|
19313
|
+
init_markdown();
|
|
17900
19314
|
});
|
|
17901
19315
|
|
|
17902
19316
|
// src/cli/replace/replace-span.tsx
|
|
@@ -17939,7 +19353,7 @@ function collectRunSlots(paragraph) {
|
|
|
17939
19353
|
offset += length;
|
|
17940
19354
|
continue;
|
|
17941
19355
|
}
|
|
17942
|
-
if (child.tag === "w:ins" || child.tag === "w:del") {
|
|
19356
|
+
if (child.tag === "w:ins" || child.tag === "w:del" || child.tag === "w:hyperlink") {
|
|
17943
19357
|
for (const inner of child.children) {
|
|
17944
19358
|
if (inner.tag !== "w:r")
|
|
17945
19359
|
continue;
|
|
@@ -17964,14 +19378,14 @@ function rebuildContainer(container, baseOffset, span, replacement, runPropertie
|
|
|
17964
19378
|
if (placed)
|
|
17965
19379
|
return;
|
|
17966
19380
|
placed = true;
|
|
17967
|
-
const
|
|
19381
|
+
const run26 = /* @__PURE__ */ jsxDEV(ReplacementRun, {
|
|
17968
19382
|
runProperties,
|
|
17969
19383
|
text: replacement
|
|
17970
19384
|
}, undefined, false, undefined, this);
|
|
17971
19385
|
newChildren.push(tracked && isParagraph ? /* @__PURE__ */ jsxDEV(Ins, {
|
|
17972
19386
|
meta: mintMeta(tracked),
|
|
17973
|
-
children:
|
|
17974
|
-
}, undefined, false, undefined, this) :
|
|
19387
|
+
children: run26
|
|
19388
|
+
}, undefined, false, undefined, this) : run26);
|
|
17975
19389
|
};
|
|
17976
19390
|
for (const child of container.children) {
|
|
17977
19391
|
if (child.tag === "w:r") {
|
|
@@ -18007,7 +19421,7 @@ function rebuildContainer(container, baseOffset, span, replacement, runPropertie
|
|
|
18007
19421
|
}
|
|
18008
19422
|
continue;
|
|
18009
19423
|
}
|
|
18010
|
-
if (isParagraph && (child.tag === "w:ins" || child.tag === "w:del")) {
|
|
19424
|
+
if (isParagraph && (child.tag === "w:ins" || child.tag === "w:del" || child.tag === "w:hyperlink")) {
|
|
18011
19425
|
let innerLength = 0;
|
|
18012
19426
|
for (const inner of child.children) {
|
|
18013
19427
|
if (inner.tag === "w:r")
|
|
@@ -18031,14 +19445,14 @@ function rebuildAcrossBoundaries(paragraph, span, replacement, runProperties, tr
|
|
|
18031
19445
|
if (placed)
|
|
18032
19446
|
return;
|
|
18033
19447
|
placed = true;
|
|
18034
|
-
const
|
|
19448
|
+
const run26 = /* @__PURE__ */ jsxDEV(ReplacementRun, {
|
|
18035
19449
|
runProperties,
|
|
18036
19450
|
text: replacement
|
|
18037
19451
|
}, undefined, false, undefined, this);
|
|
18038
19452
|
newChildren.push(tracked ? /* @__PURE__ */ jsxDEV(Ins, {
|
|
18039
19453
|
meta: mintMeta(tracked),
|
|
18040
|
-
children:
|
|
18041
|
-
}, undefined, false, undefined, this) :
|
|
19454
|
+
children: run26
|
|
19455
|
+
}, undefined, false, undefined, this) : run26);
|
|
18042
19456
|
};
|
|
18043
19457
|
for (const child of paragraph.children) {
|
|
18044
19458
|
if (child.tag === "w:r") {
|
|
@@ -18075,7 +19489,7 @@ function rebuildAcrossBoundaries(paragraph, span, replacement, runProperties, tr
|
|
|
18075
19489
|
continue;
|
|
18076
19490
|
}
|
|
18077
19491
|
if (child.tag === "w:ins" || child.tag === "w:del") {
|
|
18078
|
-
const innerLength =
|
|
19492
|
+
const innerLength = sumInnerRunLengths2(child);
|
|
18079
19493
|
const wrapperStart = offset;
|
|
18080
19494
|
const wrapperEnd = offset + innerLength;
|
|
18081
19495
|
offset = wrapperEnd;
|
|
@@ -18091,6 +19505,25 @@ function rebuildAcrossBoundaries(paragraph, span, replacement, runProperties, tr
|
|
|
18091
19505
|
splitWrapperAcrossSpan(child, wrapperStart, span, tracked, newChildren, placeReplacement);
|
|
18092
19506
|
continue;
|
|
18093
19507
|
}
|
|
19508
|
+
if (child.tag === "w:hyperlink") {
|
|
19509
|
+
const innerLength = sumInnerRunLengths2(child);
|
|
19510
|
+
const wrapperStart = offset;
|
|
19511
|
+
const wrapperEnd = offset + innerLength;
|
|
19512
|
+
offset = wrapperEnd;
|
|
19513
|
+
if (wrapperEnd <= span.start) {
|
|
19514
|
+
newChildren.push(child);
|
|
19515
|
+
continue;
|
|
19516
|
+
}
|
|
19517
|
+
if (wrapperStart >= span.end) {
|
|
19518
|
+
placeReplacement();
|
|
19519
|
+
newChildren.push(child);
|
|
19520
|
+
continue;
|
|
19521
|
+
}
|
|
19522
|
+
splitHyperlinkAcrossSpan(child, wrapperStart, span, runProperties, replacement, tracked, newChildren, placeReplacement, () => {
|
|
19523
|
+
placed = true;
|
|
19524
|
+
});
|
|
19525
|
+
continue;
|
|
19526
|
+
}
|
|
18094
19527
|
newChildren.push(child);
|
|
18095
19528
|
}
|
|
18096
19529
|
if (!placed)
|
|
@@ -18151,7 +19584,62 @@ function splitWrapperAcrossSpan(wrapper, wrapperStart, span, tracked, out, place
|
|
|
18151
19584
|
out.push(postWrapper);
|
|
18152
19585
|
}
|
|
18153
19586
|
}
|
|
18154
|
-
function
|
|
19587
|
+
function splitHyperlinkAcrossSpan(wrapper, wrapperStart, span, runProperties, replacement, tracked, out, placeReplacement, markReplacementPlaced) {
|
|
19588
|
+
const wrapperEnd = wrapperStart + wrapper.children.reduce((total, inner) => inner.tag === "w:r" ? total + runTextLength(inner) : total, 0);
|
|
19589
|
+
const startsInside = span.start > wrapperStart && span.start < wrapperEnd;
|
|
19590
|
+
const preInner = [];
|
|
19591
|
+
const postInner = [];
|
|
19592
|
+
let innerOffset = wrapperStart;
|
|
19593
|
+
for (const inner of wrapper.children) {
|
|
19594
|
+
if (inner.tag !== "w:r") {
|
|
19595
|
+
preInner.push(inner);
|
|
19596
|
+
continue;
|
|
19597
|
+
}
|
|
19598
|
+
const length = runTextLength(inner);
|
|
19599
|
+
const runStart = innerOffset;
|
|
19600
|
+
const runEnd = innerOffset + length;
|
|
19601
|
+
innerOffset = runEnd;
|
|
19602
|
+
if (runEnd <= span.start) {
|
|
19603
|
+
preInner.push(inner);
|
|
19604
|
+
continue;
|
|
19605
|
+
}
|
|
19606
|
+
if (runStart >= span.end) {
|
|
19607
|
+
postInner.push(inner);
|
|
19608
|
+
continue;
|
|
19609
|
+
}
|
|
19610
|
+
const sliceStartInRun = Math.max(0, span.start - runStart);
|
|
19611
|
+
const sliceEndInRun = Math.min(length, span.end - runStart);
|
|
19612
|
+
if (sliceStartInRun > 0)
|
|
19613
|
+
preInner.push(sliceRun(inner, 0, sliceStartInRun));
|
|
19614
|
+
if (sliceEndInRun < length) {
|
|
19615
|
+
postInner.push(sliceRun(inner, sliceEndInRun, length));
|
|
19616
|
+
}
|
|
19617
|
+
}
|
|
19618
|
+
if (startsInside) {
|
|
19619
|
+
const innerReplacement = /* @__PURE__ */ jsxDEV(ReplacementRun, {
|
|
19620
|
+
runProperties,
|
|
19621
|
+
text: replacement
|
|
19622
|
+
}, undefined, false, undefined, this);
|
|
19623
|
+
preInner.push(tracked ? /* @__PURE__ */ jsxDEV(Ins, {
|
|
19624
|
+
meta: mintMeta(tracked),
|
|
19625
|
+
children: innerReplacement
|
|
19626
|
+
}, undefined, false, undefined, this) : innerReplacement);
|
|
19627
|
+
markReplacementPlaced();
|
|
19628
|
+
}
|
|
19629
|
+
if (preInner.length > 0) {
|
|
19630
|
+
const preWrapper = new XmlNode2("w:hyperlink", { ...wrapper.attributes });
|
|
19631
|
+
preWrapper.children = preInner;
|
|
19632
|
+
out.push(preWrapper);
|
|
19633
|
+
}
|
|
19634
|
+
if (!startsInside)
|
|
19635
|
+
placeReplacement();
|
|
19636
|
+
if (postInner.length > 0) {
|
|
19637
|
+
const postWrapper = new XmlNode2("w:hyperlink", { ...wrapper.attributes });
|
|
19638
|
+
postWrapper.children = postInner;
|
|
19639
|
+
out.push(postWrapper);
|
|
19640
|
+
}
|
|
19641
|
+
}
|
|
19642
|
+
function sumInnerRunLengths2(wrapper) {
|
|
18155
19643
|
let total = 0;
|
|
18156
19644
|
for (const inner of wrapper.children) {
|
|
18157
19645
|
if (inner.tag === "w:r")
|
|
@@ -18162,8 +19650,8 @@ function sumInnerRunLengths(wrapper) {
|
|
|
18162
19650
|
function mintMeta(tracked) {
|
|
18163
19651
|
return { ...tracked.meta, revisionId: tracked.allocator.next() };
|
|
18164
19652
|
}
|
|
18165
|
-
function convertRunTextToDelText(
|
|
18166
|
-
for (const child of
|
|
19653
|
+
function convertRunTextToDelText(run26) {
|
|
19654
|
+
for (const child of run26.children) {
|
|
18167
19655
|
if (child.tag === "w:t")
|
|
18168
19656
|
child.tag = "w:delText";
|
|
18169
19657
|
}
|
|
@@ -18190,15 +19678,15 @@ var init_replace_span = __esm(() => {
|
|
|
18190
19678
|
});
|
|
18191
19679
|
|
|
18192
19680
|
// src/cli/replace/index.ts
|
|
18193
|
-
var
|
|
18194
|
-
__export(
|
|
18195
|
-
run: () =>
|
|
19681
|
+
var exports_replace3 = {};
|
|
19682
|
+
__export(exports_replace3, {
|
|
19683
|
+
run: () => run26
|
|
18196
19684
|
});
|
|
18197
|
-
import { parseArgs as
|
|
18198
|
-
async function
|
|
19685
|
+
import { parseArgs as parseArgs22 } from "util";
|
|
19686
|
+
async function run26(args) {
|
|
18199
19687
|
let parsed;
|
|
18200
19688
|
try {
|
|
18201
|
-
parsed =
|
|
19689
|
+
parsed = parseArgs22({
|
|
18202
19690
|
args,
|
|
18203
19691
|
allowPositionals: true,
|
|
18204
19692
|
options: {
|
|
@@ -18213,21 +19701,21 @@ async function run21(args) {
|
|
|
18213
19701
|
});
|
|
18214
19702
|
} catch (parseError) {
|
|
18215
19703
|
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
18216
|
-
return fail("USAGE", message,
|
|
19704
|
+
return fail("USAGE", message, HELP26);
|
|
18217
19705
|
}
|
|
18218
19706
|
if (parsed.values.help) {
|
|
18219
|
-
await writeStdout(
|
|
19707
|
+
await writeStdout(HELP26);
|
|
18220
19708
|
return EXIT.OK;
|
|
18221
19709
|
}
|
|
18222
19710
|
const path = parsed.positionals[0];
|
|
18223
19711
|
const pattern = parsed.positionals[1];
|
|
18224
19712
|
const replacement = parsed.positionals[2];
|
|
18225
19713
|
if (!path)
|
|
18226
|
-
return fail("USAGE", "Missing FILE argument",
|
|
19714
|
+
return fail("USAGE", "Missing FILE argument", HELP26);
|
|
18227
19715
|
if (pattern == null)
|
|
18228
|
-
return fail("USAGE", "Missing PATTERN argument",
|
|
19716
|
+
return fail("USAGE", "Missing PATTERN argument", HELP26);
|
|
18229
19717
|
if (replacement == null) {
|
|
18230
|
-
return fail("USAGE", "Missing REPLACEMENT argument",
|
|
19718
|
+
return fail("USAGE", "Missing REPLACEMENT argument", HELP26);
|
|
18231
19719
|
}
|
|
18232
19720
|
const ignoreCase = Boolean(parsed.values["ignore-case"]);
|
|
18233
19721
|
const useRegex = Boolean(parsed.values.regex);
|
|
@@ -18329,7 +19817,7 @@ async function run21(args) {
|
|
|
18329
19817
|
});
|
|
18330
19818
|
return EXIT.OK;
|
|
18331
19819
|
}
|
|
18332
|
-
var
|
|
19820
|
+
var HELP26 = `docx replace \u2014 substitute text spans (sed for docx)
|
|
18333
19821
|
|
|
18334
19822
|
Usage:
|
|
18335
19823
|
docx replace FILE PATTERN REPLACEMENT [options]
|
|
@@ -18363,7 +19851,7 @@ Examples:
|
|
|
18363
19851
|
docx replace doc.docx "(\\w+) (\\w+)" "$2 $1" --regex --all
|
|
18364
19852
|
docx replace doc.docx "wordy phrase" "tighter phrase" --all --dry-run
|
|
18365
19853
|
`;
|
|
18366
|
-
var
|
|
19854
|
+
var init_replace3 = __esm(() => {
|
|
18367
19855
|
init_core();
|
|
18368
19856
|
init_respond();
|
|
18369
19857
|
init_replace_span();
|
|
@@ -18372,13 +19860,13 @@ var init_replace2 = __esm(() => {
|
|
|
18372
19860
|
// src/cli/track-changes/index.tsx
|
|
18373
19861
|
var exports_track_changes = {};
|
|
18374
19862
|
__export(exports_track_changes, {
|
|
18375
|
-
run: () =>
|
|
19863
|
+
run: () => run27
|
|
18376
19864
|
});
|
|
18377
|
-
import { parseArgs as
|
|
18378
|
-
async function
|
|
19865
|
+
import { parseArgs as parseArgs23 } from "util";
|
|
19866
|
+
async function run27(args) {
|
|
18379
19867
|
let parsed;
|
|
18380
19868
|
try {
|
|
18381
|
-
parsed =
|
|
19869
|
+
parsed = parseArgs23({
|
|
18382
19870
|
args,
|
|
18383
19871
|
allowPositionals: true,
|
|
18384
19872
|
options: {
|
|
@@ -18389,18 +19877,18 @@ async function run22(args) {
|
|
|
18389
19877
|
});
|
|
18390
19878
|
} catch (parseError) {
|
|
18391
19879
|
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
18392
|
-
return fail("USAGE", message,
|
|
19880
|
+
return fail("USAGE", message, HELP27);
|
|
18393
19881
|
}
|
|
18394
19882
|
if (parsed.values.help) {
|
|
18395
|
-
await writeStdout(
|
|
19883
|
+
await writeStdout(HELP27);
|
|
18396
19884
|
return EXIT.OK;
|
|
18397
19885
|
}
|
|
18398
19886
|
const path = parsed.positionals[0];
|
|
18399
19887
|
if (!path)
|
|
18400
|
-
return fail("USAGE", "Missing FILE argument",
|
|
19888
|
+
return fail("USAGE", "Missing FILE argument", HELP27);
|
|
18401
19889
|
const mode = parsed.positionals[1];
|
|
18402
19890
|
if (mode !== "on" && mode !== "off") {
|
|
18403
|
-
return fail("USAGE", `Expected "on" or "off", got: ${mode ?? "<nothing>"}`,
|
|
19891
|
+
return fail("USAGE", `Expected "on" or "off", got: ${mode ?? "<nothing>"}`, HELP27);
|
|
18404
19892
|
}
|
|
18405
19893
|
const view = await openOrFail(path);
|
|
18406
19894
|
if (typeof view === "number")
|
|
@@ -18452,7 +19940,7 @@ async function run22(args) {
|
|
|
18452
19940
|
});
|
|
18453
19941
|
return EXIT.OK;
|
|
18454
19942
|
}
|
|
18455
|
-
var
|
|
19943
|
+
var HELP27 = `docx track-changes \u2014 toggle the document's tracked-changes mode
|
|
18456
19944
|
|
|
18457
19945
|
Usage:
|
|
18458
19946
|
docx track-changes FILE on|off [options]
|
|
@@ -18485,19 +19973,11 @@ function countWords(text) {
|
|
|
18485
19973
|
const matches = text.match(/\S+/g);
|
|
18486
19974
|
return matches?.length ?? 0;
|
|
18487
19975
|
}
|
|
18488
|
-
function paragraphText2(paragraph) {
|
|
18489
|
-
let out = "";
|
|
18490
|
-
for (const run23 of paragraph.runs) {
|
|
18491
|
-
if (run23.type === "text")
|
|
18492
|
-
out += run23.text;
|
|
18493
|
-
}
|
|
18494
|
-
return out;
|
|
18495
|
-
}
|
|
18496
19976
|
function countWordsInBlocks(blocks) {
|
|
18497
19977
|
let total = 0;
|
|
18498
19978
|
for (const block of blocks) {
|
|
18499
19979
|
if (block.type === "paragraph") {
|
|
18500
|
-
total += countWords(
|
|
19980
|
+
total += countWords(paragraphText(block));
|
|
18501
19981
|
} else if (block.type === "table") {
|
|
18502
19982
|
for (const row of block.rows) {
|
|
18503
19983
|
for (const cell of row.cells) {
|
|
@@ -18508,24 +19988,8 @@ function countWordsInBlocks(blocks) {
|
|
|
18508
19988
|
}
|
|
18509
19989
|
return total;
|
|
18510
19990
|
}
|
|
18511
|
-
function findBlockById(blocks, blockId) {
|
|
18512
|
-
for (const block of blocks) {
|
|
18513
|
-
if (block.id === blockId)
|
|
18514
|
-
return block;
|
|
18515
|
-
if (block.type === "table") {
|
|
18516
|
-
for (const row of block.rows) {
|
|
18517
|
-
for (const cell of row.cells) {
|
|
18518
|
-
const inner = findBlockById(cell.blocks, blockId);
|
|
18519
|
-
if (inner)
|
|
18520
|
-
return inner;
|
|
18521
|
-
}
|
|
18522
|
-
}
|
|
18523
|
-
}
|
|
18524
|
-
}
|
|
18525
|
-
return null;
|
|
18526
|
-
}
|
|
18527
19991
|
function countWordsInParagraphSpan(paragraph, start, end) {
|
|
18528
|
-
const text =
|
|
19992
|
+
const text = paragraphText(paragraph);
|
|
18529
19993
|
const clampedEnd = Math.min(Math.max(end, 0), text.length);
|
|
18530
19994
|
const clampedStart = Math.min(Math.max(start, 0), clampedEnd);
|
|
18531
19995
|
return countWords(text.slice(clampedStart, clampedEnd));
|
|
@@ -18546,46 +20010,32 @@ function countWordsInRange(paragraphsInOrder, startBlockId, startOffset, endBloc
|
|
|
18546
20010
|
let total = 0;
|
|
18547
20011
|
const first = paragraphsInOrder[startIndex];
|
|
18548
20012
|
if (first) {
|
|
18549
|
-
total += countWordsInParagraphSpan(first, startOffset,
|
|
20013
|
+
total += countWordsInParagraphSpan(first, startOffset, paragraphText(first).length);
|
|
18550
20014
|
}
|
|
18551
20015
|
for (let index = startIndex + 1;index < endIndex; index++) {
|
|
18552
20016
|
const middle = paragraphsInOrder[index];
|
|
18553
20017
|
if (middle)
|
|
18554
|
-
total += countWords(
|
|
20018
|
+
total += countWords(paragraphText(middle));
|
|
18555
20019
|
}
|
|
18556
20020
|
const last = paragraphsInOrder[endIndex];
|
|
18557
20021
|
if (last)
|
|
18558
20022
|
total += countWordsInParagraphSpan(last, 0, endOffset);
|
|
18559
20023
|
return total;
|
|
18560
20024
|
}
|
|
18561
|
-
|
|
18562
|
-
|
|
18563
|
-
|
|
18564
|
-
if (block.type === "paragraph") {
|
|
18565
|
-
out.push(block);
|
|
18566
|
-
continue;
|
|
18567
|
-
}
|
|
18568
|
-
if (block.type === "table") {
|
|
18569
|
-
for (const row of block.rows) {
|
|
18570
|
-
for (const cell of row.cells) {
|
|
18571
|
-
out.push(...flattenParagraphs(cell.blocks));
|
|
18572
|
-
}
|
|
18573
|
-
}
|
|
18574
|
-
}
|
|
18575
|
-
}
|
|
18576
|
-
return out;
|
|
18577
|
-
}
|
|
20025
|
+
var init_count = __esm(() => {
|
|
20026
|
+
init_core();
|
|
20027
|
+
});
|
|
18578
20028
|
|
|
18579
20029
|
// src/cli/wc/index.ts
|
|
18580
20030
|
var exports_wc = {};
|
|
18581
20031
|
__export(exports_wc, {
|
|
18582
|
-
run: () =>
|
|
20032
|
+
run: () => run28
|
|
18583
20033
|
});
|
|
18584
|
-
import { parseArgs as
|
|
18585
|
-
async function
|
|
20034
|
+
import { parseArgs as parseArgs24 } from "util";
|
|
20035
|
+
async function run28(args) {
|
|
18586
20036
|
let parsed;
|
|
18587
20037
|
try {
|
|
18588
|
-
parsed =
|
|
20038
|
+
parsed = parseArgs24({
|
|
18589
20039
|
args,
|
|
18590
20040
|
allowPositionals: true,
|
|
18591
20041
|
options: {
|
|
@@ -18594,16 +20044,16 @@ async function run23(args) {
|
|
|
18594
20044
|
});
|
|
18595
20045
|
} catch (parseError) {
|
|
18596
20046
|
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
18597
|
-
return fail("USAGE", message,
|
|
20047
|
+
return fail("USAGE", message, HELP28);
|
|
18598
20048
|
}
|
|
18599
20049
|
if (parsed.values.help) {
|
|
18600
|
-
await writeStdout(
|
|
20050
|
+
await writeStdout(HELP28);
|
|
18601
20051
|
return EXIT.OK;
|
|
18602
20052
|
}
|
|
18603
20053
|
const path = parsed.positionals[0];
|
|
18604
20054
|
const locatorInput = parsed.positionals[1];
|
|
18605
20055
|
if (!path)
|
|
18606
|
-
return fail("USAGE", "Missing FILE argument",
|
|
20056
|
+
return fail("USAGE", "Missing FILE argument", HELP28);
|
|
18607
20057
|
const view = await openOrFail(path);
|
|
18608
20058
|
if (typeof view === "number")
|
|
18609
20059
|
return view;
|
|
@@ -18635,7 +20085,7 @@ async function run23(args) {
|
|
|
18635
20085
|
if (!block) {
|
|
18636
20086
|
return fail("BLOCK_NOT_FOUND", `Block not found: ${locator.blockId}`);
|
|
18637
20087
|
}
|
|
18638
|
-
const words = block.type === "paragraph" ? countWords(
|
|
20088
|
+
const words = block.type === "paragraph" ? countWords(paragraphText(block)) : block.type === "table" ? countWordsInBlocks([block]) : 0;
|
|
18639
20089
|
await respond({
|
|
18640
20090
|
ok: true,
|
|
18641
20091
|
operation: "wc",
|
|
@@ -18707,7 +20157,7 @@ async function run23(args) {
|
|
|
18707
20157
|
if (!block || block.type !== "paragraph") {
|
|
18708
20158
|
return fail("BLOCK_NOT_FOUND", `Paragraph not found: ${composedId}`);
|
|
18709
20159
|
}
|
|
18710
|
-
const words = locator.inner.kind === "blockSpan" ? countWordsInParagraphSpan(block, locator.inner.start, locator.inner.end) : countWords(
|
|
20160
|
+
const words = locator.inner.kind === "blockSpan" ? countWordsInParagraphSpan(block, locator.inner.start, locator.inner.end) : countWords(paragraphText(block));
|
|
18711
20161
|
await respond({
|
|
18712
20162
|
ok: true,
|
|
18713
20163
|
operation: "wc",
|
|
@@ -18732,7 +20182,7 @@ function findCellBlocks(blocks, locator) {
|
|
|
18732
20182
|
return null;
|
|
18733
20183
|
return cell.blocks;
|
|
18734
20184
|
}
|
|
18735
|
-
var
|
|
20185
|
+
var HELP28 = `docx wc \u2014 count words in a document or a locator-addressed slice
|
|
18736
20186
|
|
|
18737
20187
|
Usage:
|
|
18738
20188
|
docx wc FILE [LOCATOR] [options]
|
|
@@ -18765,11 +20215,12 @@ Examples:
|
|
|
18765
20215
|
var init_wc = __esm(() => {
|
|
18766
20216
|
init_core();
|
|
18767
20217
|
init_respond();
|
|
20218
|
+
init_count();
|
|
18768
20219
|
});
|
|
18769
20220
|
// package.json
|
|
18770
20221
|
var package_default = {
|
|
18771
20222
|
name: "bun-docx",
|
|
18772
|
-
version: "0.
|
|
20223
|
+
version: "0.6.0",
|
|
18773
20224
|
description: "CLI for AI agents (Claude, Codex) to read, edit, and comment on .docx files with full format fidelity.",
|
|
18774
20225
|
keywords: [
|
|
18775
20226
|
"docx",
|
|
@@ -18848,6 +20299,7 @@ Commands:
|
|
|
18848
20299
|
outline FILE List headings as a hierarchical tree
|
|
18849
20300
|
comments \u2026 Add, reply, resolve, delete, list comments
|
|
18850
20301
|
images \u2026 Extract, replace, list images
|
|
20302
|
+
hyperlinks \u2026 List, replace hyperlinks
|
|
18851
20303
|
track-changes FILE on|off Toggle tracked-changes mode
|
|
18852
20304
|
info \u2026 Reference material (schema, locators)
|
|
18853
20305
|
|
|
@@ -18874,12 +20326,13 @@ var COMMANDS = {
|
|
|
18874
20326
|
delete: () => Promise.resolve().then(() => (init_delete2(), exports_delete2)),
|
|
18875
20327
|
edit: () => Promise.resolve().then(() => (init_edit(), exports_edit)),
|
|
18876
20328
|
find: () => Promise.resolve().then(() => (init_find(), exports_find)),
|
|
20329
|
+
hyperlinks: () => Promise.resolve().then(() => (init_hyperlinks(), exports_hyperlinks)),
|
|
18877
20330
|
images: () => Promise.resolve().then(() => (init_images(), exports_images)),
|
|
18878
20331
|
info: () => Promise.resolve().then(() => (init_info(), exports_info)),
|
|
18879
20332
|
insert: () => Promise.resolve().then(() => (init_insert(), exports_insert)),
|
|
18880
20333
|
outline: () => Promise.resolve().then(() => (init_outline(), exports_outline)),
|
|
18881
20334
|
read: () => Promise.resolve().then(() => (init_read2(), exports_read)),
|
|
18882
|
-
replace: () => Promise.resolve().then(() => (
|
|
20335
|
+
replace: () => Promise.resolve().then(() => (init_replace3(), exports_replace3)),
|
|
18883
20336
|
"track-changes": () => Promise.resolve().then(() => (init_track_changes2(), exports_track_changes)),
|
|
18884
20337
|
wc: () => Promise.resolve().then(() => (init_wc(), exports_wc))
|
|
18885
20338
|
};
|