bun-docx 0.4.0 → 0.5.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 +10 -2
- package/dist/index.js +1107 -297
- 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,6 +13774,7 @@ 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
|
};
|
|
@@ -13813,17 +13814,30 @@ function readParagraph(view, node, id, state) {
|
|
|
13813
13814
|
if (paragraphProperties) {
|
|
13814
13815
|
applyParagraphProperties(paragraph, paragraphProperties);
|
|
13815
13816
|
}
|
|
13816
|
-
const
|
|
13817
|
-
|
|
13818
|
-
|
|
13817
|
+
const context = {
|
|
13818
|
+
view,
|
|
13819
|
+
blockId: id,
|
|
13820
|
+
paragraph,
|
|
13821
|
+
activeComments: new Set,
|
|
13822
|
+
state,
|
|
13823
|
+
offsetRef: { value: 0 }
|
|
13824
|
+
};
|
|
13825
|
+
walkRunContainer(context, node, undefined, undefined);
|
|
13826
|
+
return paragraph;
|
|
13827
|
+
}
|
|
13828
|
+
function walkRunContainer(context, container, trackedChange, hyperlink) {
|
|
13829
|
+
for (const child of container.children) {
|
|
13819
13830
|
if (child.tag === "w:pPr")
|
|
13820
13831
|
continue;
|
|
13821
13832
|
if (child.tag === "w:commentRangeStart") {
|
|
13822
13833
|
const commentId = child.getAttribute("w:id");
|
|
13823
13834
|
if (commentId) {
|
|
13824
13835
|
const key = `c${commentId}`;
|
|
13825
|
-
activeComments.add(key);
|
|
13826
|
-
state.openComments.set(key, {
|
|
13836
|
+
context.activeComments.add(key);
|
|
13837
|
+
context.state.openComments.set(key, {
|
|
13838
|
+
blockId: context.blockId,
|
|
13839
|
+
offset: context.offsetRef.value
|
|
13840
|
+
});
|
|
13827
13841
|
}
|
|
13828
13842
|
continue;
|
|
13829
13843
|
}
|
|
@@ -13831,26 +13845,26 @@ function readParagraph(view, node, id, state) {
|
|
|
13831
13845
|
const commentId = child.getAttribute("w:id");
|
|
13832
13846
|
if (commentId) {
|
|
13833
13847
|
const key = `c${commentId}`;
|
|
13834
|
-
activeComments.delete(key);
|
|
13835
|
-
const opened = state.openComments.get(key);
|
|
13848
|
+
context.activeComments.delete(key);
|
|
13849
|
+
const opened = context.state.openComments.get(key);
|
|
13836
13850
|
if (opened) {
|
|
13837
|
-
state.commentAnchors.set(key, {
|
|
13851
|
+
context.state.commentAnchors.set(key, {
|
|
13838
13852
|
startBlockId: opened.blockId,
|
|
13839
13853
|
startOffset: opened.offset,
|
|
13840
|
-
endBlockId:
|
|
13841
|
-
endOffset:
|
|
13854
|
+
endBlockId: context.blockId,
|
|
13855
|
+
endOffset: context.offsetRef.value
|
|
13842
13856
|
});
|
|
13843
|
-
state.openComments.delete(key);
|
|
13857
|
+
context.state.openComments.delete(key);
|
|
13844
13858
|
}
|
|
13845
13859
|
}
|
|
13846
13860
|
continue;
|
|
13847
13861
|
}
|
|
13848
13862
|
if (child.tag === "w:r") {
|
|
13849
|
-
const run = readRun(view, child, activeComments,
|
|
13863
|
+
const run = readRun(context.view, child, context.activeComments, trackedChange, hyperlink, context.state);
|
|
13850
13864
|
if (run) {
|
|
13851
13865
|
if (run.type === "text")
|
|
13852
|
-
|
|
13853
|
-
paragraph.runs.push(run);
|
|
13866
|
+
context.offsetRef.value += run.text.length;
|
|
13867
|
+
context.paragraph.runs.push(run);
|
|
13854
13868
|
}
|
|
13855
13869
|
continue;
|
|
13856
13870
|
}
|
|
@@ -13861,46 +13875,40 @@ function readParagraph(view, node, id, state) {
|
|
|
13861
13875
|
date: child.getAttribute("w:date") ?? "",
|
|
13862
13876
|
revisionId: child.getAttribute("w:id") ?? ""
|
|
13863
13877
|
};
|
|
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
|
-
}
|
|
13878
|
+
walkRunContainer(context, child, change, hyperlink);
|
|
13879
|
+
continue;
|
|
13880
|
+
}
|
|
13881
|
+
if (child.tag === "w:hyperlink") {
|
|
13882
|
+
const link = readHyperlinkProperties(context.view, child, container.children, context.state);
|
|
13883
|
+
walkRunContainer(context, child, trackedChange, link);
|
|
13901
13884
|
}
|
|
13902
13885
|
}
|
|
13903
|
-
|
|
13886
|
+
}
|
|
13887
|
+
function readHyperlinkProperties(view, node, parent, state) {
|
|
13888
|
+
const id = `link${state.hyperlinkIndex++}`;
|
|
13889
|
+
const link = { id };
|
|
13890
|
+
const relationshipId = node.getAttribute("r:id");
|
|
13891
|
+
if (relationshipId) {
|
|
13892
|
+
const relationship = view.hyperlinksByRelationshipId.get(relationshipId);
|
|
13893
|
+
if (relationship?.url)
|
|
13894
|
+
link.url = relationship.url;
|
|
13895
|
+
}
|
|
13896
|
+
const anchor = node.getAttribute("w:anchor");
|
|
13897
|
+
if (anchor)
|
|
13898
|
+
link.anchor = anchor;
|
|
13899
|
+
const tooltip = node.getAttribute("w:tooltip");
|
|
13900
|
+
if (tooltip)
|
|
13901
|
+
link.tooltip = tooltip;
|
|
13902
|
+
if (!link.url && !link.anchor && !link.tooltip) {
|
|
13903
|
+
state.hyperlinkIndex--;
|
|
13904
|
+
return;
|
|
13905
|
+
}
|
|
13906
|
+
view.hyperlinkById.set(id, {
|
|
13907
|
+
node,
|
|
13908
|
+
parent,
|
|
13909
|
+
...relationshipId ? { relationshipId } : {}
|
|
13910
|
+
});
|
|
13911
|
+
return link;
|
|
13904
13912
|
}
|
|
13905
13913
|
function applyParagraphProperties(paragraph, paragraphProperties) {
|
|
13906
13914
|
const styleNode = paragraphProperties.findChild("w:pStyle");
|
|
@@ -13925,7 +13933,7 @@ function applyParagraphProperties(paragraph, paragraphProperties) {
|
|
|
13925
13933
|
paragraph.list = { level, numId: id };
|
|
13926
13934
|
}
|
|
13927
13935
|
}
|
|
13928
|
-
function readRun(view, node, activeComments, trackedChange, state) {
|
|
13936
|
+
function readRun(view, node, activeComments, trackedChange, hyperlink, state) {
|
|
13929
13937
|
const runProperties = node.findChild("w:rPr");
|
|
13930
13938
|
for (const child of node.children) {
|
|
13931
13939
|
if (child.tag === "w:drawing") {
|
|
@@ -13956,6 +13964,8 @@ function readRun(view, node, activeComments, trackedChange, state) {
|
|
|
13956
13964
|
run.comments = [...activeComments];
|
|
13957
13965
|
if (trackedChange)
|
|
13958
13966
|
run.trackedChange = trackedChange;
|
|
13967
|
+
if (hyperlink)
|
|
13968
|
+
run.hyperlink = hyperlink;
|
|
13959
13969
|
return run;
|
|
13960
13970
|
}
|
|
13961
13971
|
function applyRunProperties(run, runProperties) {
|
|
@@ -14060,22 +14070,30 @@ function readCellBlocks(view, cell, tableId, rowIndex, columnIndex, state) {
|
|
|
14060
14070
|
}
|
|
14061
14071
|
return blocks;
|
|
14062
14072
|
}
|
|
14063
|
-
function
|
|
14073
|
+
function readRelationships(view) {
|
|
14064
14074
|
const relationships = XmlNode2.findRoot(view.relationshipsTree, "Relationships");
|
|
14065
14075
|
if (!relationships)
|
|
14066
14076
|
return;
|
|
14067
14077
|
for (const child of relationships.children) {
|
|
14068
14078
|
if (child.tag !== "Relationship")
|
|
14069
14079
|
continue;
|
|
14070
|
-
|
|
14071
|
-
continue;
|
|
14080
|
+
const type = child.getAttribute("Type");
|
|
14072
14081
|
const relationshipId = child.getAttribute("Id");
|
|
14073
14082
|
const target = child.getAttribute("Target");
|
|
14074
14083
|
if (!relationshipId || !target)
|
|
14075
14084
|
continue;
|
|
14076
|
-
|
|
14077
|
-
|
|
14078
|
-
|
|
14085
|
+
if (type === RELATIONSHIP_NAMESPACE_IMAGE) {
|
|
14086
|
+
const partName = target.startsWith("/") ? target.slice(1) : `word/${target}`;
|
|
14087
|
+
const contentType = lookupContentType(view, partName);
|
|
14088
|
+
view.imagesByRelationshipId.set(relationshipId, {
|
|
14089
|
+
partName,
|
|
14090
|
+
contentType
|
|
14091
|
+
});
|
|
14092
|
+
continue;
|
|
14093
|
+
}
|
|
14094
|
+
if (type === RELATIONSHIP_NAMESPACE_HYPERLINK) {
|
|
14095
|
+
view.hyperlinksByRelationshipId.set(relationshipId, { url: target });
|
|
14096
|
+
}
|
|
14079
14097
|
}
|
|
14080
14098
|
}
|
|
14081
14099
|
function lookupContentType(view, partName) {
|
|
@@ -14204,7 +14222,7 @@ function readCommentsExtended(view) {
|
|
|
14204
14222
|
}
|
|
14205
14223
|
return out;
|
|
14206
14224
|
}
|
|
14207
|
-
var RELATIONSHIP_NAMESPACE_IMAGE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
|
|
14225
|
+
var RELATIONSHIP_NAMESPACE_IMAGE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", RELATIONSHIP_NAMESPACE_HYPERLINK = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
|
|
14208
14226
|
var init_read = __esm(() => {
|
|
14209
14227
|
init_parser();
|
|
14210
14228
|
});
|
|
@@ -14232,7 +14250,9 @@ async function openDocView(path) {
|
|
|
14232
14250
|
blockReferences: new Map,
|
|
14233
14251
|
commentReferences: new Map,
|
|
14234
14252
|
imagesByRelationshipId: new Map,
|
|
14235
|
-
imageById: new Map
|
|
14253
|
+
imageById: new Map,
|
|
14254
|
+
hyperlinksByRelationshipId: new Map,
|
|
14255
|
+
hyperlinkById: new Map
|
|
14236
14256
|
};
|
|
14237
14257
|
view.doc = buildDoc(view, pkg.path);
|
|
14238
14258
|
return view;
|
|
@@ -14319,6 +14339,10 @@ function parseLocator(input) {
|
|
|
14319
14339
|
const imageMatch = trimmed.match(IMAGE_RE);
|
|
14320
14340
|
if (imageMatch)
|
|
14321
14341
|
return { kind: "image", imageId: `img${imageMatch[1]}` };
|
|
14342
|
+
const linkMatch = trimmed.match(LINK_RE);
|
|
14343
|
+
if (linkMatch) {
|
|
14344
|
+
return { kind: "hyperlink", hyperlinkId: `link${linkMatch[1]}` };
|
|
14345
|
+
}
|
|
14322
14346
|
const cellMatch = trimmed.match(CELL_RE);
|
|
14323
14347
|
if (cellMatch) {
|
|
14324
14348
|
const [, tableIndex, rowIndex, columnIndex, rest] = cellMatch;
|
|
@@ -14367,7 +14391,7 @@ function validateOffsets(input, start, end, crossBlock) {
|
|
|
14367
14391
|
throw new LocatorParseError(input, "end offset precedes start");
|
|
14368
14392
|
}
|
|
14369
14393
|
}
|
|
14370
|
-
var LocatorParseError, BLOCK_RE, SPAN_RE, RANGE_RE, COMMENT_RE, IMAGE_RE, CELL_RE;
|
|
14394
|
+
var LocatorParseError, BLOCK_RE, SPAN_RE, RANGE_RE, COMMENT_RE, IMAGE_RE, LINK_RE, CELL_RE;
|
|
14371
14395
|
var init_parse = __esm(() => {
|
|
14372
14396
|
LocatorParseError = class LocatorParseError extends Error {
|
|
14373
14397
|
input;
|
|
@@ -14382,6 +14406,7 @@ var init_parse = __esm(() => {
|
|
|
14382
14406
|
RANGE_RE = /^p(\d+):(\d+)-p(\d+):(\d+)$/;
|
|
14383
14407
|
COMMENT_RE = /^c(\d+)$/;
|
|
14384
14408
|
IMAGE_RE = /^img(\d+)$/;
|
|
14409
|
+
LINK_RE = /^link(\d+)$/;
|
|
14385
14410
|
CELL_RE = /^t(\d+):r(\d+)c(\d+)(?::(.+))?$/;
|
|
14386
14411
|
});
|
|
14387
14412
|
|
|
@@ -14431,6 +14456,39 @@ var init_locators = __esm(() => {
|
|
|
14431
14456
|
init_resolve();
|
|
14432
14457
|
});
|
|
14433
14458
|
|
|
14459
|
+
// src/core/relationships.ts
|
|
14460
|
+
function mintRelationshipId(relationshipsRoot) {
|
|
14461
|
+
let highest = 0;
|
|
14462
|
+
for (const child of relationshipsRoot.children) {
|
|
14463
|
+
if (child.tag !== "Relationship")
|
|
14464
|
+
continue;
|
|
14465
|
+
const id = child.getAttribute("Id");
|
|
14466
|
+
if (!id)
|
|
14467
|
+
continue;
|
|
14468
|
+
const match = id.match(/^rId(\d+)$/);
|
|
14469
|
+
if (match?.[1]) {
|
|
14470
|
+
const number = Number(match[1]);
|
|
14471
|
+
if (number > highest)
|
|
14472
|
+
highest = number;
|
|
14473
|
+
}
|
|
14474
|
+
}
|
|
14475
|
+
return `rId${highest + 1}`;
|
|
14476
|
+
}
|
|
14477
|
+
function addHyperlinkRelationship(relationshipsRoot, url) {
|
|
14478
|
+
const id = mintRelationshipId(relationshipsRoot);
|
|
14479
|
+
relationshipsRoot.children.push(new XmlNode2("Relationship", {
|
|
14480
|
+
Id: id,
|
|
14481
|
+
Type: HYPERLINK_RELATIONSHIP_TYPE,
|
|
14482
|
+
Target: url,
|
|
14483
|
+
TargetMode: "External"
|
|
14484
|
+
}));
|
|
14485
|
+
return id;
|
|
14486
|
+
}
|
|
14487
|
+
var HYPERLINK_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
|
|
14488
|
+
var init_relationships = __esm(() => {
|
|
14489
|
+
init_parser();
|
|
14490
|
+
});
|
|
14491
|
+
|
|
14434
14492
|
// src/core/track-changes/index.ts
|
|
14435
14493
|
function isTrackChangesEnabled(view) {
|
|
14436
14494
|
if (!view.settingsTree)
|
|
@@ -14607,7 +14665,8 @@ var init_jsx = __esm(() => {
|
|
|
14607
14665
|
"comments",
|
|
14608
14666
|
"comment",
|
|
14609
14667
|
"settings",
|
|
14610
|
-
"trackChanges"
|
|
14668
|
+
"trackChanges",
|
|
14669
|
+
"hyperlink"
|
|
14611
14670
|
];
|
|
14612
14671
|
R_TAGS = ["embed", "link", "id"];
|
|
14613
14672
|
A_TAGS = [
|
|
@@ -14722,6 +14781,7 @@ var init_core = __esm(() => {
|
|
|
14722
14781
|
init_locators();
|
|
14723
14782
|
init_package();
|
|
14724
14783
|
init_parser();
|
|
14784
|
+
init_relationships();
|
|
14725
14785
|
init_track_changes();
|
|
14726
14786
|
init_emit();
|
|
14727
14787
|
});
|
|
@@ -14755,6 +14815,7 @@ function exitCodeFor(code) {
|
|
|
14755
14815
|
case "BLOCK_NOT_FOUND":
|
|
14756
14816
|
case "COMMENT_NOT_FOUND":
|
|
14757
14817
|
case "IMAGE_NOT_FOUND":
|
|
14818
|
+
case "HYPERLINK_NOT_FOUND":
|
|
14758
14819
|
case "MATCH_NOT_FOUND":
|
|
14759
14820
|
return EXIT.NOT_FOUND;
|
|
14760
14821
|
case "NOT_A_ZIP":
|
|
@@ -16629,12 +16690,107 @@ var init_find = __esm(() => {
|
|
|
16629
16690
|
init_respond();
|
|
16630
16691
|
});
|
|
16631
16692
|
|
|
16632
|
-
// src/cli/
|
|
16633
|
-
|
|
16634
|
-
|
|
16693
|
+
// src/cli/hyperlinks/wrap.tsx
|
|
16694
|
+
function wrapSpanInHyperlink(paragraph, span, relationshipId) {
|
|
16695
|
+
if (span.start >= span.end) {
|
|
16696
|
+
throw new HyperlinkWrapError(`Empty or inverted span ${span.start}-${span.end}`);
|
|
16697
|
+
}
|
|
16698
|
+
const newChildren = [];
|
|
16699
|
+
const wrappedRuns = [];
|
|
16700
|
+
let offset = 0;
|
|
16701
|
+
let placed = false;
|
|
16702
|
+
const placeWrapper = () => {
|
|
16703
|
+
if (placed || wrappedRuns.length === 0)
|
|
16704
|
+
return;
|
|
16705
|
+
newChildren.push(hyperlinkWrapper(relationshipId, wrappedRuns));
|
|
16706
|
+
wrappedRuns.length = 0;
|
|
16707
|
+
placed = true;
|
|
16708
|
+
};
|
|
16709
|
+
for (const child of paragraph.children) {
|
|
16710
|
+
if (child.tag === "w:r") {
|
|
16711
|
+
const length = runTextLength(child);
|
|
16712
|
+
const runStart = offset;
|
|
16713
|
+
const runEnd = offset + length;
|
|
16714
|
+
offset = runEnd;
|
|
16715
|
+
if (runEnd <= span.start || runStart >= span.end) {
|
|
16716
|
+
placeWrapper();
|
|
16717
|
+
newChildren.push(child);
|
|
16718
|
+
continue;
|
|
16719
|
+
}
|
|
16720
|
+
const sliceStartInRun = Math.max(0, span.start - runStart);
|
|
16721
|
+
const sliceEndInRun = Math.min(length, span.end - runStart);
|
|
16722
|
+
if (sliceStartInRun > 0) {
|
|
16723
|
+
newChildren.push(sliceRun(child, 0, sliceStartInRun));
|
|
16724
|
+
}
|
|
16725
|
+
wrappedRuns.push(sliceRun(child, sliceStartInRun, sliceEndInRun));
|
|
16726
|
+
if (runEnd >= span.end)
|
|
16727
|
+
placeWrapper();
|
|
16728
|
+
if (sliceEndInRun < length) {
|
|
16729
|
+
newChildren.push(sliceRun(child, sliceEndInRun, length));
|
|
16730
|
+
}
|
|
16731
|
+
continue;
|
|
16732
|
+
}
|
|
16733
|
+
if (child.tag === "w:hyperlink") {
|
|
16734
|
+
const hyperlinkLength = sumInnerRunLengths(child);
|
|
16735
|
+
const hyperlinkStart = offset;
|
|
16736
|
+
const hyperlinkEnd = offset + hyperlinkLength;
|
|
16737
|
+
offset = hyperlinkEnd;
|
|
16738
|
+
if (hyperlinkEnd <= span.start || hyperlinkStart >= span.end) {
|
|
16739
|
+
placeWrapper();
|
|
16740
|
+
newChildren.push(child);
|
|
16741
|
+
continue;
|
|
16742
|
+
}
|
|
16743
|
+
throw new HyperlinkWrapError(`Span ${span.start}-${span.end} overlaps an existing hyperlink at ${hyperlinkStart}-${hyperlinkEnd}; nested hyperlinks are not allowed`);
|
|
16744
|
+
}
|
|
16745
|
+
if (child.tag === "w:ins" || child.tag === "w:del") {
|
|
16746
|
+
const innerLength = sumInnerRunLengths(child);
|
|
16747
|
+
const wrapperStart = offset;
|
|
16748
|
+
const wrapperEnd = offset + innerLength;
|
|
16749
|
+
offset = wrapperEnd;
|
|
16750
|
+
if (wrapperEnd <= span.start || wrapperStart >= span.end) {
|
|
16751
|
+
placeWrapper();
|
|
16752
|
+
newChildren.push(child);
|
|
16753
|
+
continue;
|
|
16754
|
+
}
|
|
16755
|
+
throw new HyperlinkWrapError(`Span ${span.start}-${span.end} crosses a tracked-change wrapper at ${wrapperStart}-${wrapperEnd}; resolve or accept the change first`);
|
|
16756
|
+
}
|
|
16757
|
+
newChildren.push(child);
|
|
16758
|
+
}
|
|
16759
|
+
placeWrapper();
|
|
16760
|
+
paragraph.children = newChildren;
|
|
16761
|
+
}
|
|
16762
|
+
function hyperlinkWrapper(relationshipId, runs) {
|
|
16763
|
+
return /* @__PURE__ */ jsxDEV(w.hyperlink, {
|
|
16764
|
+
"r:id": relationshipId,
|
|
16765
|
+
children: runs
|
|
16766
|
+
}, undefined, false, undefined, this);
|
|
16767
|
+
}
|
|
16768
|
+
function sumInnerRunLengths(wrapper) {
|
|
16769
|
+
let total = 0;
|
|
16770
|
+
for (const inner of wrapper.children) {
|
|
16771
|
+
if (inner.tag === "w:r")
|
|
16772
|
+
total += runTextLength(inner);
|
|
16773
|
+
}
|
|
16774
|
+
return total;
|
|
16775
|
+
}
|
|
16776
|
+
var HyperlinkWrapError;
|
|
16777
|
+
var init_wrap = __esm(() => {
|
|
16778
|
+
init_jsx();
|
|
16779
|
+
init_parser();
|
|
16780
|
+
init_jsx_dev_runtime();
|
|
16781
|
+
HyperlinkWrapError = class HyperlinkWrapError extends Error {
|
|
16782
|
+
constructor(message) {
|
|
16783
|
+
super(message);
|
|
16784
|
+
this.name = "HyperlinkWrapError";
|
|
16785
|
+
}
|
|
16786
|
+
};
|
|
16787
|
+
});
|
|
16788
|
+
|
|
16789
|
+
// src/cli/hyperlinks/add.tsx
|
|
16790
|
+
var exports_add2 = {};
|
|
16791
|
+
__export(exports_add2, {
|
|
16635
16792
|
run: () => run11
|
|
16636
16793
|
});
|
|
16637
|
-
import { join } from "path";
|
|
16638
16794
|
import { parseArgs as parseArgs10 } from "util";
|
|
16639
16795
|
async function run11(args) {
|
|
16640
16796
|
let parsed;
|
|
@@ -16643,8 +16799,10 @@ async function run11(args) {
|
|
|
16643
16799
|
args,
|
|
16644
16800
|
allowPositionals: true,
|
|
16645
16801
|
options: {
|
|
16646
|
-
|
|
16647
|
-
|
|
16802
|
+
at: { type: "string" },
|
|
16803
|
+
url: { type: "string" },
|
|
16804
|
+
output: { type: "string", short: "o" },
|
|
16805
|
+
"dry-run": { type: "boolean" },
|
|
16648
16806
|
help: { type: "boolean", short: "h" }
|
|
16649
16807
|
}
|
|
16650
16808
|
});
|
|
@@ -16659,109 +16817,100 @@ async function run11(args) {
|
|
|
16659
16817
|
const path = parsed.positionals[0];
|
|
16660
16818
|
if (!path)
|
|
16661
16819
|
return fail("USAGE", "Missing FILE argument", HELP11);
|
|
16662
|
-
const
|
|
16663
|
-
|
|
16664
|
-
|
|
16665
|
-
|
|
16820
|
+
const atInput = parsed.values.at;
|
|
16821
|
+
const url = parsed.values.url;
|
|
16822
|
+
if (!atInput)
|
|
16823
|
+
return fail("USAGE", "Missing --at LOCATOR", HELP11);
|
|
16824
|
+
if (!url)
|
|
16825
|
+
return fail("USAGE", "Missing --url URL", HELP11);
|
|
16826
|
+
let locator;
|
|
16827
|
+
try {
|
|
16828
|
+
locator = parseLocator(atInput);
|
|
16829
|
+
} catch (error) {
|
|
16830
|
+
if (error instanceof LocatorParseError) {
|
|
16831
|
+
return fail("INVALID_LOCATOR", error.message);
|
|
16832
|
+
}
|
|
16833
|
+
throw error;
|
|
16834
|
+
}
|
|
16835
|
+
const target = locatorToBlockTarget(locator);
|
|
16836
|
+
if (!target?.span) {
|
|
16837
|
+
return fail("INVALID_LOCATOR", "hyperlinks add requires a span locator like pN:S-E or tT:rRcC:pK:S-E");
|
|
16838
|
+
}
|
|
16666
16839
|
const view = await openOrFail(path);
|
|
16667
16840
|
if (typeof view === "number")
|
|
16668
16841
|
return view;
|
|
16669
|
-
await
|
|
16670
|
-
|
|
16671
|
-
|
|
16672
|
-
const
|
|
16673
|
-
if (
|
|
16674
|
-
|
|
16675
|
-
|
|
16676
|
-
|
|
16677
|
-
|
|
16678
|
-
|
|
16679
|
-
|
|
16680
|
-
|
|
16681
|
-
|
|
16682
|
-
const extension = extensionFor(image.contentType, reference.partName);
|
|
16683
|
-
const fileName = `${image.hash}.${extension}`;
|
|
16684
|
-
const outputPath = join(outputDir, fileName);
|
|
16685
|
-
if (!seenHashes.has(image.hash)) {
|
|
16686
|
-
const bytes = await view.pkg.readBytes(reference.partName);
|
|
16687
|
-
await Bun.write(outputPath, bytes);
|
|
16688
|
-
seenHashes.add(image.hash);
|
|
16689
|
-
}
|
|
16690
|
-
manifest.push({
|
|
16691
|
-
id: image.id,
|
|
16692
|
-
path: outputPath,
|
|
16693
|
-
bytes: (await Bun.file(outputPath).arrayBuffer()).byteLength
|
|
16842
|
+
const paragraphRef = await resolveBlockOrFail(view, target.blockId);
|
|
16843
|
+
if (typeof paragraphRef === "number")
|
|
16844
|
+
return paragraphRef;
|
|
16845
|
+
const outputPath = parsed.values.output;
|
|
16846
|
+
if (parsed.values["dry-run"]) {
|
|
16847
|
+
await respond({
|
|
16848
|
+
ok: true,
|
|
16849
|
+
operation: "hyperlinks.add",
|
|
16850
|
+
dryRun: true,
|
|
16851
|
+
path,
|
|
16852
|
+
at: atInput,
|
|
16853
|
+
url,
|
|
16854
|
+
...outputPath ? { output: outputPath } : {}
|
|
16694
16855
|
});
|
|
16856
|
+
return EXIT.OK;
|
|
16695
16857
|
}
|
|
16696
|
-
|
|
16697
|
-
|
|
16698
|
-
|
|
16699
|
-
|
|
16700
|
-
|
|
16701
|
-
|
|
16702
|
-
|
|
16703
|
-
|
|
16704
|
-
|
|
16705
|
-
|
|
16706
|
-
continue;
|
|
16707
|
-
}
|
|
16708
|
-
if (block.type === "table") {
|
|
16709
|
-
for (const row of block.rows) {
|
|
16710
|
-
for (const cell of row.cells) {
|
|
16711
|
-
collectImages(cell.blocks, out);
|
|
16712
|
-
}
|
|
16713
|
-
}
|
|
16858
|
+
const relationships = XmlNode2.findRoot(view.relationshipsTree, "Relationships");
|
|
16859
|
+
if (!relationships) {
|
|
16860
|
+
return fail("UNHANDLED", "Missing <Relationships> root in document rels");
|
|
16861
|
+
}
|
|
16862
|
+
const relationshipId = addHyperlinkRelationship(relationships, url);
|
|
16863
|
+
try {
|
|
16864
|
+
wrapSpanInHyperlink(paragraphRef.node, target.span, relationshipId);
|
|
16865
|
+
} catch (error) {
|
|
16866
|
+
if (error instanceof HyperlinkWrapError) {
|
|
16867
|
+
return fail("USAGE", error.message);
|
|
16714
16868
|
}
|
|
16869
|
+
throw error;
|
|
16715
16870
|
}
|
|
16871
|
+
view.hyperlinksByRelationshipId.set(relationshipId, { url });
|
|
16872
|
+
await saveDocView(view, outputPath);
|
|
16873
|
+
await respond({
|
|
16874
|
+
ok: true,
|
|
16875
|
+
operation: "hyperlinks.add",
|
|
16876
|
+
path: outputPath ?? path,
|
|
16877
|
+
at: atInput,
|
|
16878
|
+
url
|
|
16879
|
+
});
|
|
16880
|
+
return EXIT.OK;
|
|
16716
16881
|
}
|
|
16717
|
-
|
|
16718
|
-
const fromType = EXTENSION_BY_CONTENT_TYPE[contentType.toLowerCase()];
|
|
16719
|
-
if (fromType)
|
|
16720
|
-
return fromType;
|
|
16721
|
-
const fromName = partName.split(".").pop()?.toLowerCase();
|
|
16722
|
-
return fromName ?? "bin";
|
|
16723
|
-
}
|
|
16724
|
-
var HELP11 = `docx images extract \u2014 dump image bytes to a directory
|
|
16882
|
+
var HELP11 = `docx hyperlinks add \u2014 wrap an existing span in a hyperlink
|
|
16725
16883
|
|
|
16726
16884
|
Usage:
|
|
16727
|
-
docx
|
|
16885
|
+
docx hyperlinks add FILE --at LOCATOR --url URL [options]
|
|
16728
16886
|
|
|
16729
16887
|
Required:
|
|
16730
|
-
--
|
|
16888
|
+
--at LOCATOR Where to wrap. Supports:
|
|
16889
|
+
pN:S-E chars S..E of pN
|
|
16890
|
+
tT:rRcC:pK:S-E chars S..E of a cell paragraph
|
|
16891
|
+
--url URL Target URL
|
|
16731
16892
|
|
|
16732
16893
|
Optional:
|
|
16733
|
-
--
|
|
16894
|
+
-o, --output PATH Write to PATH instead of overwriting FILE
|
|
16895
|
+
--dry-run Print what would change; do not write the file
|
|
16734
16896
|
-h, --help Show this help
|
|
16735
16897
|
|
|
16736
|
-
|
|
16737
|
-
|
|
16738
|
-
to written paths.
|
|
16898
|
+
The span must lie inside a single paragraph and must not overlap an existing
|
|
16899
|
+
hyperlink or a tracked-change wrapper.
|
|
16739
16900
|
|
|
16740
16901
|
Examples:
|
|
16741
|
-
docx
|
|
16742
|
-
|
|
16743
|
-
|
|
16744
|
-
var init_extract = __esm(() => {
|
|
16902
|
+
docx hyperlinks add doc.docx --at p3:5-20 --url https://example.com
|
|
16903
|
+
`;
|
|
16904
|
+
var init_add2 = __esm(() => {
|
|
16745
16905
|
init_core();
|
|
16906
|
+
init_parser();
|
|
16746
16907
|
init_respond();
|
|
16747
|
-
|
|
16748
|
-
"image/png": "png",
|
|
16749
|
-
"image/jpeg": "jpg",
|
|
16750
|
-
"image/jpg": "jpg",
|
|
16751
|
-
"image/gif": "gif",
|
|
16752
|
-
"image/svg+xml": "svg",
|
|
16753
|
-
"image/webp": "webp",
|
|
16754
|
-
"image/tiff": "tif",
|
|
16755
|
-
"image/bmp": "bmp",
|
|
16756
|
-
"image/x-emf": "emf",
|
|
16757
|
-
"image/x-wmf": "wmf",
|
|
16758
|
-
"image/vnd.microsoft.icon": "ico"
|
|
16759
|
-
};
|
|
16908
|
+
init_wrap();
|
|
16760
16909
|
});
|
|
16761
16910
|
|
|
16762
|
-
// src/cli/
|
|
16763
|
-
var
|
|
16764
|
-
__export(
|
|
16911
|
+
// src/cli/hyperlinks/delete.ts
|
|
16912
|
+
var exports_delete3 = {};
|
|
16913
|
+
__export(exports_delete3, {
|
|
16765
16914
|
run: () => run12
|
|
16766
16915
|
});
|
|
16767
16916
|
import { parseArgs as parseArgs11 } from "util";
|
|
@@ -16772,6 +16921,9 @@ async function run12(args) {
|
|
|
16772
16921
|
args,
|
|
16773
16922
|
allowPositionals: true,
|
|
16774
16923
|
options: {
|
|
16924
|
+
at: { type: "string" },
|
|
16925
|
+
output: { type: "string", short: "o" },
|
|
16926
|
+
"dry-run": { type: "boolean" },
|
|
16775
16927
|
help: { type: "boolean", short: "h" }
|
|
16776
16928
|
}
|
|
16777
16929
|
});
|
|
@@ -16786,34 +16938,560 @@ async function run12(args) {
|
|
|
16786
16938
|
const path = parsed.positionals[0];
|
|
16787
16939
|
if (!path)
|
|
16788
16940
|
return fail("USAGE", "Missing FILE argument", HELP12);
|
|
16941
|
+
const targetId = parsed.values.at;
|
|
16942
|
+
if (!targetId)
|
|
16943
|
+
return fail("USAGE", "Missing --at LINK_ID", HELP12);
|
|
16789
16944
|
const view = await openOrFail(path);
|
|
16790
16945
|
if (typeof view === "number")
|
|
16791
16946
|
return view;
|
|
16792
|
-
|
|
16793
|
-
|
|
16794
|
-
|
|
16795
|
-
|
|
16796
|
-
|
|
16797
|
-
|
|
16798
|
-
|
|
16799
|
-
|
|
16800
|
-
|
|
16801
|
-
|
|
16802
|
-
|
|
16803
|
-
|
|
16804
|
-
|
|
16805
|
-
|
|
16806
|
-
|
|
16807
|
-
|
|
16808
|
-
|
|
16809
|
-
|
|
16810
|
-
|
|
16811
|
-
|
|
16812
|
-
|
|
16813
|
-
|
|
16947
|
+
const reference = view.hyperlinkById.get(targetId);
|
|
16948
|
+
if (!reference) {
|
|
16949
|
+
return fail("HYPERLINK_NOT_FOUND", `Hyperlink not found: ${targetId}`);
|
|
16950
|
+
}
|
|
16951
|
+
const oldUrl = reference.relationshipId ? view.hyperlinksByRelationshipId.get(reference.relationshipId)?.url : undefined;
|
|
16952
|
+
const outputPath = parsed.values.output;
|
|
16953
|
+
if (parsed.values["dry-run"]) {
|
|
16954
|
+
await respond({
|
|
16955
|
+
ok: true,
|
|
16956
|
+
operation: "hyperlinks.delete",
|
|
16957
|
+
dryRun: true,
|
|
16958
|
+
path,
|
|
16959
|
+
hyperlinkId: targetId,
|
|
16960
|
+
from: oldUrl,
|
|
16961
|
+
...outputPath ? { output: outputPath } : {}
|
|
16962
|
+
});
|
|
16963
|
+
return EXIT.OK;
|
|
16964
|
+
}
|
|
16965
|
+
const index = reference.parent.indexOf(reference.node);
|
|
16966
|
+
if (index === -1) {
|
|
16967
|
+
return fail("HYPERLINK_NOT_FOUND", `Hyperlink reference is stale (parent does not contain it): ${targetId}`);
|
|
16968
|
+
}
|
|
16969
|
+
reference.parent.splice(index, 1, ...reference.node.children);
|
|
16970
|
+
view.hyperlinkById.delete(targetId);
|
|
16971
|
+
if (reference.relationshipId) {
|
|
16972
|
+
const remaining = countHyperlinkUsages(view.documentTree, reference.relationshipId);
|
|
16973
|
+
if (remaining === 0) {
|
|
16974
|
+
pruneRelationship(view.relationshipsTree, reference.relationshipId);
|
|
16975
|
+
view.hyperlinksByRelationshipId.delete(reference.relationshipId);
|
|
16976
|
+
}
|
|
16977
|
+
}
|
|
16978
|
+
await saveDocView(view, outputPath);
|
|
16979
|
+
await respond({
|
|
16980
|
+
ok: true,
|
|
16981
|
+
operation: "hyperlinks.delete",
|
|
16982
|
+
path: outputPath ?? path,
|
|
16983
|
+
hyperlinkId: targetId,
|
|
16984
|
+
from: oldUrl
|
|
16985
|
+
});
|
|
16986
|
+
return EXIT.OK;
|
|
16987
|
+
}
|
|
16988
|
+
function countHyperlinkUsages(documentTree, relationshipId) {
|
|
16989
|
+
let count = 0;
|
|
16990
|
+
for (const root of documentTree) {
|
|
16991
|
+
count += countInNode(root, relationshipId);
|
|
16992
|
+
}
|
|
16993
|
+
return count;
|
|
16994
|
+
}
|
|
16995
|
+
function countInNode(node, relationshipId) {
|
|
16996
|
+
let count = 0;
|
|
16997
|
+
if (node.tag === "w:hyperlink" && node.getAttribute("r:id") === relationshipId) {
|
|
16998
|
+
count++;
|
|
16999
|
+
}
|
|
17000
|
+
for (const child of node.children) {
|
|
17001
|
+
count += countInNode(child, relationshipId);
|
|
17002
|
+
}
|
|
17003
|
+
return count;
|
|
17004
|
+
}
|
|
17005
|
+
function pruneRelationship(relationshipsTree, relationshipId) {
|
|
17006
|
+
const relationships = XmlNode2.findRoot(relationshipsTree, "Relationships");
|
|
17007
|
+
if (!relationships)
|
|
17008
|
+
return;
|
|
17009
|
+
relationships.children = relationships.children.filter((child) => !(child.tag === "Relationship" && child.getAttribute("Id") === relationshipId));
|
|
17010
|
+
}
|
|
17011
|
+
var HELP12 = `docx hyperlinks delete \u2014 unwrap a hyperlink (keep the text)
|
|
17012
|
+
|
|
17013
|
+
Usage:
|
|
17014
|
+
docx hyperlinks delete FILE --at LINK_ID [options]
|
|
17015
|
+
|
|
17016
|
+
Required:
|
|
17017
|
+
--at LINK_ID Existing hyperlink to remove (e.g., link0)
|
|
17018
|
+
|
|
17019
|
+
Optional:
|
|
17020
|
+
-o, --output PATH Write to PATH instead of overwriting FILE
|
|
17021
|
+
--dry-run Print what would change; do not write the file
|
|
17022
|
+
-h, --help Show this help
|
|
17023
|
+
|
|
17024
|
+
The display text stays in place; only the <w:hyperlink> wrapper is removed.
|
|
17025
|
+
If the underlying relationship is no longer referenced, it is pruned from the
|
|
17026
|
+
rels file too.
|
|
17027
|
+
|
|
17028
|
+
Examples:
|
|
17029
|
+
docx hyperlinks delete doc.docx --at link0
|
|
17030
|
+
`;
|
|
17031
|
+
var init_delete3 = __esm(() => {
|
|
17032
|
+
init_core();
|
|
17033
|
+
init_parser();
|
|
17034
|
+
init_respond();
|
|
17035
|
+
});
|
|
17036
|
+
|
|
17037
|
+
// src/cli/hyperlinks/list.ts
|
|
17038
|
+
var exports_list2 = {};
|
|
17039
|
+
__export(exports_list2, {
|
|
17040
|
+
run: () => run13
|
|
17041
|
+
});
|
|
17042
|
+
import { parseArgs as parseArgs12 } from "util";
|
|
17043
|
+
async function run13(args) {
|
|
17044
|
+
let parsed;
|
|
17045
|
+
try {
|
|
17046
|
+
parsed = parseArgs12({
|
|
17047
|
+
args,
|
|
17048
|
+
allowPositionals: true,
|
|
17049
|
+
options: {
|
|
17050
|
+
help: { type: "boolean", short: "h" }
|
|
17051
|
+
}
|
|
17052
|
+
});
|
|
17053
|
+
} catch (parseError) {
|
|
17054
|
+
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
17055
|
+
return fail("USAGE", message, HELP13);
|
|
17056
|
+
}
|
|
17057
|
+
if (parsed.values.help) {
|
|
17058
|
+
await writeStdout(HELP13);
|
|
17059
|
+
return EXIT.OK;
|
|
17060
|
+
}
|
|
17061
|
+
const path = parsed.positionals[0];
|
|
17062
|
+
if (!path)
|
|
17063
|
+
return fail("USAGE", "Missing FILE argument", HELP13);
|
|
17064
|
+
const view = await openOrFail(path);
|
|
17065
|
+
if (typeof view === "number")
|
|
17066
|
+
return view;
|
|
17067
|
+
const entries = new Map;
|
|
17068
|
+
collectHyperlinks(view.doc.blocks, entries);
|
|
17069
|
+
await respond([...entries.values()]);
|
|
17070
|
+
return EXIT.OK;
|
|
17071
|
+
}
|
|
17072
|
+
function collectHyperlinks(blocks, entries) {
|
|
17073
|
+
for (const block of blocks) {
|
|
17074
|
+
if (block.type === "paragraph") {
|
|
17075
|
+
for (const run14 of block.runs) {
|
|
17076
|
+
if (run14.type !== "text" || !run14.hyperlink)
|
|
17077
|
+
continue;
|
|
17078
|
+
addToEntry(entries, run14.hyperlink, block.id, run14.text);
|
|
17079
|
+
}
|
|
17080
|
+
continue;
|
|
17081
|
+
}
|
|
17082
|
+
if (block.type === "table") {
|
|
17083
|
+
for (const row of block.rows) {
|
|
17084
|
+
for (const cell of row.cells) {
|
|
17085
|
+
collectHyperlinks(cell.blocks, entries);
|
|
17086
|
+
}
|
|
17087
|
+
}
|
|
17088
|
+
}
|
|
17089
|
+
}
|
|
17090
|
+
}
|
|
17091
|
+
function addToEntry(entries, hyperlink, blockId, text) {
|
|
17092
|
+
const existing = entries.get(hyperlink.id);
|
|
17093
|
+
if (existing) {
|
|
17094
|
+
existing.text += text;
|
|
17095
|
+
return;
|
|
17096
|
+
}
|
|
17097
|
+
const entry = {
|
|
17098
|
+
id: hyperlink.id,
|
|
17099
|
+
text,
|
|
17100
|
+
blockId
|
|
17101
|
+
};
|
|
17102
|
+
if (hyperlink.url)
|
|
17103
|
+
entry.url = hyperlink.url;
|
|
17104
|
+
if (hyperlink.anchor)
|
|
17105
|
+
entry.anchor = hyperlink.anchor;
|
|
17106
|
+
if (hyperlink.tooltip)
|
|
17107
|
+
entry.tooltip = hyperlink.tooltip;
|
|
17108
|
+
entries.set(hyperlink.id, entry);
|
|
17109
|
+
}
|
|
17110
|
+
var HELP13 = `docx hyperlinks list \u2014 print hyperlink manifest as JSON
|
|
17111
|
+
|
|
17112
|
+
Usage:
|
|
17113
|
+
docx hyperlinks list FILE [options]
|
|
17114
|
+
|
|
17115
|
+
Options:
|
|
17116
|
+
-h, --help Show this help
|
|
17117
|
+
|
|
17118
|
+
Each entry has: id, url (or anchor), tooltip (if set), text (display text),
|
|
17119
|
+
and blockId (the paragraph containing the link).
|
|
17120
|
+
|
|
17121
|
+
Examples:
|
|
17122
|
+
docx hyperlinks list doc.docx | jq -c '.[] | {id, url, text}'
|
|
17123
|
+
`;
|
|
17124
|
+
var init_list2 = __esm(() => {
|
|
17125
|
+
init_respond();
|
|
17126
|
+
});
|
|
17127
|
+
|
|
17128
|
+
// src/cli/hyperlinks/replace.ts
|
|
17129
|
+
var exports_replace = {};
|
|
17130
|
+
__export(exports_replace, {
|
|
17131
|
+
run: () => run14
|
|
17132
|
+
});
|
|
17133
|
+
import { parseArgs as parseArgs13 } from "util";
|
|
17134
|
+
async function run14(args) {
|
|
17135
|
+
let parsed;
|
|
17136
|
+
try {
|
|
17137
|
+
parsed = parseArgs13({
|
|
17138
|
+
args,
|
|
17139
|
+
allowPositionals: true,
|
|
17140
|
+
options: {
|
|
17141
|
+
at: { type: "string" },
|
|
17142
|
+
with: { type: "string" },
|
|
17143
|
+
output: { type: "string", short: "o" },
|
|
17144
|
+
"dry-run": { type: "boolean" },
|
|
17145
|
+
help: { type: "boolean", short: "h" }
|
|
17146
|
+
}
|
|
17147
|
+
});
|
|
17148
|
+
} catch (parseError) {
|
|
17149
|
+
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
17150
|
+
return fail("USAGE", message, HELP14);
|
|
17151
|
+
}
|
|
17152
|
+
if (parsed.values.help) {
|
|
17153
|
+
await writeStdout(HELP14);
|
|
17154
|
+
return EXIT.OK;
|
|
17155
|
+
}
|
|
17156
|
+
const path = parsed.positionals[0];
|
|
17157
|
+
if (!path)
|
|
17158
|
+
return fail("USAGE", "Missing FILE argument", HELP14);
|
|
17159
|
+
const targetId = parsed.values.at;
|
|
17160
|
+
if (!targetId)
|
|
17161
|
+
return fail("USAGE", "Missing --at LINK_ID", HELP14);
|
|
17162
|
+
const newUrl = parsed.values.with;
|
|
17163
|
+
if (!newUrl)
|
|
17164
|
+
return fail("USAGE", "Missing --with URL", HELP14);
|
|
17165
|
+
const view = await openOrFail(path);
|
|
17166
|
+
if (typeof view === "number")
|
|
17167
|
+
return view;
|
|
17168
|
+
const reference = view.hyperlinkById.get(targetId);
|
|
17169
|
+
if (!reference) {
|
|
17170
|
+
return fail("HYPERLINK_NOT_FOUND", `Hyperlink not found: ${targetId}`);
|
|
17171
|
+
}
|
|
17172
|
+
const relationships = XmlNode2.findRoot(view.relationshipsTree, "Relationships");
|
|
17173
|
+
if (!relationships) {
|
|
17174
|
+
return fail("UNHANDLED", "Missing <Relationships> root in document rels");
|
|
17175
|
+
}
|
|
17176
|
+
const existingId = reference.relationshipId;
|
|
17177
|
+
const oldUrl = existingId ? view.hyperlinksByRelationshipId.get(existingId)?.url : undefined;
|
|
17178
|
+
const sharedCount = existingId ? countHyperlinkUsages2(view.documentTree, existingId) : 0;
|
|
17179
|
+
const willAllocateNew = !existingId || sharedCount > 1;
|
|
17180
|
+
const outputPath = parsed.values.output;
|
|
17181
|
+
if (parsed.values["dry-run"]) {
|
|
17182
|
+
await respond({
|
|
17183
|
+
ok: true,
|
|
17184
|
+
operation: "hyperlinks.replace",
|
|
17185
|
+
dryRun: true,
|
|
17186
|
+
path,
|
|
17187
|
+
hyperlinkId: targetId,
|
|
17188
|
+
from: oldUrl,
|
|
17189
|
+
to: newUrl,
|
|
17190
|
+
sharedRelationship: sharedCount > 1,
|
|
17191
|
+
...outputPath ? { output: outputPath } : {}
|
|
17192
|
+
});
|
|
17193
|
+
return EXIT.OK;
|
|
17194
|
+
}
|
|
17195
|
+
if (willAllocateNew) {
|
|
17196
|
+
const newRelationshipId = addHyperlinkRelationship(relationships, newUrl);
|
|
17197
|
+
reference.node.setAttribute("r:id", newRelationshipId);
|
|
17198
|
+
reference.relationshipId = newRelationshipId;
|
|
17199
|
+
view.hyperlinksByRelationshipId.set(newRelationshipId, { url: newUrl });
|
|
17200
|
+
} else if (existingId) {
|
|
17201
|
+
updateRelationshipTarget(relationships, existingId, newUrl);
|
|
17202
|
+
view.hyperlinksByRelationshipId.set(existingId, { url: newUrl });
|
|
17203
|
+
}
|
|
17204
|
+
await saveDocView(view, outputPath);
|
|
17205
|
+
await respond({
|
|
17206
|
+
ok: true,
|
|
17207
|
+
operation: "hyperlinks.replace",
|
|
17208
|
+
path: outputPath ?? path,
|
|
17209
|
+
hyperlinkId: targetId,
|
|
17210
|
+
from: oldUrl,
|
|
17211
|
+
to: newUrl
|
|
17212
|
+
});
|
|
17213
|
+
return EXIT.OK;
|
|
17214
|
+
}
|
|
17215
|
+
function updateRelationshipTarget(relationships, relationshipId, newTarget) {
|
|
17216
|
+
for (const child of relationships.children) {
|
|
17217
|
+
if (child.tag !== "Relationship")
|
|
17218
|
+
continue;
|
|
17219
|
+
if (child.getAttribute("Id") === relationshipId) {
|
|
17220
|
+
child.setAttribute("Target", newTarget);
|
|
17221
|
+
return;
|
|
17222
|
+
}
|
|
17223
|
+
}
|
|
17224
|
+
}
|
|
17225
|
+
function countHyperlinkUsages2(documentTree, relationshipId) {
|
|
17226
|
+
let count = 0;
|
|
17227
|
+
for (const root of documentTree) {
|
|
17228
|
+
count += countInNode2(root, relationshipId);
|
|
17229
|
+
}
|
|
17230
|
+
return count;
|
|
17231
|
+
}
|
|
17232
|
+
function countInNode2(node, relationshipId) {
|
|
17233
|
+
let count = 0;
|
|
17234
|
+
if (node.tag === "w:hyperlink" && node.getAttribute("r:id") === relationshipId) {
|
|
17235
|
+
count++;
|
|
17236
|
+
}
|
|
17237
|
+
for (const child of node.children) {
|
|
17238
|
+
count += countInNode2(child, relationshipId);
|
|
17239
|
+
}
|
|
17240
|
+
return count;
|
|
17241
|
+
}
|
|
17242
|
+
var HELP14 = `docx hyperlinks replace \u2014 change a hyperlink's URL
|
|
17243
|
+
|
|
17244
|
+
Usage:
|
|
17245
|
+
docx hyperlinks replace FILE --at LINK_ID --with URL [options]
|
|
17246
|
+
|
|
17247
|
+
Required:
|
|
17248
|
+
--at LINK_ID Existing hyperlink to update (e.g., link0)
|
|
17249
|
+
--with URL New target URL
|
|
17250
|
+
|
|
17251
|
+
Optional:
|
|
17252
|
+
-o, --output PATH Write to PATH instead of overwriting FILE
|
|
17253
|
+
--dry-run Print what would change; do not write the file
|
|
17254
|
+
-h, --help Show this help
|
|
17255
|
+
|
|
17256
|
+
Replaces only the targeted hyperlink. If multiple hyperlinks shared the same
|
|
17257
|
+
underlying relationship, a new relationship is allocated so the others are
|
|
17258
|
+
unaffected.
|
|
17259
|
+
|
|
17260
|
+
Examples:
|
|
17261
|
+
docx hyperlinks replace doc.docx --at link0 --with https://example.com
|
|
17262
|
+
`;
|
|
17263
|
+
var init_replace = __esm(() => {
|
|
17264
|
+
init_core();
|
|
17265
|
+
init_parser();
|
|
17266
|
+
init_respond();
|
|
17267
|
+
});
|
|
17268
|
+
|
|
17269
|
+
// src/cli/hyperlinks/index.ts
|
|
17270
|
+
var exports_hyperlinks = {};
|
|
17271
|
+
__export(exports_hyperlinks, {
|
|
17272
|
+
run: () => run15
|
|
17273
|
+
});
|
|
17274
|
+
async function run15(args) {
|
|
17275
|
+
const verb = args[0];
|
|
17276
|
+
if (!verb || verb === "--help" || verb === "-h" || verb === "help") {
|
|
17277
|
+
await writeStdout(HELP15);
|
|
17278
|
+
return verb ? 0 : 2;
|
|
17279
|
+
}
|
|
17280
|
+
const loader = SUBCOMMANDS2[verb];
|
|
17281
|
+
if (!loader) {
|
|
17282
|
+
return fail("USAGE", `Unknown hyperlinks subcommand: ${verb}`, 'Run "docx hyperlinks --help".');
|
|
17283
|
+
}
|
|
17284
|
+
const module_ = await loader();
|
|
17285
|
+
return module_.run(args.slice(1));
|
|
17286
|
+
}
|
|
17287
|
+
var SUBCOMMANDS2, HELP15 = `docx hyperlinks \u2014 manage hyperlinks
|
|
17288
|
+
|
|
17289
|
+
Usage:
|
|
17290
|
+
docx hyperlinks <verb> FILE [options]
|
|
17291
|
+
|
|
17292
|
+
Verbs:
|
|
17293
|
+
add Wrap an existing span in a hyperlink
|
|
17294
|
+
delete Unwrap a hyperlink (keep the text)
|
|
17295
|
+
list Print hyperlink manifest as JSON
|
|
17296
|
+
replace Change a hyperlink's URL
|
|
17297
|
+
|
|
17298
|
+
Run "docx hyperlinks <verb> --help" for verb-specific help.
|
|
17299
|
+
`;
|
|
17300
|
+
var init_hyperlinks = __esm(() => {
|
|
17301
|
+
init_respond();
|
|
17302
|
+
SUBCOMMANDS2 = {
|
|
17303
|
+
add: () => Promise.resolve().then(() => (init_add2(), exports_add2)),
|
|
17304
|
+
delete: () => Promise.resolve().then(() => (init_delete3(), exports_delete3)),
|
|
17305
|
+
list: () => Promise.resolve().then(() => (init_list2(), exports_list2)),
|
|
17306
|
+
replace: () => Promise.resolve().then(() => (init_replace(), exports_replace))
|
|
17307
|
+
};
|
|
17308
|
+
});
|
|
17309
|
+
|
|
17310
|
+
// src/cli/images/extract.ts
|
|
17311
|
+
var exports_extract = {};
|
|
17312
|
+
__export(exports_extract, {
|
|
17313
|
+
run: () => run16
|
|
17314
|
+
});
|
|
17315
|
+
import { join } from "path";
|
|
17316
|
+
import { parseArgs as parseArgs14 } from "util";
|
|
17317
|
+
async function run16(args) {
|
|
17318
|
+
let parsed;
|
|
17319
|
+
try {
|
|
17320
|
+
parsed = parseArgs14({
|
|
17321
|
+
args,
|
|
17322
|
+
allowPositionals: true,
|
|
17323
|
+
options: {
|
|
17324
|
+
to: { type: "string" },
|
|
17325
|
+
id: { type: "string" },
|
|
17326
|
+
help: { type: "boolean", short: "h" }
|
|
17327
|
+
}
|
|
17328
|
+
});
|
|
17329
|
+
} catch (parseError) {
|
|
17330
|
+
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
17331
|
+
return fail("USAGE", message, HELP16);
|
|
17332
|
+
}
|
|
17333
|
+
if (parsed.values.help) {
|
|
17334
|
+
await writeStdout(HELP16);
|
|
17335
|
+
return EXIT.OK;
|
|
17336
|
+
}
|
|
17337
|
+
const path = parsed.positionals[0];
|
|
17338
|
+
if (!path)
|
|
17339
|
+
return fail("USAGE", "Missing FILE argument", HELP16);
|
|
17340
|
+
const outputDir = parsed.values.to;
|
|
17341
|
+
if (!outputDir)
|
|
17342
|
+
return fail("USAGE", "Missing --to DIR", HELP16);
|
|
17343
|
+
const targetId = parsed.values.id;
|
|
17344
|
+
const view = await openOrFail(path);
|
|
17345
|
+
if (typeof view === "number")
|
|
17346
|
+
return view;
|
|
17347
|
+
await enrichImageHashes(view);
|
|
17348
|
+
const allImages = [];
|
|
17349
|
+
collectImages(view.doc.blocks, allImages);
|
|
17350
|
+
const targets = targetId ? allImages.filter((image) => image.id === targetId) : allImages;
|
|
17351
|
+
if (targetId && targets.length === 0) {
|
|
17352
|
+
return fail("IMAGE_NOT_FOUND", `Image not found: ${targetId}`);
|
|
17353
|
+
}
|
|
17354
|
+
const manifest = [];
|
|
17355
|
+
const seenHashes = new Set;
|
|
17356
|
+
for (const image of targets) {
|
|
17357
|
+
const reference = view.imageById.get(image.id);
|
|
17358
|
+
if (!reference)
|
|
17359
|
+
continue;
|
|
17360
|
+
const extension = extensionFor(image.contentType, reference.partName);
|
|
17361
|
+
const fileName = `${image.hash}.${extension}`;
|
|
17362
|
+
const outputPath = join(outputDir, fileName);
|
|
17363
|
+
if (!seenHashes.has(image.hash)) {
|
|
17364
|
+
const bytes = await view.pkg.readBytes(reference.partName);
|
|
17365
|
+
await Bun.write(outputPath, bytes);
|
|
17366
|
+
seenHashes.add(image.hash);
|
|
17367
|
+
}
|
|
17368
|
+
manifest.push({
|
|
17369
|
+
id: image.id,
|
|
17370
|
+
path: outputPath,
|
|
17371
|
+
bytes: (await Bun.file(outputPath).arrayBuffer()).byteLength
|
|
17372
|
+
});
|
|
17373
|
+
}
|
|
17374
|
+
await respond({ ok: true, operation: "images.extract", path, manifest });
|
|
17375
|
+
return EXIT.OK;
|
|
17376
|
+
}
|
|
17377
|
+
function collectImages(blocks, out) {
|
|
17378
|
+
for (const block of blocks) {
|
|
17379
|
+
if (block.type === "paragraph") {
|
|
17380
|
+
for (const run17 of block.runs) {
|
|
17381
|
+
if (run17.type === "image")
|
|
17382
|
+
out.push(run17);
|
|
17383
|
+
}
|
|
17384
|
+
continue;
|
|
17385
|
+
}
|
|
17386
|
+
if (block.type === "table") {
|
|
17387
|
+
for (const row of block.rows) {
|
|
17388
|
+
for (const cell of row.cells) {
|
|
17389
|
+
collectImages(cell.blocks, out);
|
|
17390
|
+
}
|
|
17391
|
+
}
|
|
17392
|
+
}
|
|
17393
|
+
}
|
|
17394
|
+
}
|
|
17395
|
+
function extensionFor(contentType, partName) {
|
|
17396
|
+
const fromType = EXTENSION_BY_CONTENT_TYPE[contentType.toLowerCase()];
|
|
17397
|
+
if (fromType)
|
|
17398
|
+
return fromType;
|
|
17399
|
+
const fromName = partName.split(".").pop()?.toLowerCase();
|
|
17400
|
+
return fromName ?? "bin";
|
|
17401
|
+
}
|
|
17402
|
+
var HELP16 = `docx images extract \u2014 dump image bytes to a directory
|
|
17403
|
+
|
|
17404
|
+
Usage:
|
|
17405
|
+
docx images extract FILE --to DIR [options]
|
|
17406
|
+
|
|
17407
|
+
Required:
|
|
17408
|
+
--to DIR Output directory (created if missing)
|
|
17409
|
+
|
|
17410
|
+
Optional:
|
|
17411
|
+
--id IMG_ID Extract a single image (default: extract all)
|
|
17412
|
+
-h, --help Show this help
|
|
17413
|
+
|
|
17414
|
+
Files are named <hash>.<ext> where hash is the sha256 of the image bytes
|
|
17415
|
+
and ext is derived from contentType. Returns a manifest mapping image ids
|
|
17416
|
+
to written paths.
|
|
17417
|
+
|
|
17418
|
+
Examples:
|
|
17419
|
+
docx images extract doc.docx --to ./media
|
|
17420
|
+
docx images extract doc.docx --to ./media --id img2
|
|
17421
|
+
`, EXTENSION_BY_CONTENT_TYPE;
|
|
17422
|
+
var init_extract = __esm(() => {
|
|
17423
|
+
init_core();
|
|
17424
|
+
init_respond();
|
|
17425
|
+
EXTENSION_BY_CONTENT_TYPE = {
|
|
17426
|
+
"image/png": "png",
|
|
17427
|
+
"image/jpeg": "jpg",
|
|
17428
|
+
"image/jpg": "jpg",
|
|
17429
|
+
"image/gif": "gif",
|
|
17430
|
+
"image/svg+xml": "svg",
|
|
17431
|
+
"image/webp": "webp",
|
|
17432
|
+
"image/tiff": "tif",
|
|
17433
|
+
"image/bmp": "bmp",
|
|
17434
|
+
"image/x-emf": "emf",
|
|
17435
|
+
"image/x-wmf": "wmf",
|
|
17436
|
+
"image/vnd.microsoft.icon": "ico"
|
|
17437
|
+
};
|
|
17438
|
+
});
|
|
17439
|
+
|
|
17440
|
+
// src/cli/images/list.ts
|
|
17441
|
+
var exports_list3 = {};
|
|
17442
|
+
__export(exports_list3, {
|
|
17443
|
+
run: () => run17
|
|
17444
|
+
});
|
|
17445
|
+
import { parseArgs as parseArgs15 } from "util";
|
|
17446
|
+
async function run17(args) {
|
|
17447
|
+
let parsed;
|
|
17448
|
+
try {
|
|
17449
|
+
parsed = parseArgs15({
|
|
17450
|
+
args,
|
|
17451
|
+
allowPositionals: true,
|
|
17452
|
+
options: {
|
|
17453
|
+
help: { type: "boolean", short: "h" }
|
|
17454
|
+
}
|
|
17455
|
+
});
|
|
17456
|
+
} catch (parseError) {
|
|
17457
|
+
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
17458
|
+
return fail("USAGE", message, HELP17);
|
|
17459
|
+
}
|
|
17460
|
+
if (parsed.values.help) {
|
|
17461
|
+
await writeStdout(HELP17);
|
|
17462
|
+
return EXIT.OK;
|
|
17463
|
+
}
|
|
17464
|
+
const path = parsed.positionals[0];
|
|
17465
|
+
if (!path)
|
|
17466
|
+
return fail("USAGE", "Missing FILE argument", HELP17);
|
|
17467
|
+
const view = await openOrFail(path);
|
|
17468
|
+
if (typeof view === "number")
|
|
17469
|
+
return view;
|
|
17470
|
+
await enrichImageHashes(view);
|
|
17471
|
+
const images = [];
|
|
17472
|
+
collectImages2(view.doc.blocks, images);
|
|
17473
|
+
await respond(images);
|
|
17474
|
+
return EXIT.OK;
|
|
17475
|
+
}
|
|
17476
|
+
function collectImages2(blocks, out) {
|
|
17477
|
+
for (const block of blocks) {
|
|
17478
|
+
if (block.type === "paragraph") {
|
|
17479
|
+
for (const run18 of block.runs) {
|
|
17480
|
+
if (run18.type === "image")
|
|
17481
|
+
out.push(run18);
|
|
17482
|
+
}
|
|
17483
|
+
continue;
|
|
17484
|
+
}
|
|
17485
|
+
if (block.type === "table") {
|
|
17486
|
+
for (const row of block.rows) {
|
|
17487
|
+
for (const cell of row.cells) {
|
|
17488
|
+
collectImages2(cell.blocks, out);
|
|
17489
|
+
}
|
|
17490
|
+
}
|
|
17491
|
+
}
|
|
16814
17492
|
}
|
|
16815
17493
|
}
|
|
16816
|
-
var
|
|
17494
|
+
var HELP17 = `docx images list \u2014 print image manifest as JSON
|
|
16817
17495
|
|
|
16818
17496
|
Usage:
|
|
16819
17497
|
docx images list FILE [options]
|
|
@@ -16824,21 +17502,21 @@ Options:
|
|
|
16824
17502
|
Examples:
|
|
16825
17503
|
docx images list doc.docx | jq -c '.[] | {id, contentType, hash}'
|
|
16826
17504
|
`;
|
|
16827
|
-
var
|
|
17505
|
+
var init_list3 = __esm(() => {
|
|
16828
17506
|
init_core();
|
|
16829
17507
|
init_respond();
|
|
16830
17508
|
});
|
|
16831
17509
|
|
|
16832
17510
|
// src/cli/images/replace.ts
|
|
16833
|
-
var
|
|
16834
|
-
__export(
|
|
16835
|
-
run: () =>
|
|
17511
|
+
var exports_replace2 = {};
|
|
17512
|
+
__export(exports_replace2, {
|
|
17513
|
+
run: () => run18
|
|
16836
17514
|
});
|
|
16837
|
-
import { parseArgs as
|
|
16838
|
-
async function
|
|
17515
|
+
import { parseArgs as parseArgs16 } from "util";
|
|
17516
|
+
async function run18(args) {
|
|
16839
17517
|
let parsed;
|
|
16840
17518
|
try {
|
|
16841
|
-
parsed =
|
|
17519
|
+
parsed = parseArgs16({
|
|
16842
17520
|
args,
|
|
16843
17521
|
allowPositionals: true,
|
|
16844
17522
|
options: {
|
|
@@ -16851,21 +17529,21 @@ async function run13(args) {
|
|
|
16851
17529
|
});
|
|
16852
17530
|
} catch (parseError) {
|
|
16853
17531
|
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
16854
|
-
return fail("USAGE", message,
|
|
17532
|
+
return fail("USAGE", message, HELP18);
|
|
16855
17533
|
}
|
|
16856
17534
|
if (parsed.values.help) {
|
|
16857
|
-
await writeStdout(
|
|
17535
|
+
await writeStdout(HELP18);
|
|
16858
17536
|
return EXIT.OK;
|
|
16859
17537
|
}
|
|
16860
17538
|
const path = parsed.positionals[0];
|
|
16861
17539
|
if (!path)
|
|
16862
|
-
return fail("USAGE", "Missing FILE argument",
|
|
17540
|
+
return fail("USAGE", "Missing FILE argument", HELP18);
|
|
16863
17541
|
const targetId = parsed.values.at;
|
|
16864
17542
|
if (!targetId)
|
|
16865
|
-
return fail("USAGE", "Missing --at IMG_ID",
|
|
17543
|
+
return fail("USAGE", "Missing --at IMG_ID", HELP18);
|
|
16866
17544
|
const sourcePath = parsed.values.with;
|
|
16867
17545
|
if (!sourcePath)
|
|
16868
|
-
return fail("USAGE", "Missing --with PATH",
|
|
17546
|
+
return fail("USAGE", "Missing --with PATH", HELP18);
|
|
16869
17547
|
const sourceFile = Bun.file(sourcePath);
|
|
16870
17548
|
if (!await sourceFile.exists()) {
|
|
16871
17549
|
return fail("FILE_NOT_FOUND", `Replacement file not found: ${sourcePath}`);
|
|
@@ -16904,7 +17582,7 @@ async function run13(args) {
|
|
|
16904
17582
|
} else {
|
|
16905
17583
|
view.pkg.writeBytes(newPartName, bytes);
|
|
16906
17584
|
view.pkg.deletePart(originalPartName);
|
|
16907
|
-
|
|
17585
|
+
updateRelationshipTarget2(view.relationshipsTree, reference.relationshipId, relativeTargetFor(newPartName));
|
|
16908
17586
|
ensureContentTypeDefault(view.contentTypesTree, newExtension, newMimeType);
|
|
16909
17587
|
reference.partName = newPartName;
|
|
16910
17588
|
reference.contentType = newMimeType;
|
|
@@ -16932,7 +17610,7 @@ function renameExtension(partName, newExtension) {
|
|
|
16932
17610
|
function relativeTargetFor(partName) {
|
|
16933
17611
|
return partName.startsWith("word/") ? partName.slice("word/".length) : partName;
|
|
16934
17612
|
}
|
|
16935
|
-
function
|
|
17613
|
+
function updateRelationshipTarget2(relationshipsTree, relationshipId, newTarget) {
|
|
16936
17614
|
const relationships = XmlNode2.findRoot(relationshipsTree, "Relationships");
|
|
16937
17615
|
if (!relationships)
|
|
16938
17616
|
return;
|
|
@@ -16957,7 +17635,7 @@ function ensureContentTypeDefault(contentTypesTree, extension, mimeType) {
|
|
|
16957
17635
|
}
|
|
16958
17636
|
types.children.push(new XmlNode2("Default", { Extension: extension, ContentType: mimeType }));
|
|
16959
17637
|
}
|
|
16960
|
-
var
|
|
17638
|
+
var HELP18 = `docx images replace \u2014 swap an image's bytes
|
|
16961
17639
|
|
|
16962
17640
|
Usage:
|
|
16963
17641
|
docx images replace FILE --at IMG_ID --with PATH [options]
|
|
@@ -16979,7 +17657,7 @@ Examples:
|
|
|
16979
17657
|
docx images replace doc.docx --at img2 --with ./new-photo.png
|
|
16980
17658
|
docx images replace doc.docx --at img0 --with ./diagram.svg
|
|
16981
17659
|
`, EXTENSION_BY_MIME;
|
|
16982
|
-
var
|
|
17660
|
+
var init_replace2 = __esm(() => {
|
|
16983
17661
|
init_core();
|
|
16984
17662
|
init_parser();
|
|
16985
17663
|
init_respond();
|
|
@@ -17000,22 +17678,22 @@ var init_replace = __esm(() => {
|
|
|
17000
17678
|
// src/cli/images/index.ts
|
|
17001
17679
|
var exports_images = {};
|
|
17002
17680
|
__export(exports_images, {
|
|
17003
|
-
run: () =>
|
|
17681
|
+
run: () => run19
|
|
17004
17682
|
});
|
|
17005
|
-
async function
|
|
17683
|
+
async function run19(args) {
|
|
17006
17684
|
const verb = args[0];
|
|
17007
17685
|
if (!verb || verb === "--help" || verb === "-h" || verb === "help") {
|
|
17008
|
-
await writeStdout(
|
|
17686
|
+
await writeStdout(HELP19);
|
|
17009
17687
|
return verb ? 0 : 2;
|
|
17010
17688
|
}
|
|
17011
|
-
const loader =
|
|
17689
|
+
const loader = SUBCOMMANDS3[verb];
|
|
17012
17690
|
if (!loader) {
|
|
17013
17691
|
return fail("USAGE", `Unknown images subcommand: ${verb}`, 'Run "docx images --help".');
|
|
17014
17692
|
}
|
|
17015
17693
|
const module_ = await loader();
|
|
17016
17694
|
return module_.run(args.slice(1));
|
|
17017
17695
|
}
|
|
17018
|
-
var
|
|
17696
|
+
var SUBCOMMANDS3, HELP19 = `docx images \u2014 manage embedded images
|
|
17019
17697
|
|
|
17020
17698
|
Usage:
|
|
17021
17699
|
docx images <verb> FILE [options]
|
|
@@ -17029,10 +17707,10 @@ Run "docx images <verb> --help" for verb-specific help.
|
|
|
17029
17707
|
`;
|
|
17030
17708
|
var init_images = __esm(() => {
|
|
17031
17709
|
init_respond();
|
|
17032
|
-
|
|
17710
|
+
SUBCOMMANDS3 = {
|
|
17033
17711
|
extract: () => Promise.resolve().then(() => (init_extract(), exports_extract)),
|
|
17034
|
-
list: () => Promise.resolve().then(() => (
|
|
17035
|
-
replace: () => Promise.resolve().then(() => (
|
|
17712
|
+
list: () => Promise.resolve().then(() => (init_list3(), exports_list3)),
|
|
17713
|
+
replace: () => Promise.resolve().then(() => (init_replace2(), exports_replace2))
|
|
17036
17714
|
};
|
|
17037
17715
|
});
|
|
17038
17716
|
|
|
@@ -17097,6 +17775,14 @@ export type TextRun = {
|
|
|
17097
17775
|
sizeHalfPoints?: number;
|
|
17098
17776
|
comments?: string[];
|
|
17099
17777
|
trackedChange?: TrackedChange;
|
|
17778
|
+
hyperlink?: Hyperlink;
|
|
17779
|
+
};
|
|
17780
|
+
|
|
17781
|
+
export type Hyperlink = {
|
|
17782
|
+
id: string;
|
|
17783
|
+
url?: string;
|
|
17784
|
+
anchor?: string;
|
|
17785
|
+
tooltip?: string;
|
|
17100
17786
|
};
|
|
17101
17787
|
|
|
17102
17788
|
export type ImageRun = {
|
|
@@ -17148,13 +17834,13 @@ var init_types = () => {};
|
|
|
17148
17834
|
// src/cli/info/schema.ts
|
|
17149
17835
|
var exports_schema = {};
|
|
17150
17836
|
__export(exports_schema, {
|
|
17151
|
-
run: () =>
|
|
17837
|
+
run: () => run20
|
|
17152
17838
|
});
|
|
17153
|
-
import { parseArgs as
|
|
17154
|
-
async function
|
|
17839
|
+
import { parseArgs as parseArgs17 } from "util";
|
|
17840
|
+
async function run20(args) {
|
|
17155
17841
|
let parsed;
|
|
17156
17842
|
try {
|
|
17157
|
-
parsed =
|
|
17843
|
+
parsed = parseArgs17({
|
|
17158
17844
|
args,
|
|
17159
17845
|
allowPositionals: true,
|
|
17160
17846
|
options: {
|
|
@@ -17165,10 +17851,10 @@ async function run15(args) {
|
|
|
17165
17851
|
});
|
|
17166
17852
|
} catch (parseError) {
|
|
17167
17853
|
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
17168
|
-
return fail("USAGE", message,
|
|
17854
|
+
return fail("USAGE", message, HELP20);
|
|
17169
17855
|
}
|
|
17170
17856
|
if (parsed.values.help) {
|
|
17171
|
-
await writeStdout(
|
|
17857
|
+
await writeStdout(HELP20);
|
|
17172
17858
|
return EXIT.OK;
|
|
17173
17859
|
}
|
|
17174
17860
|
if (parsed.values.ts) {
|
|
@@ -17178,7 +17864,7 @@ async function run15(args) {
|
|
|
17178
17864
|
await respond(JSON_SCHEMA);
|
|
17179
17865
|
return EXIT.OK;
|
|
17180
17866
|
}
|
|
17181
|
-
var
|
|
17867
|
+
var HELP20 = `docx schema \u2014 print the AST type definitions
|
|
17182
17868
|
|
|
17183
17869
|
Usage:
|
|
17184
17870
|
docx schema [options]
|
|
@@ -17275,7 +17961,18 @@ var init_schema = __esm(() => {
|
|
|
17275
17961
|
date: { type: "string" },
|
|
17276
17962
|
revisionId: { type: "string" }
|
|
17277
17963
|
}
|
|
17278
|
-
}
|
|
17964
|
+
},
|
|
17965
|
+
hyperlink: { $ref: "#/$defs/Hyperlink" }
|
|
17966
|
+
}
|
|
17967
|
+
},
|
|
17968
|
+
Hyperlink: {
|
|
17969
|
+
type: "object",
|
|
17970
|
+
required: ["id"],
|
|
17971
|
+
properties: {
|
|
17972
|
+
id: { type: "string" },
|
|
17973
|
+
url: { type: "string" },
|
|
17974
|
+
anchor: { type: "string" },
|
|
17975
|
+
tooltip: { type: "string" }
|
|
17279
17976
|
}
|
|
17280
17977
|
},
|
|
17281
17978
|
ImageRun: {
|
|
@@ -17370,13 +18067,13 @@ var init_schema = __esm(() => {
|
|
|
17370
18067
|
// src/cli/info/locators.ts
|
|
17371
18068
|
var exports_locators = {};
|
|
17372
18069
|
__export(exports_locators, {
|
|
17373
|
-
run: () =>
|
|
18070
|
+
run: () => run21
|
|
17374
18071
|
});
|
|
17375
|
-
import { parseArgs as
|
|
17376
|
-
async function
|
|
18072
|
+
import { parseArgs as parseArgs18 } from "util";
|
|
18073
|
+
async function run21(args) {
|
|
17377
18074
|
let parsed;
|
|
17378
18075
|
try {
|
|
17379
|
-
parsed =
|
|
18076
|
+
parsed = parseArgs18({
|
|
17380
18077
|
args,
|
|
17381
18078
|
allowPositionals: true,
|
|
17382
18079
|
options: {
|
|
@@ -17386,10 +18083,10 @@ async function run16(args) {
|
|
|
17386
18083
|
});
|
|
17387
18084
|
} catch (parseError) {
|
|
17388
18085
|
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
17389
|
-
return fail("USAGE", message,
|
|
18086
|
+
return fail("USAGE", message, HELP21);
|
|
17390
18087
|
}
|
|
17391
18088
|
if (parsed.values.help) {
|
|
17392
|
-
await writeStdout(
|
|
18089
|
+
await writeStdout(HELP21);
|
|
17393
18090
|
return EXIT.OK;
|
|
17394
18091
|
}
|
|
17395
18092
|
if (parsed.values.json) {
|
|
@@ -17400,7 +18097,7 @@ async function run16(args) {
|
|
|
17400
18097
|
await writeStdout(REFERENCE);
|
|
17401
18098
|
return EXIT.OK;
|
|
17402
18099
|
}
|
|
17403
|
-
var
|
|
18100
|
+
var HELP21 = `docx locators \u2014 print the locator grammar reference
|
|
17404
18101
|
|
|
17405
18102
|
Usage:
|
|
17406
18103
|
docx locators [options]
|
|
@@ -17426,6 +18123,7 @@ Range locators (across blocks):
|
|
|
17426
18123
|
Entity locators:
|
|
17427
18124
|
cN Comment id (e.g., c0)
|
|
17428
18125
|
imgN Image id (e.g., img2)
|
|
18126
|
+
linkN Hyperlink id (e.g., link0)
|
|
17429
18127
|
tN:rRcC Cell at row R, column C of table tN
|
|
17430
18128
|
|
|
17431
18129
|
Examples:
|
|
@@ -17434,6 +18132,7 @@ Examples:
|
|
|
17434
18132
|
p3:5-p5:10 -> from char 5 of p3 to char 10 of p5
|
|
17435
18133
|
c1 -> comment c1
|
|
17436
18134
|
img0 -> image img0
|
|
18135
|
+
link0 -> hyperlink link0
|
|
17437
18136
|
t0:r1c2 -> cell at row 1, col 2 of table t0
|
|
17438
18137
|
t0:r1c2:p0 -> first paragraph of that cell
|
|
17439
18138
|
t0:r1c2:p0:5-10 -> chars 5..10 of that paragraph
|
|
@@ -17466,6 +18165,7 @@ var init_locators2 = __esm(() => {
|
|
|
17466
18165
|
entityLocators: {
|
|
17467
18166
|
comment: { syntax: "cN", example: "c1" },
|
|
17468
18167
|
image: { syntax: "imgN", example: "img0" },
|
|
18168
|
+
hyperlink: { syntax: "linkN", example: "link0" },
|
|
17469
18169
|
cell: { syntax: "tN:rRcC", example: "t0:r1c2" },
|
|
17470
18170
|
nestedCell: { syntax: "tN:rRcC:pK", example: "t0:r1c2:p0" }
|
|
17471
18171
|
},
|
|
@@ -17480,22 +18180,22 @@ var init_locators2 = __esm(() => {
|
|
|
17480
18180
|
// src/cli/info/index.ts
|
|
17481
18181
|
var exports_info = {};
|
|
17482
18182
|
__export(exports_info, {
|
|
17483
|
-
run: () =>
|
|
18183
|
+
run: () => run22
|
|
17484
18184
|
});
|
|
17485
|
-
async function
|
|
18185
|
+
async function run22(args) {
|
|
17486
18186
|
const topic = args[0];
|
|
17487
18187
|
if (!topic || topic === "--help" || topic === "-h" || topic === "help") {
|
|
17488
|
-
await writeStdout(
|
|
18188
|
+
await writeStdout(HELP22);
|
|
17489
18189
|
return topic ? 0 : 2;
|
|
17490
18190
|
}
|
|
17491
|
-
const loader =
|
|
18191
|
+
const loader = SUBCOMMANDS4[topic];
|
|
17492
18192
|
if (!loader) {
|
|
17493
18193
|
return fail("USAGE", `Unknown info topic: ${topic}`, 'Run "docx info --help".');
|
|
17494
18194
|
}
|
|
17495
18195
|
const module_ = await loader();
|
|
17496
18196
|
return module_.run(args.slice(1));
|
|
17497
18197
|
}
|
|
17498
|
-
var
|
|
18198
|
+
var SUBCOMMANDS4, HELP22 = `docx info \u2014 print reference material about the CLI
|
|
17499
18199
|
|
|
17500
18200
|
Usage:
|
|
17501
18201
|
docx info <topic> [options]
|
|
@@ -17508,7 +18208,7 @@ Run "docx info <topic> --help" for topic-specific help.
|
|
|
17508
18208
|
`;
|
|
17509
18209
|
var init_info = __esm(() => {
|
|
17510
18210
|
init_respond();
|
|
17511
|
-
|
|
18211
|
+
SUBCOMMANDS4 = {
|
|
17512
18212
|
schema: () => Promise.resolve().then(() => (init_schema(), exports_schema)),
|
|
17513
18213
|
locators: () => Promise.resolve().then(() => (init_locators2(), exports_locators))
|
|
17514
18214
|
};
|
|
@@ -17517,13 +18217,13 @@ var init_info = __esm(() => {
|
|
|
17517
18217
|
// src/cli/insert/index.tsx
|
|
17518
18218
|
var exports_insert = {};
|
|
17519
18219
|
__export(exports_insert, {
|
|
17520
|
-
run: () =>
|
|
18220
|
+
run: () => run23
|
|
17521
18221
|
});
|
|
17522
|
-
import { parseArgs as
|
|
17523
|
-
async function
|
|
18222
|
+
import { parseArgs as parseArgs19 } from "util";
|
|
18223
|
+
async function run23(args) {
|
|
17524
18224
|
let parsed;
|
|
17525
18225
|
try {
|
|
17526
|
-
parsed =
|
|
18226
|
+
parsed = parseArgs19({
|
|
17527
18227
|
args,
|
|
17528
18228
|
allowPositionals: true,
|
|
17529
18229
|
options: {
|
|
@@ -17536,6 +18236,7 @@ async function run18(args) {
|
|
|
17536
18236
|
color: { type: "string" },
|
|
17537
18237
|
bold: { type: "boolean" },
|
|
17538
18238
|
italic: { type: "boolean" },
|
|
18239
|
+
url: { type: "string" },
|
|
17539
18240
|
output: { type: "string", short: "o" },
|
|
17540
18241
|
"dry-run": { type: "boolean" },
|
|
17541
18242
|
help: { type: "boolean", short: "h" }
|
|
@@ -17543,30 +18244,34 @@ async function run18(args) {
|
|
|
17543
18244
|
});
|
|
17544
18245
|
} catch (parseError) {
|
|
17545
18246
|
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
17546
|
-
return fail("USAGE", message,
|
|
18247
|
+
return fail("USAGE", message, HELP23);
|
|
17547
18248
|
}
|
|
17548
18249
|
if (parsed.values.help) {
|
|
17549
|
-
await writeStdout(
|
|
18250
|
+
await writeStdout(HELP23);
|
|
17550
18251
|
return EXIT.OK;
|
|
17551
18252
|
}
|
|
17552
18253
|
const path = parsed.positionals[0];
|
|
17553
18254
|
if (!path)
|
|
17554
|
-
return fail("USAGE", "Missing FILE argument",
|
|
18255
|
+
return fail("USAGE", "Missing FILE argument", HELP23);
|
|
17555
18256
|
const after = parsed.values.after;
|
|
17556
18257
|
const before = parsed.values.before;
|
|
17557
18258
|
if (!after && !before) {
|
|
17558
|
-
return fail("USAGE", "Missing locator: pass --after or --before",
|
|
18259
|
+
return fail("USAGE", "Missing locator: pass --after or --before", HELP23);
|
|
17559
18260
|
}
|
|
17560
18261
|
if (after && before) {
|
|
17561
|
-
return fail("USAGE", "Pass either --after or --before, not both",
|
|
18262
|
+
return fail("USAGE", "Pass either --after or --before, not both", HELP23);
|
|
17562
18263
|
}
|
|
17563
18264
|
const text = parsed.values.text;
|
|
17564
18265
|
const runsJson = parsed.values.runs;
|
|
18266
|
+
const url = parsed.values.url;
|
|
17565
18267
|
if (!text && !runsJson) {
|
|
17566
|
-
return fail("USAGE", "Missing content: pass --text or --runs",
|
|
18268
|
+
return fail("USAGE", "Missing content: pass --text or --runs", HELP23);
|
|
17567
18269
|
}
|
|
17568
18270
|
if (text && runsJson) {
|
|
17569
|
-
return fail("USAGE", "Pass either --text or --runs, not both",
|
|
18271
|
+
return fail("USAGE", "Pass either --text or --runs, not both", HELP23);
|
|
18272
|
+
}
|
|
18273
|
+
if (url && !text) {
|
|
18274
|
+
return fail("USAGE", "--url requires --text", HELP23);
|
|
17570
18275
|
}
|
|
17571
18276
|
const paragraphOptions = {};
|
|
17572
18277
|
const styleValue = parsed.values.style;
|
|
@@ -17596,6 +18301,8 @@ async function run18(args) {
|
|
|
17596
18301
|
...parsed.values.bold ? { bold: true } : {},
|
|
17597
18302
|
...parsed.values.italic ? { italic: true } : {}
|
|
17598
18303
|
}, undefined, false, undefined, this);
|
|
18304
|
+
if (url)
|
|
18305
|
+
wrapFirstRunInHyperlink(view, paragraphNode, url);
|
|
17599
18306
|
} else {
|
|
17600
18307
|
let runsValue;
|
|
17601
18308
|
try {
|
|
@@ -17644,6 +18351,29 @@ async function run18(args) {
|
|
|
17644
18351
|
});
|
|
17645
18352
|
return EXIT.OK;
|
|
17646
18353
|
}
|
|
18354
|
+
function wrapFirstRunInHyperlink(view, paragraph, url) {
|
|
18355
|
+
const relationships = XmlNode2.findRoot(view.relationshipsTree, "Relationships");
|
|
18356
|
+
if (!relationships) {
|
|
18357
|
+
throw new Error("Missing <Relationships> root in document rels");
|
|
18358
|
+
}
|
|
18359
|
+
const relationshipId = addHyperlinkRelationship(relationships, url);
|
|
18360
|
+
view.hyperlinksByRelationshipId.set(relationshipId, { url });
|
|
18361
|
+
const newChildren = [];
|
|
18362
|
+
let wrapped = false;
|
|
18363
|
+
for (const child of paragraph.children) {
|
|
18364
|
+
if (!wrapped && child.tag === "w:r") {
|
|
18365
|
+
const wrapper = /* @__PURE__ */ jsxDEV(w.hyperlink, {
|
|
18366
|
+
"r:id": relationshipId,
|
|
18367
|
+
children: child
|
|
18368
|
+
}, undefined, false, undefined, this);
|
|
18369
|
+
newChildren.push(wrapper);
|
|
18370
|
+
wrapped = true;
|
|
18371
|
+
continue;
|
|
18372
|
+
}
|
|
18373
|
+
newChildren.push(child);
|
|
18374
|
+
}
|
|
18375
|
+
paragraph.children = newChildren;
|
|
18376
|
+
}
|
|
17647
18377
|
function applyTrackedInsertion(paragraph, view) {
|
|
17648
18378
|
const allocator = createRevisionAllocator(view);
|
|
17649
18379
|
const baseMeta = { author: resolveAuthor(), date: resolveDate() };
|
|
@@ -17674,7 +18404,7 @@ function applyTrackedInsertion(paragraph, view) {
|
|
|
17674
18404
|
paragraph.children = newChildren;
|
|
17675
18405
|
markParagraphMarkAs(paragraph, "ins", mintMeta());
|
|
17676
18406
|
}
|
|
17677
|
-
var
|
|
18407
|
+
var HELP23 = `docx insert \u2014 insert a paragraph at a locator
|
|
17678
18408
|
|
|
17679
18409
|
Usage:
|
|
17680
18410
|
docx insert FILE [options]
|
|
@@ -17695,6 +18425,7 @@ Run options (only with --text):
|
|
|
17695
18425
|
--color HEX Run color, hex (e.g., 800080 for purple)
|
|
17696
18426
|
--bold Bold
|
|
17697
18427
|
--italic Italic
|
|
18428
|
+
--url URL Wrap the inserted text in a hyperlink to URL
|
|
17698
18429
|
|
|
17699
18430
|
-o, --output PATH Write to PATH instead of overwriting FILE
|
|
17700
18431
|
--dry-run Print what would be inserted; do not write the file
|
|
@@ -17704,9 +18435,12 @@ Examples:
|
|
|
17704
18435
|
docx insert doc.docx --after p3 --text "Section header" --style Heading2
|
|
17705
18436
|
docx insert doc.docx --before p0 --text "ALERT" --color CC0000 --bold
|
|
17706
18437
|
docx insert doc.docx --after p2 --runs '[{"type":"text","text":"X","bold":true}]'
|
|
18438
|
+
docx insert doc.docx --after p3 --text "click here" --url https://example.com
|
|
17707
18439
|
`;
|
|
17708
18440
|
var init_insert = __esm(() => {
|
|
17709
18441
|
init_core();
|
|
18442
|
+
init_jsx();
|
|
18443
|
+
init_parser();
|
|
17710
18444
|
init_respond();
|
|
17711
18445
|
init_emit2();
|
|
17712
18446
|
init_jsx_dev_runtime();
|
|
@@ -17768,9 +18502,9 @@ function* headingParagraphs(blocks, stylePrefix) {
|
|
|
17768
18502
|
}
|
|
17769
18503
|
function paragraphText(paragraph) {
|
|
17770
18504
|
let out = "";
|
|
17771
|
-
for (const
|
|
17772
|
-
if (
|
|
17773
|
-
out +=
|
|
18505
|
+
for (const run24 of paragraph.runs) {
|
|
18506
|
+
if (run24.type === "text")
|
|
18507
|
+
out += run24.text;
|
|
17774
18508
|
}
|
|
17775
18509
|
return out;
|
|
17776
18510
|
}
|
|
@@ -17778,13 +18512,13 @@ function paragraphText(paragraph) {
|
|
|
17778
18512
|
// src/cli/outline/index.ts
|
|
17779
18513
|
var exports_outline = {};
|
|
17780
18514
|
__export(exports_outline, {
|
|
17781
|
-
run: () =>
|
|
18515
|
+
run: () => run24
|
|
17782
18516
|
});
|
|
17783
|
-
import { parseArgs as
|
|
17784
|
-
async function
|
|
18517
|
+
import { parseArgs as parseArgs20 } from "util";
|
|
18518
|
+
async function run24(args) {
|
|
17785
18519
|
let parsed;
|
|
17786
18520
|
try {
|
|
17787
|
-
parsed =
|
|
18521
|
+
parsed = parseArgs20({
|
|
17788
18522
|
args,
|
|
17789
18523
|
allowPositionals: true,
|
|
17790
18524
|
options: {
|
|
@@ -17794,15 +18528,15 @@ async function run19(args) {
|
|
|
17794
18528
|
});
|
|
17795
18529
|
} catch (parseError) {
|
|
17796
18530
|
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
17797
|
-
return fail("USAGE", message,
|
|
18531
|
+
return fail("USAGE", message, HELP24);
|
|
17798
18532
|
}
|
|
17799
18533
|
if (parsed.values.help) {
|
|
17800
|
-
await writeStdout(
|
|
18534
|
+
await writeStdout(HELP24);
|
|
17801
18535
|
return EXIT.OK;
|
|
17802
18536
|
}
|
|
17803
18537
|
const path = parsed.positionals[0];
|
|
17804
18538
|
if (!path)
|
|
17805
|
-
return fail("USAGE", "Missing FILE argument",
|
|
18539
|
+
return fail("USAGE", "Missing FILE argument", HELP24);
|
|
17806
18540
|
const stylePrefix = parsed.values["style-prefix"] ?? "Heading";
|
|
17807
18541
|
if (stylePrefix.length === 0) {
|
|
17808
18542
|
return fail("USAGE", "--style-prefix cannot be empty");
|
|
@@ -17820,7 +18554,7 @@ async function run19(args) {
|
|
|
17820
18554
|
});
|
|
17821
18555
|
return EXIT.OK;
|
|
17822
18556
|
}
|
|
17823
|
-
var
|
|
18557
|
+
var HELP24 = `docx outline \u2014 list headings as a hierarchical tree
|
|
17824
18558
|
|
|
17825
18559
|
Usage:
|
|
17826
18560
|
docx outline FILE [options]
|
|
@@ -17850,13 +18584,13 @@ var init_outline = __esm(() => {
|
|
|
17850
18584
|
// src/cli/read/index.ts
|
|
17851
18585
|
var exports_read = {};
|
|
17852
18586
|
__export(exports_read, {
|
|
17853
|
-
run: () =>
|
|
18587
|
+
run: () => run25
|
|
17854
18588
|
});
|
|
17855
|
-
import { parseArgs as
|
|
17856
|
-
async function
|
|
18589
|
+
import { parseArgs as parseArgs21 } from "util";
|
|
18590
|
+
async function run25(args) {
|
|
17857
18591
|
let parsed;
|
|
17858
18592
|
try {
|
|
17859
|
-
parsed =
|
|
18593
|
+
parsed = parseArgs21({
|
|
17860
18594
|
args,
|
|
17861
18595
|
allowPositionals: true,
|
|
17862
18596
|
options: {
|
|
@@ -17865,15 +18599,15 @@ async function run20(args) {
|
|
|
17865
18599
|
}
|
|
17866
18600
|
});
|
|
17867
18601
|
} catch (e) {
|
|
17868
|
-
return fail("USAGE", e instanceof Error ? e.message : String(e),
|
|
18602
|
+
return fail("USAGE", e instanceof Error ? e.message : String(e), HELP25);
|
|
17869
18603
|
}
|
|
17870
18604
|
if (parsed.values.help) {
|
|
17871
|
-
await writeStdout(
|
|
18605
|
+
await writeStdout(HELP25);
|
|
17872
18606
|
return EXIT.OK;
|
|
17873
18607
|
}
|
|
17874
18608
|
const path = parsed.positionals[0];
|
|
17875
18609
|
if (!path)
|
|
17876
|
-
return fail("USAGE", "Missing FILE argument",
|
|
18610
|
+
return fail("USAGE", "Missing FILE argument", HELP25);
|
|
17877
18611
|
const view = await openOrFail(path);
|
|
17878
18612
|
if (typeof view === "number")
|
|
17879
18613
|
return view;
|
|
@@ -17881,7 +18615,7 @@ async function run20(args) {
|
|
|
17881
18615
|
await respond(view.doc);
|
|
17882
18616
|
return EXIT.OK;
|
|
17883
18617
|
}
|
|
17884
|
-
var
|
|
18618
|
+
var HELP25 = `docx read \u2014 print AST as JSON
|
|
17885
18619
|
|
|
17886
18620
|
Usage:
|
|
17887
18621
|
docx read FILE [options]
|
|
@@ -17939,7 +18673,7 @@ function collectRunSlots(paragraph) {
|
|
|
17939
18673
|
offset += length;
|
|
17940
18674
|
continue;
|
|
17941
18675
|
}
|
|
17942
|
-
if (child.tag === "w:ins" || child.tag === "w:del") {
|
|
18676
|
+
if (child.tag === "w:ins" || child.tag === "w:del" || child.tag === "w:hyperlink") {
|
|
17943
18677
|
for (const inner of child.children) {
|
|
17944
18678
|
if (inner.tag !== "w:r")
|
|
17945
18679
|
continue;
|
|
@@ -17964,14 +18698,14 @@ function rebuildContainer(container, baseOffset, span, replacement, runPropertie
|
|
|
17964
18698
|
if (placed)
|
|
17965
18699
|
return;
|
|
17966
18700
|
placed = true;
|
|
17967
|
-
const
|
|
18701
|
+
const run26 = /* @__PURE__ */ jsxDEV(ReplacementRun, {
|
|
17968
18702
|
runProperties,
|
|
17969
18703
|
text: replacement
|
|
17970
18704
|
}, undefined, false, undefined, this);
|
|
17971
18705
|
newChildren.push(tracked && isParagraph ? /* @__PURE__ */ jsxDEV(Ins, {
|
|
17972
18706
|
meta: mintMeta(tracked),
|
|
17973
|
-
children:
|
|
17974
|
-
}, undefined, false, undefined, this) :
|
|
18707
|
+
children: run26
|
|
18708
|
+
}, undefined, false, undefined, this) : run26);
|
|
17975
18709
|
};
|
|
17976
18710
|
for (const child of container.children) {
|
|
17977
18711
|
if (child.tag === "w:r") {
|
|
@@ -18007,7 +18741,7 @@ function rebuildContainer(container, baseOffset, span, replacement, runPropertie
|
|
|
18007
18741
|
}
|
|
18008
18742
|
continue;
|
|
18009
18743
|
}
|
|
18010
|
-
if (isParagraph && (child.tag === "w:ins" || child.tag === "w:del")) {
|
|
18744
|
+
if (isParagraph && (child.tag === "w:ins" || child.tag === "w:del" || child.tag === "w:hyperlink")) {
|
|
18011
18745
|
let innerLength = 0;
|
|
18012
18746
|
for (const inner of child.children) {
|
|
18013
18747
|
if (inner.tag === "w:r")
|
|
@@ -18031,14 +18765,14 @@ function rebuildAcrossBoundaries(paragraph, span, replacement, runProperties, tr
|
|
|
18031
18765
|
if (placed)
|
|
18032
18766
|
return;
|
|
18033
18767
|
placed = true;
|
|
18034
|
-
const
|
|
18768
|
+
const run26 = /* @__PURE__ */ jsxDEV(ReplacementRun, {
|
|
18035
18769
|
runProperties,
|
|
18036
18770
|
text: replacement
|
|
18037
18771
|
}, undefined, false, undefined, this);
|
|
18038
18772
|
newChildren.push(tracked ? /* @__PURE__ */ jsxDEV(Ins, {
|
|
18039
18773
|
meta: mintMeta(tracked),
|
|
18040
|
-
children:
|
|
18041
|
-
}, undefined, false, undefined, this) :
|
|
18774
|
+
children: run26
|
|
18775
|
+
}, undefined, false, undefined, this) : run26);
|
|
18042
18776
|
};
|
|
18043
18777
|
for (const child of paragraph.children) {
|
|
18044
18778
|
if (child.tag === "w:r") {
|
|
@@ -18075,7 +18809,7 @@ function rebuildAcrossBoundaries(paragraph, span, replacement, runProperties, tr
|
|
|
18075
18809
|
continue;
|
|
18076
18810
|
}
|
|
18077
18811
|
if (child.tag === "w:ins" || child.tag === "w:del") {
|
|
18078
|
-
const innerLength =
|
|
18812
|
+
const innerLength = sumInnerRunLengths2(child);
|
|
18079
18813
|
const wrapperStart = offset;
|
|
18080
18814
|
const wrapperEnd = offset + innerLength;
|
|
18081
18815
|
offset = wrapperEnd;
|
|
@@ -18091,6 +18825,25 @@ function rebuildAcrossBoundaries(paragraph, span, replacement, runProperties, tr
|
|
|
18091
18825
|
splitWrapperAcrossSpan(child, wrapperStart, span, tracked, newChildren, placeReplacement);
|
|
18092
18826
|
continue;
|
|
18093
18827
|
}
|
|
18828
|
+
if (child.tag === "w:hyperlink") {
|
|
18829
|
+
const innerLength = sumInnerRunLengths2(child);
|
|
18830
|
+
const wrapperStart = offset;
|
|
18831
|
+
const wrapperEnd = offset + innerLength;
|
|
18832
|
+
offset = wrapperEnd;
|
|
18833
|
+
if (wrapperEnd <= span.start) {
|
|
18834
|
+
newChildren.push(child);
|
|
18835
|
+
continue;
|
|
18836
|
+
}
|
|
18837
|
+
if (wrapperStart >= span.end) {
|
|
18838
|
+
placeReplacement();
|
|
18839
|
+
newChildren.push(child);
|
|
18840
|
+
continue;
|
|
18841
|
+
}
|
|
18842
|
+
splitHyperlinkAcrossSpan(child, wrapperStart, span, runProperties, replacement, tracked, newChildren, placeReplacement, () => {
|
|
18843
|
+
placed = true;
|
|
18844
|
+
});
|
|
18845
|
+
continue;
|
|
18846
|
+
}
|
|
18094
18847
|
newChildren.push(child);
|
|
18095
18848
|
}
|
|
18096
18849
|
if (!placed)
|
|
@@ -18151,7 +18904,62 @@ function splitWrapperAcrossSpan(wrapper, wrapperStart, span, tracked, out, place
|
|
|
18151
18904
|
out.push(postWrapper);
|
|
18152
18905
|
}
|
|
18153
18906
|
}
|
|
18154
|
-
function
|
|
18907
|
+
function splitHyperlinkAcrossSpan(wrapper, wrapperStart, span, runProperties, replacement, tracked, out, placeReplacement, markReplacementPlaced) {
|
|
18908
|
+
const wrapperEnd = wrapperStart + wrapper.children.reduce((total, inner) => inner.tag === "w:r" ? total + runTextLength(inner) : total, 0);
|
|
18909
|
+
const startsInside = span.start > wrapperStart && span.start < wrapperEnd;
|
|
18910
|
+
const preInner = [];
|
|
18911
|
+
const postInner = [];
|
|
18912
|
+
let innerOffset = wrapperStart;
|
|
18913
|
+
for (const inner of wrapper.children) {
|
|
18914
|
+
if (inner.tag !== "w:r") {
|
|
18915
|
+
preInner.push(inner);
|
|
18916
|
+
continue;
|
|
18917
|
+
}
|
|
18918
|
+
const length = runTextLength(inner);
|
|
18919
|
+
const runStart = innerOffset;
|
|
18920
|
+
const runEnd = innerOffset + length;
|
|
18921
|
+
innerOffset = runEnd;
|
|
18922
|
+
if (runEnd <= span.start) {
|
|
18923
|
+
preInner.push(inner);
|
|
18924
|
+
continue;
|
|
18925
|
+
}
|
|
18926
|
+
if (runStart >= span.end) {
|
|
18927
|
+
postInner.push(inner);
|
|
18928
|
+
continue;
|
|
18929
|
+
}
|
|
18930
|
+
const sliceStartInRun = Math.max(0, span.start - runStart);
|
|
18931
|
+
const sliceEndInRun = Math.min(length, span.end - runStart);
|
|
18932
|
+
if (sliceStartInRun > 0)
|
|
18933
|
+
preInner.push(sliceRun(inner, 0, sliceStartInRun));
|
|
18934
|
+
if (sliceEndInRun < length) {
|
|
18935
|
+
postInner.push(sliceRun(inner, sliceEndInRun, length));
|
|
18936
|
+
}
|
|
18937
|
+
}
|
|
18938
|
+
if (startsInside) {
|
|
18939
|
+
const innerReplacement = /* @__PURE__ */ jsxDEV(ReplacementRun, {
|
|
18940
|
+
runProperties,
|
|
18941
|
+
text: replacement
|
|
18942
|
+
}, undefined, false, undefined, this);
|
|
18943
|
+
preInner.push(tracked ? /* @__PURE__ */ jsxDEV(Ins, {
|
|
18944
|
+
meta: mintMeta(tracked),
|
|
18945
|
+
children: innerReplacement
|
|
18946
|
+
}, undefined, false, undefined, this) : innerReplacement);
|
|
18947
|
+
markReplacementPlaced();
|
|
18948
|
+
}
|
|
18949
|
+
if (preInner.length > 0) {
|
|
18950
|
+
const preWrapper = new XmlNode2("w:hyperlink", { ...wrapper.attributes });
|
|
18951
|
+
preWrapper.children = preInner;
|
|
18952
|
+
out.push(preWrapper);
|
|
18953
|
+
}
|
|
18954
|
+
if (!startsInside)
|
|
18955
|
+
placeReplacement();
|
|
18956
|
+
if (postInner.length > 0) {
|
|
18957
|
+
const postWrapper = new XmlNode2("w:hyperlink", { ...wrapper.attributes });
|
|
18958
|
+
postWrapper.children = postInner;
|
|
18959
|
+
out.push(postWrapper);
|
|
18960
|
+
}
|
|
18961
|
+
}
|
|
18962
|
+
function sumInnerRunLengths2(wrapper) {
|
|
18155
18963
|
let total = 0;
|
|
18156
18964
|
for (const inner of wrapper.children) {
|
|
18157
18965
|
if (inner.tag === "w:r")
|
|
@@ -18162,8 +18970,8 @@ function sumInnerRunLengths(wrapper) {
|
|
|
18162
18970
|
function mintMeta(tracked) {
|
|
18163
18971
|
return { ...tracked.meta, revisionId: tracked.allocator.next() };
|
|
18164
18972
|
}
|
|
18165
|
-
function convertRunTextToDelText(
|
|
18166
|
-
for (const child of
|
|
18973
|
+
function convertRunTextToDelText(run26) {
|
|
18974
|
+
for (const child of run26.children) {
|
|
18167
18975
|
if (child.tag === "w:t")
|
|
18168
18976
|
child.tag = "w:delText";
|
|
18169
18977
|
}
|
|
@@ -18190,15 +18998,15 @@ var init_replace_span = __esm(() => {
|
|
|
18190
18998
|
});
|
|
18191
18999
|
|
|
18192
19000
|
// src/cli/replace/index.ts
|
|
18193
|
-
var
|
|
18194
|
-
__export(
|
|
18195
|
-
run: () =>
|
|
19001
|
+
var exports_replace3 = {};
|
|
19002
|
+
__export(exports_replace3, {
|
|
19003
|
+
run: () => run26
|
|
18196
19004
|
});
|
|
18197
|
-
import { parseArgs as
|
|
18198
|
-
async function
|
|
19005
|
+
import { parseArgs as parseArgs22 } from "util";
|
|
19006
|
+
async function run26(args) {
|
|
18199
19007
|
let parsed;
|
|
18200
19008
|
try {
|
|
18201
|
-
parsed =
|
|
19009
|
+
parsed = parseArgs22({
|
|
18202
19010
|
args,
|
|
18203
19011
|
allowPositionals: true,
|
|
18204
19012
|
options: {
|
|
@@ -18213,21 +19021,21 @@ async function run21(args) {
|
|
|
18213
19021
|
});
|
|
18214
19022
|
} catch (parseError) {
|
|
18215
19023
|
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
18216
|
-
return fail("USAGE", message,
|
|
19024
|
+
return fail("USAGE", message, HELP26);
|
|
18217
19025
|
}
|
|
18218
19026
|
if (parsed.values.help) {
|
|
18219
|
-
await writeStdout(
|
|
19027
|
+
await writeStdout(HELP26);
|
|
18220
19028
|
return EXIT.OK;
|
|
18221
19029
|
}
|
|
18222
19030
|
const path = parsed.positionals[0];
|
|
18223
19031
|
const pattern = parsed.positionals[1];
|
|
18224
19032
|
const replacement = parsed.positionals[2];
|
|
18225
19033
|
if (!path)
|
|
18226
|
-
return fail("USAGE", "Missing FILE argument",
|
|
19034
|
+
return fail("USAGE", "Missing FILE argument", HELP26);
|
|
18227
19035
|
if (pattern == null)
|
|
18228
|
-
return fail("USAGE", "Missing PATTERN argument",
|
|
19036
|
+
return fail("USAGE", "Missing PATTERN argument", HELP26);
|
|
18229
19037
|
if (replacement == null) {
|
|
18230
|
-
return fail("USAGE", "Missing REPLACEMENT argument",
|
|
19038
|
+
return fail("USAGE", "Missing REPLACEMENT argument", HELP26);
|
|
18231
19039
|
}
|
|
18232
19040
|
const ignoreCase = Boolean(parsed.values["ignore-case"]);
|
|
18233
19041
|
const useRegex = Boolean(parsed.values.regex);
|
|
@@ -18329,7 +19137,7 @@ async function run21(args) {
|
|
|
18329
19137
|
});
|
|
18330
19138
|
return EXIT.OK;
|
|
18331
19139
|
}
|
|
18332
|
-
var
|
|
19140
|
+
var HELP26 = `docx replace \u2014 substitute text spans (sed for docx)
|
|
18333
19141
|
|
|
18334
19142
|
Usage:
|
|
18335
19143
|
docx replace FILE PATTERN REPLACEMENT [options]
|
|
@@ -18363,7 +19171,7 @@ Examples:
|
|
|
18363
19171
|
docx replace doc.docx "(\\w+) (\\w+)" "$2 $1" --regex --all
|
|
18364
19172
|
docx replace doc.docx "wordy phrase" "tighter phrase" --all --dry-run
|
|
18365
19173
|
`;
|
|
18366
|
-
var
|
|
19174
|
+
var init_replace3 = __esm(() => {
|
|
18367
19175
|
init_core();
|
|
18368
19176
|
init_respond();
|
|
18369
19177
|
init_replace_span();
|
|
@@ -18372,13 +19180,13 @@ var init_replace2 = __esm(() => {
|
|
|
18372
19180
|
// src/cli/track-changes/index.tsx
|
|
18373
19181
|
var exports_track_changes = {};
|
|
18374
19182
|
__export(exports_track_changes, {
|
|
18375
|
-
run: () =>
|
|
19183
|
+
run: () => run27
|
|
18376
19184
|
});
|
|
18377
|
-
import { parseArgs as
|
|
18378
|
-
async function
|
|
19185
|
+
import { parseArgs as parseArgs23 } from "util";
|
|
19186
|
+
async function run27(args) {
|
|
18379
19187
|
let parsed;
|
|
18380
19188
|
try {
|
|
18381
|
-
parsed =
|
|
19189
|
+
parsed = parseArgs23({
|
|
18382
19190
|
args,
|
|
18383
19191
|
allowPositionals: true,
|
|
18384
19192
|
options: {
|
|
@@ -18389,18 +19197,18 @@ async function run22(args) {
|
|
|
18389
19197
|
});
|
|
18390
19198
|
} catch (parseError) {
|
|
18391
19199
|
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
18392
|
-
return fail("USAGE", message,
|
|
19200
|
+
return fail("USAGE", message, HELP27);
|
|
18393
19201
|
}
|
|
18394
19202
|
if (parsed.values.help) {
|
|
18395
|
-
await writeStdout(
|
|
19203
|
+
await writeStdout(HELP27);
|
|
18396
19204
|
return EXIT.OK;
|
|
18397
19205
|
}
|
|
18398
19206
|
const path = parsed.positionals[0];
|
|
18399
19207
|
if (!path)
|
|
18400
|
-
return fail("USAGE", "Missing FILE argument",
|
|
19208
|
+
return fail("USAGE", "Missing FILE argument", HELP27);
|
|
18401
19209
|
const mode = parsed.positionals[1];
|
|
18402
19210
|
if (mode !== "on" && mode !== "off") {
|
|
18403
|
-
return fail("USAGE", `Expected "on" or "off", got: ${mode ?? "<nothing>"}`,
|
|
19211
|
+
return fail("USAGE", `Expected "on" or "off", got: ${mode ?? "<nothing>"}`, HELP27);
|
|
18404
19212
|
}
|
|
18405
19213
|
const view = await openOrFail(path);
|
|
18406
19214
|
if (typeof view === "number")
|
|
@@ -18452,7 +19260,7 @@ async function run22(args) {
|
|
|
18452
19260
|
});
|
|
18453
19261
|
return EXIT.OK;
|
|
18454
19262
|
}
|
|
18455
|
-
var
|
|
19263
|
+
var HELP27 = `docx track-changes \u2014 toggle the document's tracked-changes mode
|
|
18456
19264
|
|
|
18457
19265
|
Usage:
|
|
18458
19266
|
docx track-changes FILE on|off [options]
|
|
@@ -18487,9 +19295,9 @@ function countWords(text) {
|
|
|
18487
19295
|
}
|
|
18488
19296
|
function paragraphText2(paragraph) {
|
|
18489
19297
|
let out = "";
|
|
18490
|
-
for (const
|
|
18491
|
-
if (
|
|
18492
|
-
out +=
|
|
19298
|
+
for (const run28 of paragraph.runs) {
|
|
19299
|
+
if (run28.type === "text")
|
|
19300
|
+
out += run28.text;
|
|
18493
19301
|
}
|
|
18494
19302
|
return out;
|
|
18495
19303
|
}
|
|
@@ -18579,13 +19387,13 @@ function flattenParagraphs(blocks) {
|
|
|
18579
19387
|
// src/cli/wc/index.ts
|
|
18580
19388
|
var exports_wc = {};
|
|
18581
19389
|
__export(exports_wc, {
|
|
18582
|
-
run: () =>
|
|
19390
|
+
run: () => run28
|
|
18583
19391
|
});
|
|
18584
|
-
import { parseArgs as
|
|
18585
|
-
async function
|
|
19392
|
+
import { parseArgs as parseArgs24 } from "util";
|
|
19393
|
+
async function run28(args) {
|
|
18586
19394
|
let parsed;
|
|
18587
19395
|
try {
|
|
18588
|
-
parsed =
|
|
19396
|
+
parsed = parseArgs24({
|
|
18589
19397
|
args,
|
|
18590
19398
|
allowPositionals: true,
|
|
18591
19399
|
options: {
|
|
@@ -18594,16 +19402,16 @@ async function run23(args) {
|
|
|
18594
19402
|
});
|
|
18595
19403
|
} catch (parseError) {
|
|
18596
19404
|
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
18597
|
-
return fail("USAGE", message,
|
|
19405
|
+
return fail("USAGE", message, HELP28);
|
|
18598
19406
|
}
|
|
18599
19407
|
if (parsed.values.help) {
|
|
18600
|
-
await writeStdout(
|
|
19408
|
+
await writeStdout(HELP28);
|
|
18601
19409
|
return EXIT.OK;
|
|
18602
19410
|
}
|
|
18603
19411
|
const path = parsed.positionals[0];
|
|
18604
19412
|
const locatorInput = parsed.positionals[1];
|
|
18605
19413
|
if (!path)
|
|
18606
|
-
return fail("USAGE", "Missing FILE argument",
|
|
19414
|
+
return fail("USAGE", "Missing FILE argument", HELP28);
|
|
18607
19415
|
const view = await openOrFail(path);
|
|
18608
19416
|
if (typeof view === "number")
|
|
18609
19417
|
return view;
|
|
@@ -18732,7 +19540,7 @@ function findCellBlocks(blocks, locator) {
|
|
|
18732
19540
|
return null;
|
|
18733
19541
|
return cell.blocks;
|
|
18734
19542
|
}
|
|
18735
|
-
var
|
|
19543
|
+
var HELP28 = `docx wc \u2014 count words in a document or a locator-addressed slice
|
|
18736
19544
|
|
|
18737
19545
|
Usage:
|
|
18738
19546
|
docx wc FILE [LOCATOR] [options]
|
|
@@ -18769,7 +19577,7 @@ var init_wc = __esm(() => {
|
|
|
18769
19577
|
// package.json
|
|
18770
19578
|
var package_default = {
|
|
18771
19579
|
name: "bun-docx",
|
|
18772
|
-
version: "0.
|
|
19580
|
+
version: "0.5.0",
|
|
18773
19581
|
description: "CLI for AI agents (Claude, Codex) to read, edit, and comment on .docx files with full format fidelity.",
|
|
18774
19582
|
keywords: [
|
|
18775
19583
|
"docx",
|
|
@@ -18848,6 +19656,7 @@ Commands:
|
|
|
18848
19656
|
outline FILE List headings as a hierarchical tree
|
|
18849
19657
|
comments \u2026 Add, reply, resolve, delete, list comments
|
|
18850
19658
|
images \u2026 Extract, replace, list images
|
|
19659
|
+
hyperlinks \u2026 List, replace hyperlinks
|
|
18851
19660
|
track-changes FILE on|off Toggle tracked-changes mode
|
|
18852
19661
|
info \u2026 Reference material (schema, locators)
|
|
18853
19662
|
|
|
@@ -18874,12 +19683,13 @@ var COMMANDS = {
|
|
|
18874
19683
|
delete: () => Promise.resolve().then(() => (init_delete2(), exports_delete2)),
|
|
18875
19684
|
edit: () => Promise.resolve().then(() => (init_edit(), exports_edit)),
|
|
18876
19685
|
find: () => Promise.resolve().then(() => (init_find(), exports_find)),
|
|
19686
|
+
hyperlinks: () => Promise.resolve().then(() => (init_hyperlinks(), exports_hyperlinks)),
|
|
18877
19687
|
images: () => Promise.resolve().then(() => (init_images(), exports_images)),
|
|
18878
19688
|
info: () => Promise.resolve().then(() => (init_info(), exports_info)),
|
|
18879
19689
|
insert: () => Promise.resolve().then(() => (init_insert(), exports_insert)),
|
|
18880
19690
|
outline: () => Promise.resolve().then(() => (init_outline(), exports_outline)),
|
|
18881
19691
|
read: () => Promise.resolve().then(() => (init_read2(), exports_read)),
|
|
18882
|
-
replace: () => Promise.resolve().then(() => (
|
|
19692
|
+
replace: () => Promise.resolve().then(() => (init_replace3(), exports_replace3)),
|
|
18883
19693
|
"track-changes": () => Promise.resolve().then(() => (init_track_changes2(), exports_track_changes)),
|
|
18884
19694
|
wc: () => Promise.resolve().then(() => (init_wc(), exports_wc))
|
|
18885
19695
|
};
|