bun-docx 0.6.0 → 0.7.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 +27 -10
- package/dist/index.js +1419 -217
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -13570,36 +13570,81 @@ var init_xml_node = __esm(() => {
|
|
|
13570
13570
|
});
|
|
13571
13571
|
|
|
13572
13572
|
// src/core/parser/run-ops.ts
|
|
13573
|
+
function isSubtractiveTrackedChangeWrapper(tag) {
|
|
13574
|
+
return tag === "w:del" || tag === "w:moveFrom";
|
|
13575
|
+
}
|
|
13573
13576
|
function runTextLength(run) {
|
|
13574
13577
|
let total = 0;
|
|
13575
13578
|
for (const child of run.children) {
|
|
13576
13579
|
if (child.tag === "w:t")
|
|
13577
13580
|
total += child.collectText().length;
|
|
13581
|
+
else if (SINGLE_CHAR_TAGS.has(child.tag))
|
|
13582
|
+
total += 1;
|
|
13578
13583
|
}
|
|
13579
13584
|
return total;
|
|
13580
13585
|
}
|
|
13581
13586
|
function sliceRun(run, start, end) {
|
|
13582
13587
|
const sliced = new XmlNode2("w:r", { ...run.attributes });
|
|
13583
|
-
let
|
|
13588
|
+
let offset = 0;
|
|
13584
13589
|
for (const child of run.children) {
|
|
13585
|
-
if (child.tag === "w:
|
|
13590
|
+
if (child.tag === "w:rPr") {
|
|
13591
|
+
sliced.children.push(child.clone());
|
|
13592
|
+
continue;
|
|
13593
|
+
}
|
|
13594
|
+
if (child.tag === "w:t" || child.tag === "w:delText") {
|
|
13586
13595
|
const text = child.collectText();
|
|
13587
|
-
const localStart = Math.max(0, start -
|
|
13588
|
-
const localEnd = Math.min(text.length, end -
|
|
13596
|
+
const localStart = Math.max(0, start - offset);
|
|
13597
|
+
const localEnd = Math.min(text.length, end - offset);
|
|
13589
13598
|
if (localStart < localEnd) {
|
|
13590
|
-
const slicedText = new XmlNode2(
|
|
13599
|
+
const slicedText = new XmlNode2(child.tag, { "xml:space": "preserve" });
|
|
13591
13600
|
slicedText.children.push(XmlNode2.textNode(text.slice(localStart, localEnd)));
|
|
13592
13601
|
sliced.children.push(slicedText);
|
|
13593
13602
|
}
|
|
13594
|
-
|
|
13603
|
+
offset += text.length;
|
|
13604
|
+
continue;
|
|
13605
|
+
}
|
|
13606
|
+
if (SINGLE_CHAR_TAGS.has(child.tag)) {
|
|
13607
|
+
if (offset >= start && offset < end) {
|
|
13608
|
+
sliced.children.push(child.clone());
|
|
13609
|
+
}
|
|
13610
|
+
offset += 1;
|
|
13595
13611
|
continue;
|
|
13596
13612
|
}
|
|
13597
|
-
|
|
13613
|
+
if (offset >= start && offset < end) {
|
|
13614
|
+
sliced.children.push(child.clone());
|
|
13615
|
+
}
|
|
13598
13616
|
}
|
|
13599
13617
|
return sliced;
|
|
13600
13618
|
}
|
|
13619
|
+
function isRunBearingWrapper(tag) {
|
|
13620
|
+
return RUN_BEARING_WRAPPER_TAGS.has(tag);
|
|
13621
|
+
}
|
|
13622
|
+
function sumRunBearingTextLength(children) {
|
|
13623
|
+
let total = 0;
|
|
13624
|
+
for (const child of children) {
|
|
13625
|
+
if (child.tag === "w:r") {
|
|
13626
|
+
total += runTextLength(child);
|
|
13627
|
+
continue;
|
|
13628
|
+
}
|
|
13629
|
+
if (isRunBearingWrapper(child.tag)) {
|
|
13630
|
+
total += sumRunBearingTextLength(child.children);
|
|
13631
|
+
}
|
|
13632
|
+
}
|
|
13633
|
+
return total;
|
|
13634
|
+
}
|
|
13635
|
+
var SINGLE_CHAR_TAGS, RUN_BEARING_WRAPPER_TAGS;
|
|
13601
13636
|
var init_run_ops = __esm(() => {
|
|
13602
13637
|
init_xml_node();
|
|
13638
|
+
SINGLE_CHAR_TAGS = new Set(["w:noBreakHyphen", "w:softHyphen", "w:sym"]);
|
|
13639
|
+
RUN_BEARING_WRAPPER_TAGS = new Set([
|
|
13640
|
+
"w:ins",
|
|
13641
|
+
"w:del",
|
|
13642
|
+
"w:moveFrom",
|
|
13643
|
+
"w:moveTo",
|
|
13644
|
+
"w:hyperlink",
|
|
13645
|
+
"w:fldSimple",
|
|
13646
|
+
"w:smartTag"
|
|
13647
|
+
]);
|
|
13603
13648
|
});
|
|
13604
13649
|
|
|
13605
13650
|
// src/core/parser/index.ts
|
|
@@ -13760,6 +13805,311 @@ var init_package = __esm(() => {
|
|
|
13760
13805
|
};
|
|
13761
13806
|
});
|
|
13762
13807
|
|
|
13808
|
+
// src/core/ast/sym.ts
|
|
13809
|
+
function decodeSym(font, charHex) {
|
|
13810
|
+
const codepoint = Number.parseInt(charHex, 16);
|
|
13811
|
+
if (!Number.isFinite(codepoint))
|
|
13812
|
+
return "";
|
|
13813
|
+
const fontKey = font.toLowerCase().trim();
|
|
13814
|
+
const table = TABLES.get(fontKey);
|
|
13815
|
+
if (table) {
|
|
13816
|
+
const mapped = table.get(codepoint);
|
|
13817
|
+
if (mapped !== undefined)
|
|
13818
|
+
return mapped;
|
|
13819
|
+
}
|
|
13820
|
+
if (table && codepoint >= 61440 && codepoint <= 61695) {
|
|
13821
|
+
const aliased = table.get(codepoint - 61440);
|
|
13822
|
+
if (aliased !== undefined)
|
|
13823
|
+
return aliased;
|
|
13824
|
+
}
|
|
13825
|
+
if (table && codepoint >= 32 && codepoint <= 255) {
|
|
13826
|
+
const aliased = table.get(codepoint + 61440);
|
|
13827
|
+
if (aliased !== undefined)
|
|
13828
|
+
return aliased;
|
|
13829
|
+
}
|
|
13830
|
+
try {
|
|
13831
|
+
return String.fromCodePoint(codepoint);
|
|
13832
|
+
} catch {
|
|
13833
|
+
return "";
|
|
13834
|
+
}
|
|
13835
|
+
}
|
|
13836
|
+
var SYMBOL, WINGDINGS, WINGDINGS_2, WEBDINGS, ZAPF_DINGBATS, TABLES;
|
|
13837
|
+
var init_sym = __esm(() => {
|
|
13838
|
+
SYMBOL = [
|
|
13839
|
+
[33, "!"],
|
|
13840
|
+
[34, "\u2200"],
|
|
13841
|
+
[35, "#"],
|
|
13842
|
+
[36, "\u2203"],
|
|
13843
|
+
[37, "%"],
|
|
13844
|
+
[38, "&"],
|
|
13845
|
+
[39, "\u220B"],
|
|
13846
|
+
[40, "("],
|
|
13847
|
+
[41, ")"],
|
|
13848
|
+
[42, "\u2217"],
|
|
13849
|
+
[43, "+"],
|
|
13850
|
+
[44, ","],
|
|
13851
|
+
[45, "\u2212"],
|
|
13852
|
+
[46, "."],
|
|
13853
|
+
[47, "/"],
|
|
13854
|
+
[48, "0"],
|
|
13855
|
+
[49, "1"],
|
|
13856
|
+
[50, "2"],
|
|
13857
|
+
[51, "3"],
|
|
13858
|
+
[52, "4"],
|
|
13859
|
+
[53, "5"],
|
|
13860
|
+
[54, "6"],
|
|
13861
|
+
[55, "7"],
|
|
13862
|
+
[56, "8"],
|
|
13863
|
+
[57, "9"],
|
|
13864
|
+
[58, ":"],
|
|
13865
|
+
[59, ";"],
|
|
13866
|
+
[60, "<"],
|
|
13867
|
+
[61, "="],
|
|
13868
|
+
[62, ">"],
|
|
13869
|
+
[63, "?"],
|
|
13870
|
+
[64, "\u2245"],
|
|
13871
|
+
[65, "\u0391"],
|
|
13872
|
+
[66, "\u0392"],
|
|
13873
|
+
[67, "\u03A7"],
|
|
13874
|
+
[68, "\u0394"],
|
|
13875
|
+
[69, "\u0395"],
|
|
13876
|
+
[70, "\u03A6"],
|
|
13877
|
+
[71, "\u0393"],
|
|
13878
|
+
[72, "\u0397"],
|
|
13879
|
+
[73, "\u0399"],
|
|
13880
|
+
[74, "\u03D1"],
|
|
13881
|
+
[75, "\u039A"],
|
|
13882
|
+
[76, "\u039B"],
|
|
13883
|
+
[77, "\u039C"],
|
|
13884
|
+
[78, "\u039D"],
|
|
13885
|
+
[79, "\u039F"],
|
|
13886
|
+
[80, "\u03A0"],
|
|
13887
|
+
[81, "\u0398"],
|
|
13888
|
+
[82, "\u03A1"],
|
|
13889
|
+
[83, "\u03A3"],
|
|
13890
|
+
[84, "\u03A4"],
|
|
13891
|
+
[85, "\u03A5"],
|
|
13892
|
+
[86, "\u03C2"],
|
|
13893
|
+
[87, "\u03A9"],
|
|
13894
|
+
[88, "\u039E"],
|
|
13895
|
+
[89, "\u03A8"],
|
|
13896
|
+
[90, "\u0396"],
|
|
13897
|
+
[91, "["],
|
|
13898
|
+
[92, "\u2234"],
|
|
13899
|
+
[93, "]"],
|
|
13900
|
+
[94, "\u22A5"],
|
|
13901
|
+
[95, "_"],
|
|
13902
|
+
[96, "\u203E"],
|
|
13903
|
+
[97, "\u03B1"],
|
|
13904
|
+
[98, "\u03B2"],
|
|
13905
|
+
[99, "\u03C7"],
|
|
13906
|
+
[100, "\u03B4"],
|
|
13907
|
+
[101, "\u03B5"],
|
|
13908
|
+
[102, "\u03C6"],
|
|
13909
|
+
[103, "\u03B3"],
|
|
13910
|
+
[104, "\u03B7"],
|
|
13911
|
+
[105, "\u03B9"],
|
|
13912
|
+
[106, "\u03D5"],
|
|
13913
|
+
[107, "\u03BA"],
|
|
13914
|
+
[108, "\u03BB"],
|
|
13915
|
+
[109, "\u03BC"],
|
|
13916
|
+
[110, "\u03BD"],
|
|
13917
|
+
[111, "\u03BF"],
|
|
13918
|
+
[112, "\u03C0"],
|
|
13919
|
+
[113, "\u03B8"],
|
|
13920
|
+
[114, "\u03C1"],
|
|
13921
|
+
[115, "\u03C3"],
|
|
13922
|
+
[116, "\u03C4"],
|
|
13923
|
+
[117, "\u03C5"],
|
|
13924
|
+
[118, "\u03D6"],
|
|
13925
|
+
[119, "\u03C9"],
|
|
13926
|
+
[120, "\u03BE"],
|
|
13927
|
+
[121, "\u03C8"],
|
|
13928
|
+
[122, "\u03B6"],
|
|
13929
|
+
[123, "{"],
|
|
13930
|
+
[124, "|"],
|
|
13931
|
+
[125, "}"],
|
|
13932
|
+
[126, "\u223C"],
|
|
13933
|
+
[160, "\u20AC"],
|
|
13934
|
+
[161, "\u03D2"],
|
|
13935
|
+
[162, "\u2032"],
|
|
13936
|
+
[163, "\u2264"],
|
|
13937
|
+
[164, "\u2044"],
|
|
13938
|
+
[165, "\u221E"],
|
|
13939
|
+
[166, "\u0192"],
|
|
13940
|
+
[167, "\u2663"],
|
|
13941
|
+
[168, "\u2666"],
|
|
13942
|
+
[169, "\u2665"],
|
|
13943
|
+
[170, "\u2660"],
|
|
13944
|
+
[171, "\u2194"],
|
|
13945
|
+
[172, "\u2190"],
|
|
13946
|
+
[173, "\u2191"],
|
|
13947
|
+
[174, "\u2192"],
|
|
13948
|
+
[175, "\u2193"],
|
|
13949
|
+
[176, "\xB0"],
|
|
13950
|
+
[177, "\xB1"],
|
|
13951
|
+
[178, "\u2033"],
|
|
13952
|
+
[179, "\u2265"],
|
|
13953
|
+
[180, "\xD7"],
|
|
13954
|
+
[181, "\u221D"],
|
|
13955
|
+
[182, "\u2202"],
|
|
13956
|
+
[183, "\u2022"],
|
|
13957
|
+
[184, "\xF7"],
|
|
13958
|
+
[185, "\u2260"],
|
|
13959
|
+
[186, "\u2261"],
|
|
13960
|
+
[187, "\u2248"],
|
|
13961
|
+
[188, "\u2026"],
|
|
13962
|
+
[189, "|"],
|
|
13963
|
+
[190, "\u2014"],
|
|
13964
|
+
[191, "\u21B5"],
|
|
13965
|
+
[192, "\u2135"],
|
|
13966
|
+
[193, "\u2111"],
|
|
13967
|
+
[194, "\u211C"],
|
|
13968
|
+
[195, "\u2118"],
|
|
13969
|
+
[196, "\u2297"],
|
|
13970
|
+
[197, "\u2295"],
|
|
13971
|
+
[198, "\u2205"],
|
|
13972
|
+
[199, "\u2229"],
|
|
13973
|
+
[200, "\u222A"],
|
|
13974
|
+
[201, "\u2283"],
|
|
13975
|
+
[202, "\u2287"],
|
|
13976
|
+
[203, "\u2284"],
|
|
13977
|
+
[204, "\u2282"],
|
|
13978
|
+
[205, "\u2286"],
|
|
13979
|
+
[206, "\u2208"],
|
|
13980
|
+
[207, "\u2209"],
|
|
13981
|
+
[208, "\u2220"],
|
|
13982
|
+
[209, "\u2207"],
|
|
13983
|
+
[210, "\xAE"],
|
|
13984
|
+
[211, "\xA9"],
|
|
13985
|
+
[212, "\u2122"],
|
|
13986
|
+
[213, "\u220F"],
|
|
13987
|
+
[214, "\u221A"],
|
|
13988
|
+
[215, "\xB7"],
|
|
13989
|
+
[216, "\xAC"],
|
|
13990
|
+
[217, "\u2227"],
|
|
13991
|
+
[218, "\u2228"],
|
|
13992
|
+
[219, "\u21D4"],
|
|
13993
|
+
[220, "\u21D0"],
|
|
13994
|
+
[221, "\u21D1"],
|
|
13995
|
+
[222, "\u21D2"],
|
|
13996
|
+
[223, "\u21D3"],
|
|
13997
|
+
[224, "\u25CA"],
|
|
13998
|
+
[225, "\u27E8"],
|
|
13999
|
+
[229, "\u2211"],
|
|
14000
|
+
[241, "\u27E9"],
|
|
14001
|
+
[242, "\u222B"]
|
|
14002
|
+
];
|
|
14003
|
+
WINGDINGS = [
|
|
14004
|
+
[61474, "\u2702"],
|
|
14005
|
+
[61479, "\u260E"],
|
|
14006
|
+
[61480, "\u2706"],
|
|
14007
|
+
[61481, "\u2709"],
|
|
14008
|
+
[61501, "\u231B"],
|
|
14009
|
+
[61514, "\u263A"],
|
|
14010
|
+
[61515, "\uD83D\uDE10"],
|
|
14011
|
+
[61516, "\u2639"],
|
|
14012
|
+
[61519, "\u2620"],
|
|
14013
|
+
[61520, "\uD83C\uDFF3"],
|
|
14014
|
+
[61521, "\uD83C\uDFF4"],
|
|
14015
|
+
[61528, "\u261C"],
|
|
14016
|
+
[61529, "\u261E"],
|
|
14017
|
+
[61530, "\u261D"],
|
|
14018
|
+
[61531, "\u261F"],
|
|
14019
|
+
[61548, "\u2751"],
|
|
14020
|
+
[61549, "\u2752"],
|
|
14021
|
+
[61550, "\u25AA"],
|
|
14022
|
+
[61551, "\u25A1"],
|
|
14023
|
+
[61553, "\u25C6"],
|
|
14024
|
+
[61555, "\u25CF"],
|
|
14025
|
+
[61556, "\u25A0"],
|
|
14026
|
+
[61557, "\u25CF"],
|
|
14027
|
+
[61558, "\u25C6"],
|
|
14028
|
+
[61559, "\u2756"],
|
|
14029
|
+
[61607, "\u25AA"],
|
|
14030
|
+
[61608, "\u25AB"],
|
|
14031
|
+
[61664, "\u2190"],
|
|
14032
|
+
[61665, "\u2192"],
|
|
14033
|
+
[61666, "\u2191"],
|
|
14034
|
+
[61667, "\u2193"],
|
|
14035
|
+
[61668, "\u2196"],
|
|
14036
|
+
[61669, "\u2197"],
|
|
14037
|
+
[61670, "\u2198"],
|
|
14038
|
+
[61671, "\u2199"],
|
|
14039
|
+
[61672, "\u2194"],
|
|
14040
|
+
[61673, "\u2195"],
|
|
14041
|
+
[61690, "\u2713"],
|
|
14042
|
+
[61691, "\u2713"],
|
|
14043
|
+
[61692, "\u2713"],
|
|
14044
|
+
[61693, "\u2717"],
|
|
14045
|
+
[61694, "\u2717"]
|
|
14046
|
+
];
|
|
14047
|
+
WINGDINGS_2 = [
|
|
14048
|
+
[61520, "\u25B6"],
|
|
14049
|
+
[61521, "\u25C0"],
|
|
14050
|
+
[61522, "\u25B2"],
|
|
14051
|
+
[61523, "\u25BC"],
|
|
14052
|
+
[61656, "\u2752"],
|
|
14053
|
+
[61657, "\u2610"],
|
|
14054
|
+
[61691, "\u2611"],
|
|
14055
|
+
[61692, "\u2612"],
|
|
14056
|
+
[61693, "\u2713"],
|
|
14057
|
+
[61694, "\u2717"],
|
|
14058
|
+
[61695, "\u2718"]
|
|
14059
|
+
];
|
|
14060
|
+
WEBDINGS = [
|
|
14061
|
+
[61473, "\uD83D\uDD77"],
|
|
14062
|
+
[61476, "\uD83D\uDC41"],
|
|
14063
|
+
[61477, "\uD83D\uDC42"],
|
|
14064
|
+
[61490, "\uD83C\uDF10"],
|
|
14065
|
+
[61497, "\u2709"],
|
|
14066
|
+
[61500, "\uD83D\uDCC5"],
|
|
14067
|
+
[61504, "\uD83C\uDFE0"],
|
|
14068
|
+
[61514, "\uD83D\uDCDE"],
|
|
14069
|
+
[61528, "\uD83D\uDD0D"],
|
|
14070
|
+
[61543, "\uD83D\uDD12"],
|
|
14071
|
+
[61544, "\uD83D\uDD13"],
|
|
14072
|
+
[61560, "\u270F"],
|
|
14073
|
+
[61604, "\u2605"]
|
|
14074
|
+
];
|
|
14075
|
+
ZAPF_DINGBATS = [
|
|
14076
|
+
[33, "\u2701"],
|
|
14077
|
+
[34, "\u2702"],
|
|
14078
|
+
[35, "\u2703"],
|
|
14079
|
+
[36, "\u2704"],
|
|
14080
|
+
[43, "\u271A"],
|
|
14081
|
+
[51, "\u2713"],
|
|
14082
|
+
[52, "\u2714"],
|
|
14083
|
+
[53, "\u2715"],
|
|
14084
|
+
[54, "\u2716"],
|
|
14085
|
+
[55, "\u2717"],
|
|
14086
|
+
[56, "\u2718"],
|
|
14087
|
+
[57, "\u2719"],
|
|
14088
|
+
[58, "\u271A"],
|
|
14089
|
+
[59, "\u271B"],
|
|
14090
|
+
[60, "\u271C"],
|
|
14091
|
+
[74, "\u2740"],
|
|
14092
|
+
[75, "\u2741"],
|
|
14093
|
+
[76, "\u2742"],
|
|
14094
|
+
[77, "\u2743"],
|
|
14095
|
+
[78, "\u2744"],
|
|
14096
|
+
[79, "\u2745"],
|
|
14097
|
+
[108, "\u25CF"],
|
|
14098
|
+
[110, "\u25A0"],
|
|
14099
|
+
[113, "\u25C6"]
|
|
14100
|
+
];
|
|
14101
|
+
TABLES = new Map([
|
|
14102
|
+
["symbol", new Map(SYMBOL)],
|
|
14103
|
+
["wingdings", new Map(WINGDINGS)],
|
|
14104
|
+
["wingdings 2", new Map(WINGDINGS_2)],
|
|
14105
|
+
["wingdings 3", new Map(WINGDINGS_2)],
|
|
14106
|
+
["webdings", new Map(WEBDINGS)],
|
|
14107
|
+
["zapfdingbats", new Map(ZAPF_DINGBATS)],
|
|
14108
|
+
["zapf dingbats", new Map(ZAPF_DINGBATS)],
|
|
14109
|
+
["itc zapf dingbats", new Map(ZAPF_DINGBATS)]
|
|
14110
|
+
]);
|
|
14111
|
+
});
|
|
14112
|
+
|
|
13763
14113
|
// src/core/ast/read.ts
|
|
13764
14114
|
function buildDoc(view, path) {
|
|
13765
14115
|
readRelationships(view);
|
|
@@ -13775,6 +14125,7 @@ function buildDoc(view, path) {
|
|
|
13775
14125
|
const state = {
|
|
13776
14126
|
imageIndex: 0,
|
|
13777
14127
|
hyperlinkIndex: 0,
|
|
14128
|
+
trackedChangeIndex: 0,
|
|
13778
14129
|
commentAnchors: new Map,
|
|
13779
14130
|
openComments: new Map
|
|
13780
14131
|
};
|
|
@@ -13870,8 +14221,8 @@ function walkRunContainer(context, container, trackedChange, hyperlink) {
|
|
|
13870
14221
|
continue;
|
|
13871
14222
|
}
|
|
13872
14223
|
if (child.tag === "w:r") {
|
|
13873
|
-
const
|
|
13874
|
-
|
|
14224
|
+
const runs = readRun(context.view, child, context.activeComments, trackedChange, hyperlink, context.state);
|
|
14225
|
+
for (const run of runs) {
|
|
13875
14226
|
if (run.type === "text")
|
|
13876
14227
|
context.offsetRef.value += run.text.length;
|
|
13877
14228
|
context.paragraph.runs.push(run);
|
|
@@ -13900,19 +14251,30 @@ function walkRunContainer(context, container, trackedChange, hyperlink) {
|
|
|
13900
14251
|
}
|
|
13901
14252
|
continue;
|
|
13902
14253
|
}
|
|
13903
|
-
if (child.tag === "w:ins" || child.tag === "w:del") {
|
|
14254
|
+
if (child.tag === "w:ins" || child.tag === "w:del" || child.tag === "w:moveFrom" || child.tag === "w:moveTo") {
|
|
14255
|
+
const trackedChangeId = `tc${context.state.trackedChangeIndex++}`;
|
|
13904
14256
|
const change = {
|
|
13905
|
-
|
|
14257
|
+
id: trackedChangeId,
|
|
14258
|
+
kind: TRACKED_CHANGE_KIND_BY_TAG[child.tag],
|
|
13906
14259
|
author: child.getAttribute("w:author") ?? "",
|
|
13907
14260
|
date: child.getAttribute("w:date") ?? "",
|
|
13908
14261
|
revisionId: child.getAttribute("w:id") ?? ""
|
|
13909
14262
|
};
|
|
14263
|
+
context.view.trackedChangeReferences.set(trackedChangeId, {
|
|
14264
|
+
node: child,
|
|
14265
|
+
parent: container.children,
|
|
14266
|
+
blockId: context.blockId
|
|
14267
|
+
});
|
|
13910
14268
|
walkRunContainer(context, child, change, hyperlink);
|
|
13911
14269
|
continue;
|
|
13912
14270
|
}
|
|
13913
14271
|
if (child.tag === "w:hyperlink") {
|
|
13914
14272
|
const link = readHyperlinkProperties(context.view, child, container.children, context.state);
|
|
13915
14273
|
walkRunContainer(context, child, trackedChange, link);
|
|
14274
|
+
continue;
|
|
14275
|
+
}
|
|
14276
|
+
if (child.tag === "w:fldSimple" || child.tag === "w:smartTag") {
|
|
14277
|
+
walkRunContainer(context, child, trackedChange, hyperlink);
|
|
13916
14278
|
}
|
|
13917
14279
|
}
|
|
13918
14280
|
}
|
|
@@ -13967,48 +14329,83 @@ function applyParagraphProperties(paragraph, paragraphProperties) {
|
|
|
13967
14329
|
}
|
|
13968
14330
|
function readRun(view, node, activeComments, trackedChange, hyperlink, state) {
|
|
13969
14331
|
const runProperties = node.findChild("w:rPr");
|
|
14332
|
+
const out = [];
|
|
14333
|
+
let pendingText = "";
|
|
14334
|
+
function flushText() {
|
|
14335
|
+
if (pendingText.length === 0)
|
|
14336
|
+
return;
|
|
14337
|
+
const run = { type: "text", text: pendingText };
|
|
14338
|
+
if (runProperties)
|
|
14339
|
+
applyRunProperties(run, runProperties);
|
|
14340
|
+
if (activeComments.size > 0)
|
|
14341
|
+
run.comments = [...activeComments];
|
|
14342
|
+
if (trackedChange)
|
|
14343
|
+
run.trackedChange = trackedChange;
|
|
14344
|
+
if (hyperlink)
|
|
14345
|
+
run.hyperlink = hyperlink;
|
|
14346
|
+
out.push(run);
|
|
14347
|
+
pendingText = "";
|
|
14348
|
+
}
|
|
13970
14349
|
for (const child of node.children) {
|
|
14350
|
+
if (child.tag === "w:rPr")
|
|
14351
|
+
continue;
|
|
14352
|
+
if (child.tag === "w:t" || child.tag === "w:delText") {
|
|
14353
|
+
pendingText += child.collectText();
|
|
14354
|
+
continue;
|
|
14355
|
+
}
|
|
14356
|
+
if (child.tag === "w:noBreakHyphen") {
|
|
14357
|
+
pendingText += "\u2011";
|
|
14358
|
+
continue;
|
|
14359
|
+
}
|
|
14360
|
+
if (child.tag === "w:softHyphen") {
|
|
14361
|
+
pendingText += "\xAD";
|
|
14362
|
+
continue;
|
|
14363
|
+
}
|
|
14364
|
+
if (child.tag === "w:sym") {
|
|
14365
|
+
const font = child.getAttribute("w:font") ?? "";
|
|
14366
|
+
const charHex = child.getAttribute("w:char") ?? "";
|
|
14367
|
+
pendingText += decodeSym(font, charHex);
|
|
14368
|
+
continue;
|
|
14369
|
+
}
|
|
13971
14370
|
if (child.tag === "w:drawing") {
|
|
14371
|
+
flushText();
|
|
13972
14372
|
const drawing = readDrawing(view, child, state);
|
|
13973
14373
|
if (drawing)
|
|
13974
|
-
|
|
14374
|
+
out.push(drawing);
|
|
14375
|
+
continue;
|
|
13975
14376
|
}
|
|
13976
|
-
if (child.tag === "w:
|
|
13977
|
-
|
|
13978
|
-
|
|
14377
|
+
if (child.tag === "w:pict" || child.tag === "w:object") {
|
|
14378
|
+
flushText();
|
|
14379
|
+
out.push({ type: "chart", kind: "drawing" });
|
|
14380
|
+
continue;
|
|
13979
14381
|
}
|
|
13980
|
-
if (child.tag === "w:
|
|
13981
|
-
|
|
14382
|
+
if (child.tag === "w:br" || child.tag === "w:cr") {
|
|
14383
|
+
flushText();
|
|
14384
|
+
const kind = child.tag === "w:cr" ? "line" : child.getAttribute("w:type") ?? "line";
|
|
14385
|
+
out.push({ type: "break", kind });
|
|
14386
|
+
continue;
|
|
14387
|
+
}
|
|
14388
|
+
if (child.tag === "w:tab" || child.tag === "w:ptab") {
|
|
14389
|
+
flushText();
|
|
14390
|
+
out.push({ type: "tab" });
|
|
14391
|
+
continue;
|
|
13982
14392
|
}
|
|
13983
14393
|
if (child.tag === "w:footnoteReference") {
|
|
14394
|
+
flushText();
|
|
13984
14395
|
const id = child.getAttribute("w:id");
|
|
13985
14396
|
if (id)
|
|
13986
|
-
|
|
14397
|
+
out.push({ type: "footnoteRef", kind: "footnote", id: `fn${id}` });
|
|
14398
|
+
continue;
|
|
13987
14399
|
}
|
|
13988
14400
|
if (child.tag === "w:endnoteReference") {
|
|
14401
|
+
flushText();
|
|
13989
14402
|
const id = child.getAttribute("w:id");
|
|
13990
14403
|
if (id)
|
|
13991
|
-
|
|
14404
|
+
out.push({ type: "footnoteRef", kind: "endnote", id: `en${id}` });
|
|
13992
14405
|
}
|
|
13993
14406
|
}
|
|
13994
|
-
|
|
13995
|
-
|
|
13996
|
-
if (child.tag === "w:t" || child.tag === "w:delText") {
|
|
13997
|
-
combinedText += child.collectText();
|
|
13998
|
-
}
|
|
13999
|
-
}
|
|
14000
|
-
if (combinedText.length === 0)
|
|
14001
|
-
return null;
|
|
14002
|
-
const run = { type: "text", text: combinedText };
|
|
14003
|
-
if (runProperties)
|
|
14004
|
-
applyRunProperties(run, runProperties);
|
|
14005
|
-
if (activeComments.size > 0)
|
|
14006
|
-
run.comments = [...activeComments];
|
|
14007
|
-
if (trackedChange)
|
|
14008
|
-
run.trackedChange = trackedChange;
|
|
14009
|
-
if (hyperlink)
|
|
14010
|
-
run.hyperlink = hyperlink;
|
|
14011
|
-
return run;
|
|
14407
|
+
flushText();
|
|
14408
|
+
return out;
|
|
14012
14409
|
}
|
|
14013
14410
|
function readDrawing(view, drawing, state) {
|
|
14014
14411
|
const image = readImageFromDrawing(view, drawing, state);
|
|
@@ -14307,9 +14704,16 @@ function readNotes(tree, rootTag, itemTag, idPrefix) {
|
|
|
14307
14704
|
}
|
|
14308
14705
|
return out;
|
|
14309
14706
|
}
|
|
14310
|
-
var RELATIONSHIP_NAMESPACE_IMAGE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", RELATIONSHIP_NAMESPACE_HYPERLINK = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
|
|
14707
|
+
var RELATIONSHIP_NAMESPACE_IMAGE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", RELATIONSHIP_NAMESPACE_HYPERLINK = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink", TRACKED_CHANGE_KIND_BY_TAG;
|
|
14311
14708
|
var init_read = __esm(() => {
|
|
14312
14709
|
init_parser();
|
|
14710
|
+
init_sym();
|
|
14711
|
+
TRACKED_CHANGE_KIND_BY_TAG = {
|
|
14712
|
+
"w:ins": "ins",
|
|
14713
|
+
"w:del": "del",
|
|
14714
|
+
"w:moveFrom": "moveFrom",
|
|
14715
|
+
"w:moveTo": "moveTo"
|
|
14716
|
+
};
|
|
14313
14717
|
});
|
|
14314
14718
|
|
|
14315
14719
|
// src/core/ast/doc-view.ts
|
|
@@ -14341,7 +14745,8 @@ async function openDocView(path) {
|
|
|
14341
14745
|
imagesByRelationshipId: new Map,
|
|
14342
14746
|
imageById: new Map,
|
|
14343
14747
|
hyperlinksByRelationshipId: new Map,
|
|
14344
|
-
hyperlinkById: new Map
|
|
14748
|
+
hyperlinkById: new Map,
|
|
14749
|
+
trackedChangeReferences: new Map
|
|
14345
14750
|
};
|
|
14346
14751
|
view.doc = buildDoc(view, pkg.path);
|
|
14347
14752
|
return view;
|
|
@@ -14420,6 +14825,30 @@ function paragraphText(paragraph) {
|
|
|
14420
14825
|
}
|
|
14421
14826
|
return out;
|
|
14422
14827
|
}
|
|
14828
|
+
function paragraphTextAccepted(paragraph) {
|
|
14829
|
+
let out = "";
|
|
14830
|
+
for (const run of paragraph.runs) {
|
|
14831
|
+
if (run.type !== "text")
|
|
14832
|
+
continue;
|
|
14833
|
+
const kind = run.trackedChange?.kind;
|
|
14834
|
+
if (kind === "del" || kind === "moveFrom")
|
|
14835
|
+
continue;
|
|
14836
|
+
out += run.text;
|
|
14837
|
+
}
|
|
14838
|
+
return out;
|
|
14839
|
+
}
|
|
14840
|
+
function paragraphTextBaseline(paragraph) {
|
|
14841
|
+
let out = "";
|
|
14842
|
+
for (const run of paragraph.runs) {
|
|
14843
|
+
if (run.type !== "text")
|
|
14844
|
+
continue;
|
|
14845
|
+
const kind = run.trackedChange?.kind;
|
|
14846
|
+
if (kind === "ins" || kind === "moveTo")
|
|
14847
|
+
continue;
|
|
14848
|
+
out += run.text;
|
|
14849
|
+
}
|
|
14850
|
+
return out;
|
|
14851
|
+
}
|
|
14423
14852
|
function flattenParagraphs(blocks) {
|
|
14424
14853
|
const out = [];
|
|
14425
14854
|
for (const block of blocks) {
|
|
@@ -14475,6 +14904,13 @@ function parseLocator(input) {
|
|
|
14475
14904
|
if (linkMatch) {
|
|
14476
14905
|
return { kind: "hyperlink", hyperlinkId: `link${linkMatch[1]}` };
|
|
14477
14906
|
}
|
|
14907
|
+
const trackedChangeMatch = trimmed.match(TRACKED_CHANGE_RE);
|
|
14908
|
+
if (trackedChangeMatch) {
|
|
14909
|
+
return {
|
|
14910
|
+
kind: "trackedChange",
|
|
14911
|
+
trackedChangeId: `tc${trackedChangeMatch[1]}`
|
|
14912
|
+
};
|
|
14913
|
+
}
|
|
14478
14914
|
const cellMatch = trimmed.match(CELL_RE);
|
|
14479
14915
|
if (cellMatch) {
|
|
14480
14916
|
const [, tableIndex, rowIndex, columnIndex, rest] = cellMatch;
|
|
@@ -14523,7 +14959,7 @@ function validateOffsets(input, start, end, crossBlock) {
|
|
|
14523
14959
|
throw new LocatorParseError(input, "end offset precedes start");
|
|
14524
14960
|
}
|
|
14525
14961
|
}
|
|
14526
|
-
var LocatorParseError, BLOCK_RE, SPAN_RE, RANGE_RE, COMMENT_RE, IMAGE_RE, LINK_RE, CELL_RE;
|
|
14962
|
+
var LocatorParseError, BLOCK_RE, SPAN_RE, RANGE_RE, COMMENT_RE, IMAGE_RE, LINK_RE, TRACKED_CHANGE_RE, CELL_RE;
|
|
14527
14963
|
var init_parse = __esm(() => {
|
|
14528
14964
|
LocatorParseError = class LocatorParseError extends Error {
|
|
14529
14965
|
input;
|
|
@@ -14539,6 +14975,7 @@ var init_parse = __esm(() => {
|
|
|
14539
14975
|
COMMENT_RE = /^c(\d+)$/;
|
|
14540
14976
|
IMAGE_RE = /^img(\d+)$/;
|
|
14541
14977
|
LINK_RE = /^link(\d+)$/;
|
|
14978
|
+
TRACKED_CHANGE_RE = /^tc(\d+)$/;
|
|
14542
14979
|
CELL_RE = /^t(\d+):r(\d+)c(\d+)(?::(.+))?$/;
|
|
14543
14980
|
});
|
|
14544
14981
|
|
|
@@ -14645,8 +15082,6 @@ function resolveAuthor(authorFlag) {
|
|
|
14645
15082
|
return authorFlag;
|
|
14646
15083
|
if (Bun.env.DOCX_AUTHOR)
|
|
14647
15084
|
return Bun.env.DOCX_AUTHOR;
|
|
14648
|
-
if (Bun.env.DOCX_CLI_AUTHOR)
|
|
14649
|
-
return Bun.env.DOCX_CLI_AUTHOR;
|
|
14650
15085
|
return "docx-cli";
|
|
14651
15086
|
}
|
|
14652
15087
|
function resolveDate() {
|
|
@@ -14660,7 +15095,7 @@ function convertTextToDelText(node) {
|
|
|
14660
15095
|
function computeMaxRevisionId(view) {
|
|
14661
15096
|
let max = -1;
|
|
14662
15097
|
walkXml(view.documentTree, (node) => {
|
|
14663
|
-
if (node.tag !== "w:ins" && node.tag !== "w:del")
|
|
15098
|
+
if (node.tag !== "w:ins" && node.tag !== "w:del" && node.tag !== "w:moveFrom" && node.tag !== "w:moveTo")
|
|
14664
15099
|
return;
|
|
14665
15100
|
const idAttr = node.getAttribute("w:id");
|
|
14666
15101
|
if (!idAttr)
|
|
@@ -14948,6 +15383,7 @@ function exitCodeFor(code) {
|
|
|
14948
15383
|
case "COMMENT_NOT_FOUND":
|
|
14949
15384
|
case "IMAGE_NOT_FOUND":
|
|
14950
15385
|
case "HYPERLINK_NOT_FOUND":
|
|
15386
|
+
case "TRACKED_CHANGE_NOT_FOUND":
|
|
14951
15387
|
case "MATCH_NOT_FOUND":
|
|
14952
15388
|
return EXIT.NOT_FOUND;
|
|
14953
15389
|
case "NOT_A_ZIP":
|
|
@@ -15067,18 +15503,7 @@ function ensureCommentsExtPart(view) {
|
|
|
15067
15503
|
return root;
|
|
15068
15504
|
}
|
|
15069
15505
|
function paragraphTextLength(paragraph) {
|
|
15070
|
-
|
|
15071
|
-
for (const child of paragraph.children) {
|
|
15072
|
-
if (child.tag === "w:r")
|
|
15073
|
-
total += runTextLength(child);
|
|
15074
|
-
else if (child.tag === "w:ins" || child.tag === "w:del") {
|
|
15075
|
-
for (const inner of child.children) {
|
|
15076
|
-
if (inner.tag === "w:r")
|
|
15077
|
-
total += runTextLength(inner);
|
|
15078
|
-
}
|
|
15079
|
-
}
|
|
15080
|
-
}
|
|
15081
|
-
return total;
|
|
15506
|
+
return sumRunBearingTextLength(paragraph.children);
|
|
15082
15507
|
}
|
|
15083
15508
|
function addCommentMarkersToParagraph(paragraph, commentId, span) {
|
|
15084
15509
|
const total = paragraphTextLength(paragraph);
|
|
@@ -15114,6 +15539,97 @@ function addCommentRangeMarkers(startParagraph, startOffset, endParagraph, endOf
|
|
|
15114
15539
|
}
|
|
15115
15540
|
]);
|
|
15116
15541
|
}
|
|
15542
|
+
function addCommentMarkersAroundRun(paragraph, target, commentId) {
|
|
15543
|
+
function walk(parent) {
|
|
15544
|
+
const children = parent.children;
|
|
15545
|
+
for (let index = 0;index < children.length; index++) {
|
|
15546
|
+
const child = children[index];
|
|
15547
|
+
if (child === target) {
|
|
15548
|
+
children.splice(index, 1, commentRangeStartMarker(commentId), target, commentRangeEndMarker(commentId), commentReferenceRun(commentId));
|
|
15549
|
+
return true;
|
|
15550
|
+
}
|
|
15551
|
+
if (child && isRunBearingWrapper(child.tag)) {
|
|
15552
|
+
if (walk(child))
|
|
15553
|
+
return true;
|
|
15554
|
+
}
|
|
15555
|
+
}
|
|
15556
|
+
return false;
|
|
15557
|
+
}
|
|
15558
|
+
return walk(paragraph);
|
|
15559
|
+
}
|
|
15560
|
+
function findElementOffsetsInParagraph(paragraph, target) {
|
|
15561
|
+
let cursor = 0;
|
|
15562
|
+
let result = null;
|
|
15563
|
+
function walk(children) {
|
|
15564
|
+
for (const child of children) {
|
|
15565
|
+
if (child === target) {
|
|
15566
|
+
const start = cursor;
|
|
15567
|
+
cursor += sumRunBearingTextLength([child]);
|
|
15568
|
+
result = { start, end: cursor };
|
|
15569
|
+
return true;
|
|
15570
|
+
}
|
|
15571
|
+
if (child.tag === "w:r") {
|
|
15572
|
+
cursor += runTextLength(child);
|
|
15573
|
+
continue;
|
|
15574
|
+
}
|
|
15575
|
+
if (isRunBearingWrapper(child.tag)) {
|
|
15576
|
+
if (walk(child.children))
|
|
15577
|
+
return true;
|
|
15578
|
+
}
|
|
15579
|
+
}
|
|
15580
|
+
return false;
|
|
15581
|
+
}
|
|
15582
|
+
walk(paragraph.children);
|
|
15583
|
+
return result;
|
|
15584
|
+
}
|
|
15585
|
+
function findContainingParagraph(documentTree, target) {
|
|
15586
|
+
function walk(node) {
|
|
15587
|
+
if (node.tag === "w:p" && containsNode(node, target))
|
|
15588
|
+
return node;
|
|
15589
|
+
for (const child of node.children) {
|
|
15590
|
+
const found = walk(child);
|
|
15591
|
+
if (found)
|
|
15592
|
+
return found;
|
|
15593
|
+
}
|
|
15594
|
+
return null;
|
|
15595
|
+
}
|
|
15596
|
+
for (const root of documentTree) {
|
|
15597
|
+
const found = walk(root);
|
|
15598
|
+
if (found)
|
|
15599
|
+
return found;
|
|
15600
|
+
}
|
|
15601
|
+
return null;
|
|
15602
|
+
}
|
|
15603
|
+
function containsNode(haystack, needle) {
|
|
15604
|
+
if (haystack === needle)
|
|
15605
|
+
return true;
|
|
15606
|
+
for (const child of haystack.children) {
|
|
15607
|
+
if (containsNode(child, needle))
|
|
15608
|
+
return true;
|
|
15609
|
+
}
|
|
15610
|
+
return false;
|
|
15611
|
+
}
|
|
15612
|
+
function emitAuditComment(view, anchor, options) {
|
|
15613
|
+
const numericId = nextCommentId(view);
|
|
15614
|
+
const paraId = generateParaId();
|
|
15615
|
+
if (anchor.kind === "span") {
|
|
15616
|
+
addCommentMarkersToParagraph(anchor.paragraph, numericId, anchor.span);
|
|
15617
|
+
} else {
|
|
15618
|
+
addCommentMarkersAroundRun(anchor.paragraph, anchor.run, numericId);
|
|
15619
|
+
}
|
|
15620
|
+
const commentsRoot = ensureCommentsPart(view);
|
|
15621
|
+
commentsRoot.children.push(/* @__PURE__ */ jsxDEV(CommentBody, {
|
|
15622
|
+
options: {
|
|
15623
|
+
id: numericId,
|
|
15624
|
+
author: options.author,
|
|
15625
|
+
date: options.date,
|
|
15626
|
+
initials: authorInitials(options.author),
|
|
15627
|
+
paraId,
|
|
15628
|
+
text: options.body
|
|
15629
|
+
}
|
|
15630
|
+
}, undefined, false, undefined, this));
|
|
15631
|
+
return numericId;
|
|
15632
|
+
}
|
|
15117
15633
|
function commentRangeStartMarker(commentId) {
|
|
15118
15634
|
return /* @__PURE__ */ jsxDEV(w.commentRangeStart, {
|
|
15119
15635
|
"w-id": commentId
|
|
@@ -15149,13 +15665,13 @@ function placeMarkersInParagraph(paragraph, markers) {
|
|
|
15149
15665
|
}
|
|
15150
15666
|
const pending = markers.slice();
|
|
15151
15667
|
const state = { offset: 0, placedCount: 0 };
|
|
15152
|
-
paragraph.children = walkAndPlace(paragraph.children, pending,
|
|
15668
|
+
paragraph.children = walkAndPlace(paragraph.children, pending, state);
|
|
15153
15669
|
flushAtCurrentOffset(paragraph.children, pending, state);
|
|
15154
15670
|
if (state.placedCount !== markers.length) {
|
|
15155
15671
|
throw new SpanOutOfRangeError(`Could not place comment markers (placed ${state.placedCount} of ${markers.length})`);
|
|
15156
15672
|
}
|
|
15157
15673
|
}
|
|
15158
|
-
function walkAndPlace(children, pending,
|
|
15674
|
+
function walkAndPlace(children, pending, state) {
|
|
15159
15675
|
const result = [];
|
|
15160
15676
|
for (const child of children) {
|
|
15161
15677
|
if (child.tag === "w:r") {
|
|
@@ -15197,9 +15713,9 @@ function walkAndPlace(children, pending, isParagraphLevel, state) {
|
|
|
15197
15713
|
state.offset = runEnd;
|
|
15198
15714
|
continue;
|
|
15199
15715
|
}
|
|
15200
|
-
if (
|
|
15716
|
+
if (isRunBearingWrapper(child.tag)) {
|
|
15201
15717
|
flushAtCurrentOffset(result, pending, state);
|
|
15202
|
-
const innerChildren = walkAndPlace(child.children, pending,
|
|
15718
|
+
const innerChildren = walkAndPlace(child.children, pending, state);
|
|
15203
15719
|
const wrapper = new XmlNode2(child.tag, { ...child.attributes });
|
|
15204
15720
|
wrapper.children = innerChildren;
|
|
15205
15721
|
result.push(wrapper);
|
|
@@ -16174,6 +16690,7 @@ async function run8(args) {
|
|
|
16174
16690
|
allowPositionals: true,
|
|
16175
16691
|
options: {
|
|
16176
16692
|
at: { type: "string" },
|
|
16693
|
+
author: { type: "string" },
|
|
16177
16694
|
output: { type: "string", short: "o" },
|
|
16178
16695
|
"dry-run": { type: "boolean" },
|
|
16179
16696
|
help: { type: "boolean", short: "h" }
|
|
@@ -16219,7 +16736,7 @@ async function run8(args) {
|
|
|
16219
16736
|
if (blockRef.node.tag !== "w:p") {
|
|
16220
16737
|
return fail("TRACKED_CHANGE_CONFLICT", "Tracked deletion of non-paragraph blocks (e.g., tables) is not supported", "Use `docx track-changes off` first, or delete table contents row-by-row.");
|
|
16221
16738
|
}
|
|
16222
|
-
applyTrackedDeletion(view, blockRef.node);
|
|
16739
|
+
applyTrackedDeletion(view, blockRef.node, parsed.values.author);
|
|
16223
16740
|
} else {
|
|
16224
16741
|
blockRef.parent.splice(targetIndex, 1);
|
|
16225
16742
|
}
|
|
@@ -16232,9 +16749,9 @@ async function run8(args) {
|
|
|
16232
16749
|
});
|
|
16233
16750
|
return EXIT.OK;
|
|
16234
16751
|
}
|
|
16235
|
-
function applyTrackedDeletion(view, paragraph) {
|
|
16752
|
+
function applyTrackedDeletion(view, paragraph, authorFlag) {
|
|
16236
16753
|
const allocator = createRevisionAllocator(view);
|
|
16237
|
-
const baseMeta = { author: resolveAuthor(), date: resolveDate() };
|
|
16754
|
+
const baseMeta = { author: resolveAuthor(authorFlag), date: resolveDate() };
|
|
16238
16755
|
const mintMeta = () => ({
|
|
16239
16756
|
...baseMeta,
|
|
16240
16757
|
revisionId: allocator.next()
|
|
@@ -16271,6 +16788,7 @@ Usage:
|
|
|
16271
16788
|
Locator (required):
|
|
16272
16789
|
--at LOCATOR Block to remove (e.g., p3, t0)
|
|
16273
16790
|
|
|
16791
|
+
--author NAME Author for tracked changes (default: $DOCX_AUTHOR)
|
|
16274
16792
|
-o, --output PATH Write to PATH instead of overwriting FILE
|
|
16275
16793
|
--dry-run Print what would be removed; do not write the file
|
|
16276
16794
|
-h, --help Show this help
|
|
@@ -16423,6 +16941,7 @@ async function run9(args) {
|
|
|
16423
16941
|
color: { type: "string" },
|
|
16424
16942
|
bold: { type: "boolean" },
|
|
16425
16943
|
italic: { type: "boolean" },
|
|
16944
|
+
author: { type: "string" },
|
|
16426
16945
|
output: { type: "string", short: "o" },
|
|
16427
16946
|
"dry-run": { type: "boolean" },
|
|
16428
16947
|
help: { type: "boolean", short: "h" }
|
|
@@ -16510,7 +17029,7 @@ async function run9(args) {
|
|
|
16510
17029
|
return EXIT.OK;
|
|
16511
17030
|
}
|
|
16512
17031
|
if (isTrackChangesEnabled(view)) {
|
|
16513
|
-
applyTrackedEdit(view, blockRef.node, paragraphNode);
|
|
17032
|
+
applyTrackedEdit(view, blockRef.node, paragraphNode, parsed.values.author);
|
|
16514
17033
|
} else {
|
|
16515
17034
|
blockRef.parent.splice(targetIndex, 1, paragraphNode);
|
|
16516
17035
|
}
|
|
@@ -16523,9 +17042,9 @@ async function run9(args) {
|
|
|
16523
17042
|
});
|
|
16524
17043
|
return EXIT.OK;
|
|
16525
17044
|
}
|
|
16526
|
-
function applyTrackedEdit(view, existingParagraph, newParagraph) {
|
|
17045
|
+
function applyTrackedEdit(view, existingParagraph, newParagraph, authorFlag) {
|
|
16527
17046
|
const allocator = createRevisionAllocator(view);
|
|
16528
|
-
const baseMeta = { author: resolveAuthor(), date: resolveDate() };
|
|
17047
|
+
const baseMeta = { author: resolveAuthor(authorFlag), date: resolveDate() };
|
|
16529
17048
|
const mintMeta = () => ({
|
|
16530
17049
|
...baseMeta,
|
|
16531
17050
|
revisionId: allocator.next()
|
|
@@ -16592,6 +17111,7 @@ Run options (only with --text):
|
|
|
16592
17111
|
--bold Bold
|
|
16593
17112
|
--italic Italic
|
|
16594
17113
|
|
|
17114
|
+
--author NAME Author for tracked changes (default: $DOCX_AUTHOR)
|
|
16595
17115
|
-o, --output PATH Write to PATH instead of overwriting FILE
|
|
16596
17116
|
--dry-run Print what would change; do not write the file
|
|
16597
17117
|
-h, --help Show this help
|
|
@@ -16701,10 +17221,9 @@ function trackedChangesOverlapping(paragraph, start, end) {
|
|
|
16701
17221
|
const change = run10.trackedChange;
|
|
16702
17222
|
if (!change)
|
|
16703
17223
|
continue;
|
|
16704
|
-
|
|
16705
|
-
if (seen.has(key))
|
|
17224
|
+
if (seen.has(change.id))
|
|
16706
17225
|
continue;
|
|
16707
|
-
seen.add(
|
|
17226
|
+
seen.add(change.id);
|
|
16708
17227
|
out.push(change);
|
|
16709
17228
|
}
|
|
16710
17229
|
return out;
|
|
@@ -16862,20 +17381,8 @@ function wrapSpanInHyperlink(paragraph, span, relationshipId) {
|
|
|
16862
17381
|
}
|
|
16863
17382
|
continue;
|
|
16864
17383
|
}
|
|
16865
|
-
if (child.tag
|
|
16866
|
-
const
|
|
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);
|
|
17384
|
+
if (isRunBearingWrapper(child.tag)) {
|
|
17385
|
+
const innerLength = sumRunBearingTextLength(child.children);
|
|
16879
17386
|
const wrapperStart = offset;
|
|
16880
17387
|
const wrapperEnd = offset + innerLength;
|
|
16881
17388
|
offset = wrapperEnd;
|
|
@@ -16884,27 +17391,28 @@ function wrapSpanInHyperlink(paragraph, span, relationshipId) {
|
|
|
16884
17391
|
newChildren.push(child);
|
|
16885
17392
|
continue;
|
|
16886
17393
|
}
|
|
16887
|
-
throw new HyperlinkWrapError(
|
|
17394
|
+
throw new HyperlinkWrapError(messageForOverlap(child.tag, span));
|
|
16888
17395
|
}
|
|
16889
17396
|
newChildren.push(child);
|
|
16890
17397
|
}
|
|
16891
17398
|
placeWrapper();
|
|
16892
17399
|
paragraph.children = newChildren;
|
|
16893
17400
|
}
|
|
17401
|
+
function messageForOverlap(tag, span) {
|
|
17402
|
+
if (tag === "w:hyperlink") {
|
|
17403
|
+
return `Span ${span.start}-${span.end} overlaps an existing hyperlink; nested hyperlinks are not allowed`;
|
|
17404
|
+
}
|
|
17405
|
+
if (tag === "w:ins" || tag === "w:del" || tag === "w:moveFrom" || tag === "w:moveTo") {
|
|
17406
|
+
return `Span ${span.start}-${span.end} crosses a tracked-change wrapper (${tag}); resolve or accept the change first`;
|
|
17407
|
+
}
|
|
17408
|
+
return `Span ${span.start}-${span.end} crosses a ${tag} wrapper; cannot wrap a hyperlink across it`;
|
|
17409
|
+
}
|
|
16894
17410
|
function hyperlinkWrapper(relationshipId, runs) {
|
|
16895
17411
|
return /* @__PURE__ */ jsxDEV(w.hyperlink, {
|
|
16896
17412
|
"r:id": relationshipId,
|
|
16897
17413
|
children: runs
|
|
16898
17414
|
}, undefined, false, undefined, this);
|
|
16899
17415
|
}
|
|
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
17416
|
var HyperlinkWrapError;
|
|
16909
17417
|
var init_wrap = __esm(() => {
|
|
16910
17418
|
init_jsx();
|
|
@@ -16933,6 +17441,7 @@ async function run11(args) {
|
|
|
16933
17441
|
options: {
|
|
16934
17442
|
at: { type: "string" },
|
|
16935
17443
|
url: { type: "string" },
|
|
17444
|
+
author: { type: "string" },
|
|
16936
17445
|
output: { type: "string", short: "o" },
|
|
16937
17446
|
"dry-run": { type: "boolean" },
|
|
16938
17447
|
help: { type: "boolean", short: "h" }
|
|
@@ -17001,6 +17510,13 @@ async function run11(args) {
|
|
|
17001
17510
|
throw error;
|
|
17002
17511
|
}
|
|
17003
17512
|
view.hyperlinksByRelationshipId.set(relationshipId, { url });
|
|
17513
|
+
if (isTrackChangesEnabled(view)) {
|
|
17514
|
+
emitAuditComment(view, { kind: "span", paragraph: paragraphRef.node, span: target.span }, {
|
|
17515
|
+
body: `[docx-cli] hyperlink added \u2192 ${url}`,
|
|
17516
|
+
author: resolveAuthor(parsed.values.author),
|
|
17517
|
+
date: resolveDate()
|
|
17518
|
+
});
|
|
17519
|
+
}
|
|
17004
17520
|
await saveDocView(view, outputPath);
|
|
17005
17521
|
await respond({
|
|
17006
17522
|
ok: true,
|
|
@@ -17023,12 +17539,19 @@ Required:
|
|
|
17023
17539
|
--url URL Target URL
|
|
17024
17540
|
|
|
17025
17541
|
Optional:
|
|
17542
|
+
--author NAME Author for the audit comment when track-changes is on
|
|
17543
|
+
(default: $DOCX_AUTHOR)
|
|
17026
17544
|
-o, --output PATH Write to PATH instead of overwriting FILE
|
|
17027
17545
|
--dry-run Print what would change; do not write the file
|
|
17028
17546
|
-h, --help Show this help
|
|
17029
17547
|
|
|
17030
17548
|
The span must lie inside a single paragraph and must not overlap an existing
|
|
17031
|
-
hyperlink
|
|
17549
|
+
hyperlink, a tracked-change wrapper (<w:ins>/<w:del>/<w:moveFrom>/<w:moveTo>),
|
|
17550
|
+
or any other run-bearing wrapper that we model. Resolve or accept the
|
|
17551
|
+
wrapper first, then add the hyperlink.
|
|
17552
|
+
|
|
17553
|
+
When track-changes is on, an audit comment is anchored to the wrapped span
|
|
17554
|
+
since OOXML has no native tracked-change form for hyperlink edits.
|
|
17032
17555
|
|
|
17033
17556
|
Examples:
|
|
17034
17557
|
docx hyperlinks add doc.docx --at p3:5-20 --url https://example.com
|
|
@@ -17036,6 +17559,7 @@ Examples:
|
|
|
17036
17559
|
var init_add2 = __esm(() => {
|
|
17037
17560
|
init_core();
|
|
17038
17561
|
init_parser();
|
|
17562
|
+
init_helpers();
|
|
17039
17563
|
init_respond();
|
|
17040
17564
|
init_wrap();
|
|
17041
17565
|
});
|
|
@@ -17054,6 +17578,7 @@ async function run12(args) {
|
|
|
17054
17578
|
allowPositionals: true,
|
|
17055
17579
|
options: {
|
|
17056
17580
|
at: { type: "string" },
|
|
17581
|
+
author: { type: "string" },
|
|
17057
17582
|
output: { type: "string", short: "o" },
|
|
17058
17583
|
"dry-run": { type: "boolean" },
|
|
17059
17584
|
help: { type: "boolean", short: "h" }
|
|
@@ -17098,6 +17623,9 @@ async function run12(args) {
|
|
|
17098
17623
|
if (index === -1) {
|
|
17099
17624
|
return fail("HYPERLINK_NOT_FOUND", `Hyperlink reference is stale (parent does not contain it): ${targetId}`);
|
|
17100
17625
|
}
|
|
17626
|
+
const trackingOn = isTrackChangesEnabled(view);
|
|
17627
|
+
const paragraph = trackingOn ? findContainingParagraph(view.documentTree, reference.node) : null;
|
|
17628
|
+
const offsets = trackingOn && paragraph ? findElementOffsetsInParagraph(paragraph, reference.node) : null;
|
|
17101
17629
|
reference.parent.splice(index, 1, ...reference.node.children);
|
|
17102
17630
|
view.hyperlinkById.delete(targetId);
|
|
17103
17631
|
if (reference.relationshipId) {
|
|
@@ -17107,6 +17635,13 @@ async function run12(args) {
|
|
|
17107
17635
|
view.hyperlinksByRelationshipId.delete(reference.relationshipId);
|
|
17108
17636
|
}
|
|
17109
17637
|
}
|
|
17638
|
+
if (trackingOn && paragraph && offsets) {
|
|
17639
|
+
emitAuditComment(view, { kind: "span", paragraph, span: offsets }, {
|
|
17640
|
+
body: `[docx-cli] hyperlink removed (was: ${oldUrl ?? "(none)"})`,
|
|
17641
|
+
author: resolveAuthor(parsed.values.author),
|
|
17642
|
+
date: resolveDate()
|
|
17643
|
+
});
|
|
17644
|
+
}
|
|
17110
17645
|
await saveDocView(view, outputPath);
|
|
17111
17646
|
await respond({
|
|
17112
17647
|
ok: true,
|
|
@@ -17149,6 +17684,8 @@ Required:
|
|
|
17149
17684
|
--at LINK_ID Existing hyperlink to remove (e.g., link0)
|
|
17150
17685
|
|
|
17151
17686
|
Optional:
|
|
17687
|
+
--author NAME Author for the audit comment when track-changes is on
|
|
17688
|
+
(default: $DOCX_AUTHOR)
|
|
17152
17689
|
-o, --output PATH Write to PATH instead of overwriting FILE
|
|
17153
17690
|
--dry-run Print what would change; do not write the file
|
|
17154
17691
|
-h, --help Show this help
|
|
@@ -17157,12 +17694,16 @@ The display text stays in place; only the <w:hyperlink> wrapper is removed.
|
|
|
17157
17694
|
If the underlying relationship is no longer referenced, it is pruned from the
|
|
17158
17695
|
rels file too.
|
|
17159
17696
|
|
|
17697
|
+
When track-changes is on, an audit comment is anchored to the surviving text
|
|
17698
|
+
since OOXML has no native tracked-change form for hyperlink removal.
|
|
17699
|
+
|
|
17160
17700
|
Examples:
|
|
17161
17701
|
docx hyperlinks delete doc.docx --at link0
|
|
17162
17702
|
`;
|
|
17163
17703
|
var init_delete3 = __esm(() => {
|
|
17164
17704
|
init_core();
|
|
17165
17705
|
init_parser();
|
|
17706
|
+
init_helpers();
|
|
17166
17707
|
init_respond();
|
|
17167
17708
|
});
|
|
17168
17709
|
|
|
@@ -17272,6 +17813,7 @@ async function run14(args) {
|
|
|
17272
17813
|
options: {
|
|
17273
17814
|
at: { type: "string" },
|
|
17274
17815
|
with: { type: "string" },
|
|
17816
|
+
author: { type: "string" },
|
|
17275
17817
|
output: { type: "string", short: "o" },
|
|
17276
17818
|
"dry-run": { type: "boolean" },
|
|
17277
17819
|
help: { type: "boolean", short: "h" }
|
|
@@ -17333,6 +17875,17 @@ async function run14(args) {
|
|
|
17333
17875
|
updateRelationshipTarget(relationships, existingId, newUrl);
|
|
17334
17876
|
view.hyperlinksByRelationshipId.set(existingId, { url: newUrl });
|
|
17335
17877
|
}
|
|
17878
|
+
if (isTrackChangesEnabled(view)) {
|
|
17879
|
+
const paragraph = findContainingParagraph(view.documentTree, reference.node);
|
|
17880
|
+
const offsets = paragraph ? findElementOffsetsInParagraph(paragraph, reference.node) : null;
|
|
17881
|
+
if (paragraph && offsets) {
|
|
17882
|
+
emitAuditComment(view, { kind: "span", paragraph, span: offsets }, {
|
|
17883
|
+
body: `[docx-cli] hyperlink target changed: ${oldUrl ?? "(none)"} \u2192 ${newUrl}`,
|
|
17884
|
+
author: resolveAuthor(parsed.values.author),
|
|
17885
|
+
date: resolveDate()
|
|
17886
|
+
});
|
|
17887
|
+
}
|
|
17888
|
+
}
|
|
17336
17889
|
await saveDocView(view, outputPath);
|
|
17337
17890
|
await respond({
|
|
17338
17891
|
ok: true,
|
|
@@ -17381,6 +17934,8 @@ Required:
|
|
|
17381
17934
|
--with URL New target URL
|
|
17382
17935
|
|
|
17383
17936
|
Optional:
|
|
17937
|
+
--author NAME Author for the audit comment when track-changes is on
|
|
17938
|
+
(default: $DOCX_AUTHOR)
|
|
17384
17939
|
-o, --output PATH Write to PATH instead of overwriting FILE
|
|
17385
17940
|
--dry-run Print what would change; do not write the file
|
|
17386
17941
|
-h, --help Show this help
|
|
@@ -17389,12 +17944,17 @@ Replaces only the targeted hyperlink. If multiple hyperlinks shared the same
|
|
|
17389
17944
|
underlying relationship, a new relationship is allocated so the others are
|
|
17390
17945
|
unaffected.
|
|
17391
17946
|
|
|
17947
|
+
When track-changes is on, an audit comment is anchored to the affected
|
|
17948
|
+
hyperlink span since OOXML has no native tracked-change form for hyperlink
|
|
17949
|
+
target edits.
|
|
17950
|
+
|
|
17392
17951
|
Examples:
|
|
17393
17952
|
docx hyperlinks replace doc.docx --at link0 --with https://example.com
|
|
17394
17953
|
`;
|
|
17395
17954
|
var init_replace = __esm(() => {
|
|
17396
17955
|
init_core();
|
|
17397
17956
|
init_parser();
|
|
17957
|
+
init_helpers();
|
|
17398
17958
|
init_respond();
|
|
17399
17959
|
});
|
|
17400
17960
|
|
|
@@ -17654,6 +18214,7 @@ async function run18(args) {
|
|
|
17654
18214
|
options: {
|
|
17655
18215
|
at: { type: "string" },
|
|
17656
18216
|
with: { type: "string" },
|
|
18217
|
+
author: { type: "string" },
|
|
17657
18218
|
output: { type: "string", short: "o" },
|
|
17658
18219
|
"dry-run": { type: "boolean" },
|
|
17659
18220
|
help: { type: "boolean", short: "h" }
|
|
@@ -17709,6 +18270,7 @@ async function run18(args) {
|
|
|
17709
18270
|
return EXIT.OK;
|
|
17710
18271
|
}
|
|
17711
18272
|
const bytes = new Uint8Array(await sourceFile.arrayBuffer());
|
|
18273
|
+
const originalMimeType = reference.contentType;
|
|
17712
18274
|
if (newPartName === originalPartName) {
|
|
17713
18275
|
view.pkg.writeBytes(originalPartName, bytes);
|
|
17714
18276
|
} else {
|
|
@@ -17719,6 +18281,18 @@ async function run18(args) {
|
|
|
17719
18281
|
reference.partName = newPartName;
|
|
17720
18282
|
reference.contentType = newMimeType;
|
|
17721
18283
|
}
|
|
18284
|
+
if (isTrackChangesEnabled(view)) {
|
|
18285
|
+
const author = resolveAuthor(parsed.values.author);
|
|
18286
|
+
const date = resolveDate();
|
|
18287
|
+
const body = `[docx-cli] image replaced: ${originalPartName} (${originalMimeType}) \u2192 ${newPartName} (${newMimeType}, ${bytes.length} bytes)`;
|
|
18288
|
+
const drawingRuns = findDrawingRunsForRelationship(view.documentTree, reference.relationshipId);
|
|
18289
|
+
for (const drawingRun of drawingRuns) {
|
|
18290
|
+
const paragraph = findContainingParagraph(view.documentTree, drawingRun);
|
|
18291
|
+
if (!paragraph)
|
|
18292
|
+
continue;
|
|
18293
|
+
emitAuditComment(view, { kind: "run", paragraph, run: drawingRun }, { body, author, date });
|
|
18294
|
+
}
|
|
18295
|
+
}
|
|
17722
18296
|
await saveDocView(view, outputPath);
|
|
17723
18297
|
await respond({
|
|
17724
18298
|
ok: true,
|
|
@@ -17731,6 +18305,33 @@ async function run18(args) {
|
|
|
17731
18305
|
});
|
|
17732
18306
|
return EXIT.OK;
|
|
17733
18307
|
}
|
|
18308
|
+
function findDrawingRunsForRelationship(documentTree, relationshipId) {
|
|
18309
|
+
const matches = [];
|
|
18310
|
+
function walk(node) {
|
|
18311
|
+
if (node.tag === "w:r" && runReferencesImage(node, relationshipId)) {
|
|
18312
|
+
matches.push(node);
|
|
18313
|
+
return;
|
|
18314
|
+
}
|
|
18315
|
+
for (const child of node.children)
|
|
18316
|
+
walk(child);
|
|
18317
|
+
}
|
|
18318
|
+
for (const root of documentTree)
|
|
18319
|
+
walk(root);
|
|
18320
|
+
return matches;
|
|
18321
|
+
}
|
|
18322
|
+
function runReferencesImage(run19, relationshipId) {
|
|
18323
|
+
for (const child of run19.children) {
|
|
18324
|
+
if (child.tag !== "w:drawing")
|
|
18325
|
+
continue;
|
|
18326
|
+
const blip = child.findDescendant("a:blip");
|
|
18327
|
+
if (!blip)
|
|
18328
|
+
continue;
|
|
18329
|
+
const embed = blip.getAttribute("r:embed") ?? blip.getAttribute("r:link");
|
|
18330
|
+
if (embed === relationshipId)
|
|
18331
|
+
return true;
|
|
18332
|
+
}
|
|
18333
|
+
return false;
|
|
18334
|
+
}
|
|
17734
18335
|
function renameExtension(partName, newExtension) {
|
|
17735
18336
|
const dotIndex = partName.lastIndexOf(".");
|
|
17736
18337
|
const slashIndex = partName.lastIndexOf("/");
|
|
@@ -17777,6 +18378,8 @@ Required:
|
|
|
17777
18378
|
--with PATH New image file (any image MIME type)
|
|
17778
18379
|
|
|
17779
18380
|
Optional:
|
|
18381
|
+
--author NAME Author for the audit comment when track-changes is on
|
|
18382
|
+
(default: $DOCX_AUTHOR)
|
|
17780
18383
|
-o, --output PATH Write to PATH instead of overwriting FILE
|
|
17781
18384
|
--dry-run Print what would change; do not write the file
|
|
17782
18385
|
-h, --help Show this help
|
|
@@ -17785,6 +18388,10 @@ If the replacement uses a different format from the original, the part is
|
|
|
17785
18388
|
renamed (extension changes), the relationship Target is rewritten, and
|
|
17786
18389
|
[Content_Types].xml gets a Default entry for the new extension if needed.
|
|
17787
18390
|
|
|
18391
|
+
When track-changes is on, an audit comment is anchored to each drawing that
|
|
18392
|
+
referenced the swapped image since OOXML has no native tracked-change form
|
|
18393
|
+
for image replacement.
|
|
18394
|
+
|
|
17788
18395
|
Examples:
|
|
17789
18396
|
docx images replace doc.docx --at img2 --with ./new-photo.png
|
|
17790
18397
|
docx images replace doc.docx --at img0 --with ./diagram.svg
|
|
@@ -17792,6 +18399,7 @@ Examples:
|
|
|
17792
18399
|
var init_replace2 = __esm(() => {
|
|
17793
18400
|
init_core();
|
|
17794
18401
|
init_parser();
|
|
18402
|
+
init_helpers();
|
|
17795
18403
|
init_respond();
|
|
17796
18404
|
EXTENSION_BY_MIME = {
|
|
17797
18405
|
"image/png": "png",
|
|
@@ -17977,12 +18585,22 @@ export type Footnote = {
|
|
|
17977
18585
|
};
|
|
17978
18586
|
|
|
17979
18587
|
export type TrackedChange = {
|
|
17980
|
-
|
|
18588
|
+
id: string;
|
|
18589
|
+
kind: TrackedChangeKind;
|
|
17981
18590
|
author: string;
|
|
17982
18591
|
date: string;
|
|
17983
18592
|
revisionId: string;
|
|
17984
18593
|
};
|
|
17985
18594
|
|
|
18595
|
+
/** OOXML revision-tracking wrappers we surface in the AST.
|
|
18596
|
+
* - \`ins\` / \`del\`: <w:ins> / <w:del> \u2014 inserted / deleted runs.
|
|
18597
|
+
* - \`moveFrom\` / \`moveTo\`: <w:moveFrom> / <w:moveTo> \u2014 origin / destination
|
|
18598
|
+
* of a tracked move. moveFrom behaves like a delete (text leaves this
|
|
18599
|
+
* location, stored as <w:delText> internally); moveTo behaves like an
|
|
18600
|
+
* insert (text arrives at this location).
|
|
18601
|
+
*/
|
|
18602
|
+
export type TrackedChangeKind = "ins" | "del" | "moveFrom" | "moveTo";
|
|
18603
|
+
|
|
17986
18604
|
export type Comment = {
|
|
17987
18605
|
id: string;
|
|
17988
18606
|
author: string;
|
|
@@ -18036,10 +18654,10 @@ async function run20(args) {
|
|
|
18036
18654
|
await respond(JSON_SCHEMA);
|
|
18037
18655
|
return EXIT.OK;
|
|
18038
18656
|
}
|
|
18039
|
-
var HELP20 = `docx schema \u2014 print the AST type definitions
|
|
18657
|
+
var HELP20 = `docx info schema \u2014 print the AST type definitions
|
|
18040
18658
|
|
|
18041
18659
|
Usage:
|
|
18042
|
-
docx schema [options]
|
|
18660
|
+
docx info schema [options]
|
|
18043
18661
|
|
|
18044
18662
|
Options:
|
|
18045
18663
|
--json Print as a JSON Schema document (default)
|
|
@@ -18047,8 +18665,8 @@ Options:
|
|
|
18047
18665
|
-h, --help Show this help
|
|
18048
18666
|
|
|
18049
18667
|
Examples:
|
|
18050
|
-
docx schema | jq '.
|
|
18051
|
-
docx schema --ts > ast.d.ts
|
|
18668
|
+
docx info schema | jq '.$defs.Run'
|
|
18669
|
+
docx info schema --ts > ast.d.ts
|
|
18052
18670
|
`, JSON_SCHEMA;
|
|
18053
18671
|
var init_schema = __esm(() => {
|
|
18054
18672
|
init_types();
|
|
@@ -18139,9 +18757,10 @@ var init_schema = __esm(() => {
|
|
|
18139
18757
|
comments: { type: "array", items: { type: "string" } },
|
|
18140
18758
|
trackedChange: {
|
|
18141
18759
|
type: "object",
|
|
18142
|
-
required: ["kind", "author", "date", "revisionId"],
|
|
18760
|
+
required: ["id", "kind", "author", "date", "revisionId"],
|
|
18143
18761
|
properties: {
|
|
18144
|
-
|
|
18762
|
+
id: { type: "string" },
|
|
18763
|
+
kind: { enum: ["ins", "del", "moveFrom", "moveTo"] },
|
|
18145
18764
|
author: { type: "string" },
|
|
18146
18765
|
date: { type: "string" },
|
|
18147
18766
|
revisionId: { type: "string" }
|
|
@@ -18316,14 +18935,18 @@ async function run21(args) {
|
|
|
18316
18935
|
await writeStdout(REFERENCE);
|
|
18317
18936
|
return EXIT.OK;
|
|
18318
18937
|
}
|
|
18319
|
-
var HELP21 = `docx locators \u2014 print the locator grammar reference
|
|
18938
|
+
var HELP21 = `docx info locators \u2014 print the locator grammar reference
|
|
18320
18939
|
|
|
18321
18940
|
Usage:
|
|
18322
|
-
docx locators [options]
|
|
18941
|
+
docx info locators [options]
|
|
18323
18942
|
|
|
18324
18943
|
Options:
|
|
18325
18944
|
--json Print as JSON
|
|
18326
18945
|
-h, --help Show this help
|
|
18946
|
+
|
|
18947
|
+
Examples:
|
|
18948
|
+
docx info locators
|
|
18949
|
+
docx info locators --json | jq '.entityLocators'
|
|
18327
18950
|
`, REFERENCE = `LOCATOR GRAMMAR
|
|
18328
18951
|
|
|
18329
18952
|
Block locators:
|
|
@@ -18343,6 +18966,8 @@ Entity locators:
|
|
|
18343
18966
|
cN Comment id (e.g., c0)
|
|
18344
18967
|
imgN Image id (e.g., img2)
|
|
18345
18968
|
linkN Hyperlink id (e.g., link0)
|
|
18969
|
+
tcN Tracked change id (e.g., tc0) \u2014 the Nth revision wrapper
|
|
18970
|
+
(<w:ins>/<w:del>/<w:moveFrom>/<w:moveTo>) in document order
|
|
18346
18971
|
tN:rRcC Cell at row R, column C of table tN
|
|
18347
18972
|
|
|
18348
18973
|
Examples:
|
|
@@ -18352,6 +18977,7 @@ Examples:
|
|
|
18352
18977
|
c1 -> comment c1
|
|
18353
18978
|
img0 -> image img0
|
|
18354
18979
|
link0 -> hyperlink link0
|
|
18980
|
+
tc0 -> first tracked change in the document
|
|
18355
18981
|
t0:r1c2 -> cell at row 1, col 2 of table t0
|
|
18356
18982
|
t0:r1c2:p0 -> first paragraph of that cell
|
|
18357
18983
|
t0:r1c2:p0:5-10 -> chars 5..10 of that paragraph
|
|
@@ -18385,6 +19011,7 @@ var init_locators2 = __esm(() => {
|
|
|
18385
19011
|
comment: { syntax: "cN", example: "c1" },
|
|
18386
19012
|
image: { syntax: "imgN", example: "img0" },
|
|
18387
19013
|
hyperlink: { syntax: "linkN", example: "link0" },
|
|
19014
|
+
trackedChange: { syntax: "tcN", example: "tc0" },
|
|
18388
19015
|
cell: { syntax: "tN:rRcC", example: "t0:r1c2" },
|
|
18389
19016
|
nestedCell: { syntax: "tN:rRcC:pK", example: "t0:r1c2:p0" }
|
|
18390
19017
|
},
|
|
@@ -18456,6 +19083,7 @@ async function run23(args) {
|
|
|
18456
19083
|
bold: { type: "boolean" },
|
|
18457
19084
|
italic: { type: "boolean" },
|
|
18458
19085
|
url: { type: "string" },
|
|
19086
|
+
author: { type: "string" },
|
|
18459
19087
|
output: { type: "string", short: "o" },
|
|
18460
19088
|
"dry-run": { type: "boolean" },
|
|
18461
19089
|
help: { type: "boolean", short: "h" }
|
|
@@ -18544,7 +19172,7 @@ async function run23(args) {
|
|
|
18544
19172
|
}
|
|
18545
19173
|
const insertIndex = after !== undefined ? targetIndex + 1 : targetIndex;
|
|
18546
19174
|
if (isTrackChangesEnabled(view)) {
|
|
18547
|
-
applyTrackedInsertion(paragraphNode, view);
|
|
19175
|
+
applyTrackedInsertion(paragraphNode, view, parsed.values.author);
|
|
18548
19176
|
}
|
|
18549
19177
|
const outputPath = parsed.values.output;
|
|
18550
19178
|
if (parsed.values["dry-run"]) {
|
|
@@ -18593,9 +19221,9 @@ function wrapFirstRunInHyperlink(view, paragraph, url) {
|
|
|
18593
19221
|
}
|
|
18594
19222
|
paragraph.children = newChildren;
|
|
18595
19223
|
}
|
|
18596
|
-
function applyTrackedInsertion(paragraph, view) {
|
|
19224
|
+
function applyTrackedInsertion(paragraph, view, authorFlag) {
|
|
18597
19225
|
const allocator = createRevisionAllocator(view);
|
|
18598
|
-
const baseMeta = { author: resolveAuthor(), date: resolveDate() };
|
|
19226
|
+
const baseMeta = { author: resolveAuthor(authorFlag), date: resolveDate() };
|
|
18599
19227
|
const mintMeta = () => ({
|
|
18600
19228
|
...baseMeta,
|
|
18601
19229
|
revisionId: allocator.next()
|
|
@@ -18646,6 +19274,7 @@ Run options (only with --text):
|
|
|
18646
19274
|
--italic Italic
|
|
18647
19275
|
--url URL Wrap the inserted text in a hyperlink to URL
|
|
18648
19276
|
|
|
19277
|
+
--author NAME Author for tracked changes (default: $DOCX_AUTHOR)
|
|
18649
19278
|
-o, --output PATH Write to PATH instead of overwriting FILE
|
|
18650
19279
|
--dry-run Print what would be inserted; do not write the file
|
|
18651
19280
|
-h, --help Show this help
|
|
@@ -18804,7 +19433,8 @@ function renderMarkdown(doc, options = {}) {
|
|
|
18804
19433
|
options,
|
|
18805
19434
|
commentIndex,
|
|
18806
19435
|
referencedFootnoteIds: new Set,
|
|
18807
|
-
referencedEndnoteIds: new Set
|
|
19436
|
+
referencedEndnoteIds: new Set,
|
|
19437
|
+
referencedTrackedChanges: new Map
|
|
18808
19438
|
};
|
|
18809
19439
|
const parts = [];
|
|
18810
19440
|
for (const block of blocks) {
|
|
@@ -18824,6 +19454,9 @@ function renderMarkdown(doc, options = {}) {
|
|
|
18824
19454
|
const endnoteDefs = renderNoteDefinitions(doc.endnotes, ctx.referencedEndnoteIds);
|
|
18825
19455
|
if (endnoteDefs.length > 0)
|
|
18826
19456
|
definitions.push(endnoteDefs);
|
|
19457
|
+
const trackedChangeDefs = renderTrackedChangeFootnotes(ctx.referencedTrackedChanges);
|
|
19458
|
+
if (trackedChangeDefs.length > 0)
|
|
19459
|
+
definitions.push(trackedChangeDefs);
|
|
18827
19460
|
if (definitions.length > 0)
|
|
18828
19461
|
parts.push(definitions.join(`
|
|
18829
19462
|
`));
|
|
@@ -18841,8 +19474,18 @@ function emptyCommentIndex() {
|
|
|
18841
19474
|
orderedIds: []
|
|
18842
19475
|
};
|
|
18843
19476
|
}
|
|
19477
|
+
function isRunVisible(run25, view) {
|
|
19478
|
+
const kind = run25.trackedChange?.kind;
|
|
19479
|
+
if (!kind)
|
|
19480
|
+
return true;
|
|
19481
|
+
if (view === "accepted" && (kind === "del" || kind === "moveFrom"))
|
|
19482
|
+
return false;
|
|
19483
|
+
if (view === "baseline" && (kind === "ins" || kind === "moveTo"))
|
|
19484
|
+
return false;
|
|
19485
|
+
return true;
|
|
19486
|
+
}
|
|
18844
19487
|
function buildCommentIndex(blocks, options) {
|
|
18845
|
-
const
|
|
19488
|
+
const view = options.view ?? "current";
|
|
18846
19489
|
const lastSlot = new Map;
|
|
18847
19490
|
const spanText = new Map;
|
|
18848
19491
|
const orderedIds = [];
|
|
@@ -18850,7 +19493,7 @@ function buildCommentIndex(blocks, options) {
|
|
|
18850
19493
|
paragraph.runs.forEach((run25, index) => {
|
|
18851
19494
|
if (run25.type !== "text")
|
|
18852
19495
|
return;
|
|
18853
|
-
if (!
|
|
19496
|
+
if (!isRunVisible(run25, view))
|
|
18854
19497
|
return;
|
|
18855
19498
|
for (const commentId of run25.comments ?? []) {
|
|
18856
19499
|
if (!spanText.has(commentId))
|
|
@@ -18914,12 +19557,11 @@ function headingLevelFor(style) {
|
|
|
18914
19557
|
return parsed;
|
|
18915
19558
|
}
|
|
18916
19559
|
function renderRuns(paragraphId, runs, ctx) {
|
|
18917
|
-
const
|
|
19560
|
+
const view = ctx.options.view ?? "current";
|
|
18918
19561
|
const visibleEntries = [];
|
|
18919
19562
|
runs.forEach((run25, index) => {
|
|
18920
|
-
if (
|
|
19563
|
+
if (run25.type === "text" && !isRunVisible(run25, view))
|
|
18921
19564
|
return;
|
|
18922
|
-
}
|
|
18923
19565
|
visibleEntries.push({ run: run25, originalIndex: index });
|
|
18924
19566
|
});
|
|
18925
19567
|
let out = "";
|
|
@@ -18942,7 +19584,15 @@ function renderRuns(paragraphId, runs, ctx) {
|
|
|
18942
19584
|
lookahead++;
|
|
18943
19585
|
}
|
|
18944
19586
|
const segment = visibleEntries.slice(cursor, lookahead);
|
|
18945
|
-
|
|
19587
|
+
const segmentRuns = segment.map((entry2) => entry2.run);
|
|
19588
|
+
out += renderTextSegment(segmentRuns, view);
|
|
19589
|
+
if (view === "current") {
|
|
19590
|
+
for (const segmentRun of segmentRuns) {
|
|
19591
|
+
if (segmentRun.trackedChange) {
|
|
19592
|
+
ctx.referencedTrackedChanges.set(segmentRun.trackedChange.id, segmentRun.trackedChange);
|
|
19593
|
+
}
|
|
19594
|
+
}
|
|
19595
|
+
}
|
|
18946
19596
|
out += commentEndingsFor(paragraphId, segment, ctx.commentIndex);
|
|
18947
19597
|
cursor = lookahead;
|
|
18948
19598
|
continue;
|
|
@@ -18985,7 +19635,7 @@ function commentEndingsFor(paragraphId, segment, commentIndex) {
|
|
|
18985
19635
|
return out;
|
|
18986
19636
|
}
|
|
18987
19637
|
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?.
|
|
19638
|
+
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?.id === b.trackedChange?.id && sameCommentSet(a2.comments, b.comments);
|
|
18989
19639
|
}
|
|
18990
19640
|
function sameCommentSet(left, right) {
|
|
18991
19641
|
const a2 = left ?? [];
|
|
@@ -18998,7 +19648,7 @@ function sameCommentSet(left, right) {
|
|
|
18998
19648
|
}
|
|
18999
19649
|
return true;
|
|
19000
19650
|
}
|
|
19001
|
-
function renderTextSegment(runs,
|
|
19651
|
+
function renderTextSegment(runs, view) {
|
|
19002
19652
|
const text = runs.map((run25) => run25.text).join("");
|
|
19003
19653
|
if (text.length === 0)
|
|
19004
19654
|
return "";
|
|
@@ -19024,11 +19674,17 @@ function renderTextSegment(runs, showChanges) {
|
|
|
19024
19674
|
const target = first.hyperlink.url ?? `#${first.hyperlink.anchor ?? ""}`;
|
|
19025
19675
|
out = `[${out}](${target})`;
|
|
19026
19676
|
}
|
|
19027
|
-
if (
|
|
19028
|
-
|
|
19677
|
+
if (view === "current" && first.trackedChange) {
|
|
19678
|
+
const marker = criticMarkerFor(first.trackedChange.kind);
|
|
19679
|
+
out = `{${marker}${out}${marker}}[^${first.trackedChange.id}]`;
|
|
19029
19680
|
}
|
|
19030
19681
|
return out;
|
|
19031
19682
|
}
|
|
19683
|
+
function criticMarkerFor(kind) {
|
|
19684
|
+
if (kind === "ins" || kind === "moveTo")
|
|
19685
|
+
return "++";
|
|
19686
|
+
return "--";
|
|
19687
|
+
}
|
|
19032
19688
|
function colorAttrFor(value) {
|
|
19033
19689
|
if (!value)
|
|
19034
19690
|
return null;
|
|
@@ -19133,6 +19789,32 @@ function renderNoteDefinitions(notes, referenced) {
|
|
|
19133
19789
|
return lines.join(`
|
|
19134
19790
|
`);
|
|
19135
19791
|
}
|
|
19792
|
+
function renderTrackedChangeFootnotes(referenced) {
|
|
19793
|
+
if (referenced.size === 0)
|
|
19794
|
+
return "";
|
|
19795
|
+
const sorted = [...referenced.values()].sort((a2, b) => trackedChangeIdCompare(a2.id, b.id));
|
|
19796
|
+
const lines = [];
|
|
19797
|
+
for (const change of sorted) {
|
|
19798
|
+
const kind = trackedChangeLabelFor(change.kind);
|
|
19799
|
+
const author = change.author || "unknown";
|
|
19800
|
+
const meta = change.date ? `${author} (${change.date})` : author;
|
|
19801
|
+
lines.push(`[^${change.id}]: ${kind} by ${meta}`);
|
|
19802
|
+
}
|
|
19803
|
+
return lines.join(`
|
|
19804
|
+
`);
|
|
19805
|
+
}
|
|
19806
|
+
function trackedChangeLabelFor(kind) {
|
|
19807
|
+
if (kind === "ins")
|
|
19808
|
+
return "insertion";
|
|
19809
|
+
if (kind === "del")
|
|
19810
|
+
return "deletion";
|
|
19811
|
+
if (kind === "moveTo")
|
|
19812
|
+
return "moveTo";
|
|
19813
|
+
return "moveFrom";
|
|
19814
|
+
}
|
|
19815
|
+
function trackedChangeIdCompare(left, right) {
|
|
19816
|
+
return numericIdCompare(left, right, /^tc(\d+)$/);
|
|
19817
|
+
}
|
|
19136
19818
|
function noteIdCompare(left, right) {
|
|
19137
19819
|
return numericIdCompare(left, right, /(\d+)$/);
|
|
19138
19820
|
}
|
|
@@ -19198,6 +19880,7 @@ function blockIdForLocator(input, position) {
|
|
|
19198
19880
|
case "comment":
|
|
19199
19881
|
case "image":
|
|
19200
19882
|
case "hyperlink":
|
|
19883
|
+
case "trackedChange":
|
|
19201
19884
|
throw new MarkdownLocatorError(input, `--${position} does not accept a ${parsed.kind} locator \u2014 use a paragraph or table locator`);
|
|
19202
19885
|
}
|
|
19203
19886
|
}
|
|
@@ -19230,7 +19913,8 @@ async function run25(args) {
|
|
|
19230
19913
|
markdown: { type: "boolean" },
|
|
19231
19914
|
from: { type: "string" },
|
|
19232
19915
|
to: { type: "string" },
|
|
19233
|
-
|
|
19916
|
+
accepted: { type: "boolean" },
|
|
19917
|
+
baseline: { type: "boolean" },
|
|
19234
19918
|
comments: { type: "boolean" },
|
|
19235
19919
|
help: { type: "boolean", short: "h" }
|
|
19236
19920
|
}
|
|
@@ -19248,20 +19932,25 @@ async function run25(args) {
|
|
|
19248
19932
|
const markdown = Boolean(parsed.values.markdown);
|
|
19249
19933
|
const from = parsed.values.from;
|
|
19250
19934
|
const to = parsed.values.to;
|
|
19251
|
-
const
|
|
19935
|
+
const accepted = Boolean(parsed.values.accepted);
|
|
19936
|
+
const baseline = Boolean(parsed.values.baseline);
|
|
19252
19937
|
const showComments = Boolean(parsed.values.comments);
|
|
19253
|
-
if (!markdown && (from || to ||
|
|
19254
|
-
return fail("USAGE", "--from, --to, --
|
|
19938
|
+
if (!markdown && (from || to || accepted || baseline || showComments)) {
|
|
19939
|
+
return fail("USAGE", "--from, --to, --accepted, --baseline, and --comments require --markdown", HELP25);
|
|
19255
19940
|
}
|
|
19256
|
-
|
|
19257
|
-
|
|
19258
|
-
|
|
19941
|
+
if (accepted && baseline) {
|
|
19942
|
+
return fail("USAGE", "--accepted and --baseline are mutually exclusive", HELP25);
|
|
19943
|
+
}
|
|
19944
|
+
const view = accepted ? "accepted" : baseline ? "baseline" : "current";
|
|
19945
|
+
const docView = await openOrFail(path);
|
|
19946
|
+
if (typeof docView === "number")
|
|
19947
|
+
return docView;
|
|
19259
19948
|
if (markdown) {
|
|
19260
19949
|
try {
|
|
19261
|
-
const rendered = renderMarkdown(
|
|
19950
|
+
const rendered = renderMarkdown(docView.doc, {
|
|
19262
19951
|
from,
|
|
19263
19952
|
to,
|
|
19264
|
-
|
|
19953
|
+
view,
|
|
19265
19954
|
showComments
|
|
19266
19955
|
});
|
|
19267
19956
|
await writeStdout(rendered);
|
|
@@ -19273,8 +19962,8 @@ async function run25(args) {
|
|
|
19273
19962
|
throw err;
|
|
19274
19963
|
}
|
|
19275
19964
|
}
|
|
19276
|
-
await enrichImageHashes(
|
|
19277
|
-
await respond(
|
|
19965
|
+
await enrichImageHashes(docView);
|
|
19966
|
+
await respond(docView.doc);
|
|
19278
19967
|
return EXIT.OK;
|
|
19279
19968
|
}
|
|
19280
19969
|
var HELP25 = `docx read \u2014 print AST as JSON, or render document body as Markdown
|
|
@@ -19293,8 +19982,18 @@ Options:
|
|
|
19293
19982
|
Accepts pN, tN, tN:rRcC[:pK[:S-E]], pN:S-E, pN:S-pM:E.
|
|
19294
19983
|
Cell/span/range locators collapse to their enclosing
|
|
19295
19984
|
top-level block (the table or paragraph).
|
|
19296
|
-
--
|
|
19297
|
-
<
|
|
19985
|
+
--accepted With --markdown, render the post-accept view: drop
|
|
19986
|
+
subtractive wrappers (<w:del>, <w:moveFrom>), inline
|
|
19987
|
+
additive wrappers (<w:ins>, <w:moveTo>) as plain text,
|
|
19988
|
+
no markers/refs.
|
|
19989
|
+
--baseline With --markdown, render the pre-change view: drop
|
|
19990
|
+
additive wrappers (<w:ins>, <w:moveTo>), inline
|
|
19991
|
+
subtractive wrappers (<w:del>, <w:moveFrom>) as plain
|
|
19992
|
+
text, no markers/refs. Mutually exclusive with --accepted.
|
|
19993
|
+
Default --markdown shows all four: additive wrappers as
|
|
19994
|
+
{++text++}[^tcN] and subtractive as {--text--}[^tcN]
|
|
19995
|
+
(CriticMarkup); the [^tcN] footnote spells out the kind
|
|
19996
|
+
(insertion / deletion / moveTo / moveFrom).
|
|
19298
19997
|
--comments With --markdown, append [^cN] after each commented span
|
|
19299
19998
|
and emit a footnote definition for each comment at the
|
|
19300
19999
|
end of the output (author, date, body).
|
|
@@ -19304,7 +20003,8 @@ Examples:
|
|
|
19304
20003
|
docx read input.docx
|
|
19305
20004
|
docx read input.docx --markdown
|
|
19306
20005
|
docx read input.docx --markdown --from p3 --to p20
|
|
19307
|
-
docx read input.docx --markdown --
|
|
20006
|
+
docx read input.docx --markdown --accepted --comments
|
|
20007
|
+
docx read input.docx --markdown --baseline
|
|
19308
20008
|
docx read input.docx | jq '.blocks[] | select(.type == "paragraph")'
|
|
19309
20009
|
`;
|
|
19310
20010
|
var init_read2 = __esm(() => {
|
|
@@ -19341,33 +20041,25 @@ function replaceSpanInParagraph(paragraph, span, replacement, tracked) {
|
|
|
19341
20041
|
function collectRunSlots(paragraph) {
|
|
19342
20042
|
const slots = [];
|
|
19343
20043
|
let offset = 0;
|
|
19344
|
-
|
|
19345
|
-
|
|
19346
|
-
|
|
19347
|
-
|
|
19348
|
-
parent: paragraph,
|
|
19349
|
-
run: child,
|
|
19350
|
-
offsetBefore: offset,
|
|
19351
|
-
length
|
|
19352
|
-
});
|
|
19353
|
-
offset += length;
|
|
19354
|
-
continue;
|
|
19355
|
-
}
|
|
19356
|
-
if (child.tag === "w:ins" || child.tag === "w:del" || child.tag === "w:hyperlink") {
|
|
19357
|
-
for (const inner of child.children) {
|
|
19358
|
-
if (inner.tag !== "w:r")
|
|
19359
|
-
continue;
|
|
19360
|
-
const length = runTextLength(inner);
|
|
20044
|
+
function walk(parent, children) {
|
|
20045
|
+
for (const child of children) {
|
|
20046
|
+
if (child.tag === "w:r") {
|
|
20047
|
+
const length = runTextLength(child);
|
|
19361
20048
|
slots.push({
|
|
19362
|
-
parent
|
|
19363
|
-
run:
|
|
20049
|
+
parent,
|
|
20050
|
+
run: child,
|
|
19364
20051
|
offsetBefore: offset,
|
|
19365
20052
|
length
|
|
19366
20053
|
});
|
|
19367
20054
|
offset += length;
|
|
20055
|
+
continue;
|
|
20056
|
+
}
|
|
20057
|
+
if (isRunBearingWrapper(child.tag)) {
|
|
20058
|
+
walk(child, child.children);
|
|
19368
20059
|
}
|
|
19369
20060
|
}
|
|
19370
20061
|
}
|
|
20062
|
+
walk(paragraph, paragraph.children);
|
|
19371
20063
|
return slots;
|
|
19372
20064
|
}
|
|
19373
20065
|
function rebuildContainer(container, baseOffset, span, replacement, runProperties, isParagraph, tracked) {
|
|
@@ -19421,13 +20113,8 @@ function rebuildContainer(container, baseOffset, span, replacement, runPropertie
|
|
|
19421
20113
|
}
|
|
19422
20114
|
continue;
|
|
19423
20115
|
}
|
|
19424
|
-
if (isParagraph && (child.tag
|
|
19425
|
-
|
|
19426
|
-
for (const inner of child.children) {
|
|
19427
|
-
if (inner.tag === "w:r")
|
|
19428
|
-
innerLength += runTextLength(inner);
|
|
19429
|
-
}
|
|
19430
|
-
offset += innerLength;
|
|
20116
|
+
if (isParagraph && isRunBearingWrapper(child.tag)) {
|
|
20117
|
+
offset += sumRunBearingTextLength(child.children);
|
|
19431
20118
|
newChildren.push(child);
|
|
19432
20119
|
continue;
|
|
19433
20120
|
}
|
|
@@ -19488,8 +20175,8 @@ function rebuildAcrossBoundaries(paragraph, span, replacement, runProperties, tr
|
|
|
19488
20175
|
}
|
|
19489
20176
|
continue;
|
|
19490
20177
|
}
|
|
19491
|
-
if (child.tag === "w:ins" || child.tag === "w:del") {
|
|
19492
|
-
const innerLength =
|
|
20178
|
+
if (child.tag === "w:ins" || child.tag === "w:del" || child.tag === "w:moveFrom" || child.tag === "w:moveTo") {
|
|
20179
|
+
const innerLength = sumRunBearingTextLength(child.children);
|
|
19493
20180
|
const wrapperStart = offset;
|
|
19494
20181
|
const wrapperEnd = offset + innerLength;
|
|
19495
20182
|
offset = wrapperEnd;
|
|
@@ -19506,7 +20193,7 @@ function rebuildAcrossBoundaries(paragraph, span, replacement, runProperties, tr
|
|
|
19506
20193
|
continue;
|
|
19507
20194
|
}
|
|
19508
20195
|
if (child.tag === "w:hyperlink") {
|
|
19509
|
-
const innerLength =
|
|
20196
|
+
const innerLength = sumRunBearingTextLength(child.children);
|
|
19510
20197
|
const wrapperStart = offset;
|
|
19511
20198
|
const wrapperEnd = offset + innerLength;
|
|
19512
20199
|
offset = wrapperEnd;
|
|
@@ -19524,6 +20211,23 @@ function rebuildAcrossBoundaries(paragraph, span, replacement, runProperties, tr
|
|
|
19524
20211
|
});
|
|
19525
20212
|
continue;
|
|
19526
20213
|
}
|
|
20214
|
+
if (isRunBearingWrapper(child.tag)) {
|
|
20215
|
+
const innerLength = sumRunBearingTextLength(child.children);
|
|
20216
|
+
const wrapperStart = offset;
|
|
20217
|
+
const wrapperEnd = offset + innerLength;
|
|
20218
|
+
offset = wrapperEnd;
|
|
20219
|
+
if (wrapperEnd <= span.start) {
|
|
20220
|
+
newChildren.push(child);
|
|
20221
|
+
continue;
|
|
20222
|
+
}
|
|
20223
|
+
if (wrapperStart >= span.end) {
|
|
20224
|
+
placeReplacement();
|
|
20225
|
+
newChildren.push(child);
|
|
20226
|
+
continue;
|
|
20227
|
+
}
|
|
20228
|
+
splitTransparentWrapperAcrossSpan(child, wrapperStart, span, newChildren, placeReplacement);
|
|
20229
|
+
continue;
|
|
20230
|
+
}
|
|
19527
20231
|
newChildren.push(child);
|
|
19528
20232
|
}
|
|
19529
20233
|
if (!placed)
|
|
@@ -19531,7 +20235,7 @@ function rebuildAcrossBoundaries(paragraph, span, replacement, runProperties, tr
|
|
|
19531
20235
|
paragraph.children = newChildren;
|
|
19532
20236
|
}
|
|
19533
20237
|
function splitWrapperAcrossSpan(wrapper, wrapperStart, span, tracked, out, placeReplacement) {
|
|
19534
|
-
const
|
|
20238
|
+
const isSubtractive = isSubtractiveTrackedChangeWrapper(wrapper.tag);
|
|
19535
20239
|
const preInner = [];
|
|
19536
20240
|
const cutInner = [];
|
|
19537
20241
|
const postInner = [];
|
|
@@ -19562,7 +20266,7 @@ function splitWrapperAcrossSpan(wrapper, wrapperStart, span, tracked, out, place
|
|
|
19562
20266
|
postInner.push(sliceRun(inner, sliceEndInRun, length));
|
|
19563
20267
|
}
|
|
19564
20268
|
const preChildren = preInner.slice();
|
|
19565
|
-
if (
|
|
20269
|
+
if (isSubtractive) {
|
|
19566
20270
|
preChildren.push(...cutInner);
|
|
19567
20271
|
} else if (tracked && cutInner.length > 0) {
|
|
19568
20272
|
for (const cutRun of cutInner)
|
|
@@ -19584,8 +20288,48 @@ function splitWrapperAcrossSpan(wrapper, wrapperStart, span, tracked, out, place
|
|
|
19584
20288
|
out.push(postWrapper);
|
|
19585
20289
|
}
|
|
19586
20290
|
}
|
|
20291
|
+
function splitTransparentWrapperAcrossSpan(wrapper, wrapperStart, span, out, placeReplacement) {
|
|
20292
|
+
const preInner = [];
|
|
20293
|
+
const postInner = [];
|
|
20294
|
+
let innerOffset = wrapperStart;
|
|
20295
|
+
for (const inner of wrapper.children) {
|
|
20296
|
+
if (inner.tag !== "w:r") {
|
|
20297
|
+
preInner.push(inner);
|
|
20298
|
+
continue;
|
|
20299
|
+
}
|
|
20300
|
+
const length = runTextLength(inner);
|
|
20301
|
+
const runStart = innerOffset;
|
|
20302
|
+
const runEnd = innerOffset + length;
|
|
20303
|
+
innerOffset = runEnd;
|
|
20304
|
+
if (runEnd <= span.start) {
|
|
20305
|
+
preInner.push(inner);
|
|
20306
|
+
continue;
|
|
20307
|
+
}
|
|
20308
|
+
if (runStart >= span.end) {
|
|
20309
|
+
postInner.push(inner);
|
|
20310
|
+
continue;
|
|
20311
|
+
}
|
|
20312
|
+
const sliceStartInRun = Math.max(0, span.start - runStart);
|
|
20313
|
+
const sliceEndInRun = Math.min(length, span.end - runStart);
|
|
20314
|
+
if (sliceStartInRun > 0)
|
|
20315
|
+
preInner.push(sliceRun(inner, 0, sliceStartInRun));
|
|
20316
|
+
if (sliceEndInRun < length)
|
|
20317
|
+
postInner.push(sliceRun(inner, sliceEndInRun, length));
|
|
20318
|
+
}
|
|
20319
|
+
if (preInner.length > 0) {
|
|
20320
|
+
const preWrapper = new XmlNode2(wrapper.tag, { ...wrapper.attributes });
|
|
20321
|
+
preWrapper.children = preInner;
|
|
20322
|
+
out.push(preWrapper);
|
|
20323
|
+
}
|
|
20324
|
+
placeReplacement();
|
|
20325
|
+
if (postInner.length > 0) {
|
|
20326
|
+
const postWrapper = new XmlNode2(wrapper.tag, { ...wrapper.attributes });
|
|
20327
|
+
postWrapper.children = postInner;
|
|
20328
|
+
out.push(postWrapper);
|
|
20329
|
+
}
|
|
20330
|
+
}
|
|
19587
20331
|
function splitHyperlinkAcrossSpan(wrapper, wrapperStart, span, runProperties, replacement, tracked, out, placeReplacement, markReplacementPlaced) {
|
|
19588
|
-
const wrapperEnd = wrapperStart + wrapper.children
|
|
20332
|
+
const wrapperEnd = wrapperStart + sumRunBearingTextLength(wrapper.children);
|
|
19589
20333
|
const startsInside = span.start > wrapperStart && span.start < wrapperEnd;
|
|
19590
20334
|
const preInner = [];
|
|
19591
20335
|
const postInner = [];
|
|
@@ -19639,14 +20383,6 @@ function splitHyperlinkAcrossSpan(wrapper, wrapperStart, span, runProperties, re
|
|
|
19639
20383
|
out.push(postWrapper);
|
|
19640
20384
|
}
|
|
19641
20385
|
}
|
|
19642
|
-
function sumInnerRunLengths2(wrapper) {
|
|
19643
|
-
let total = 0;
|
|
19644
|
-
for (const inner of wrapper.children) {
|
|
19645
|
-
if (inner.tag === "w:r")
|
|
19646
|
-
total += runTextLength(inner);
|
|
19647
|
-
}
|
|
19648
|
-
return total;
|
|
19649
|
-
}
|
|
19650
20386
|
function mintMeta(tracked) {
|
|
19651
20387
|
return { ...tracked.meta, revisionId: tracked.allocator.next() };
|
|
19652
20388
|
}
|
|
@@ -19694,6 +20430,7 @@ async function run26(args) {
|
|
|
19694
20430
|
"ignore-case": { type: "boolean" },
|
|
19695
20431
|
all: { type: "boolean" },
|
|
19696
20432
|
limit: { type: "string" },
|
|
20433
|
+
author: { type: "string" },
|
|
19697
20434
|
output: { type: "string", short: "o" },
|
|
19698
20435
|
"dry-run": { type: "boolean" },
|
|
19699
20436
|
help: { type: "boolean", short: "h" }
|
|
@@ -19792,8 +20529,9 @@ async function run26(args) {
|
|
|
19792
20529
|
}
|
|
19793
20530
|
return rightMatch.start - leftMatch.start;
|
|
19794
20531
|
});
|
|
20532
|
+
const authorFlag = parsed.values.author;
|
|
19795
20533
|
const tracked = isTrackChangesEnabled(view) ? {
|
|
19796
|
-
meta: { author: resolveAuthor(), date: resolveDate() },
|
|
20534
|
+
meta: { author: resolveAuthor(authorFlag), date: resolveDate() },
|
|
19797
20535
|
allocator: createRevisionAllocator(view)
|
|
19798
20536
|
} : undefined;
|
|
19799
20537
|
const regexFlags = ignoreCase ? "i" : "";
|
|
@@ -19827,6 +20565,7 @@ Options:
|
|
|
19827
20565
|
--ignore-case case-insensitive match
|
|
19828
20566
|
--all replace every match (default: just the first)
|
|
19829
20567
|
--limit N replace at most N matches (in document order)
|
|
20568
|
+
--author NAME author for tracked changes (default: $DOCX_AUTHOR)
|
|
19830
20569
|
-o, --output PATH write to PATH instead of overwriting FILE
|
|
19831
20570
|
--dry-run report what would change without writing the file
|
|
19832
20571
|
-h, --help show this help
|
|
@@ -19857,9 +20596,9 @@ var init_replace3 = __esm(() => {
|
|
|
19857
20596
|
init_replace_span();
|
|
19858
20597
|
});
|
|
19859
20598
|
|
|
19860
|
-
// src/cli/track-changes/
|
|
19861
|
-
var
|
|
19862
|
-
__export(
|
|
20599
|
+
// src/cli/track-changes/list.ts
|
|
20600
|
+
var exports_list4 = {};
|
|
20601
|
+
__export(exports_list4, {
|
|
19863
20602
|
run: () => run27
|
|
19864
20603
|
});
|
|
19865
20604
|
import { parseArgs as parseArgs23 } from "util";
|
|
@@ -19870,8 +20609,6 @@ async function run27(args) {
|
|
|
19870
20609
|
args,
|
|
19871
20610
|
allowPositionals: true,
|
|
19872
20611
|
options: {
|
|
19873
|
-
output: { type: "string", short: "o" },
|
|
19874
|
-
"dry-run": { type: "boolean" },
|
|
19875
20612
|
help: { type: "boolean", short: "h" }
|
|
19876
20613
|
}
|
|
19877
20614
|
});
|
|
@@ -19886,9 +20623,364 @@ async function run27(args) {
|
|
|
19886
20623
|
const path = parsed.positionals[0];
|
|
19887
20624
|
if (!path)
|
|
19888
20625
|
return fail("USAGE", "Missing FILE argument", HELP27);
|
|
20626
|
+
const view = await openOrFail(path);
|
|
20627
|
+
if (typeof view === "number")
|
|
20628
|
+
return view;
|
|
20629
|
+
const byId = new Map;
|
|
20630
|
+
for (const paragraph of flattenParagraphs(view.doc.blocks)) {
|
|
20631
|
+
for (const run28 of paragraph.runs) {
|
|
20632
|
+
if (run28.type !== "text" || !run28.trackedChange)
|
|
20633
|
+
continue;
|
|
20634
|
+
const change = run28.trackedChange;
|
|
20635
|
+
const existing = byId.get(change.id);
|
|
20636
|
+
if (existing) {
|
|
20637
|
+
existing.text += run28.text;
|
|
20638
|
+
continue;
|
|
20639
|
+
}
|
|
20640
|
+
byId.set(change.id, {
|
|
20641
|
+
...change,
|
|
20642
|
+
blockId: paragraph.id,
|
|
20643
|
+
text: run28.text
|
|
20644
|
+
});
|
|
20645
|
+
}
|
|
20646
|
+
}
|
|
20647
|
+
for (const [id, reference] of view.trackedChangeReferences) {
|
|
20648
|
+
if (byId.has(id))
|
|
20649
|
+
continue;
|
|
20650
|
+
const kind = trackedChangeKindForTag(reference.node.tag);
|
|
20651
|
+
if (!kind)
|
|
20652
|
+
continue;
|
|
20653
|
+
byId.set(id, {
|
|
20654
|
+
id,
|
|
20655
|
+
kind,
|
|
20656
|
+
author: reference.node.getAttribute("w:author") ?? "",
|
|
20657
|
+
date: reference.node.getAttribute("w:date") ?? "",
|
|
20658
|
+
revisionId: reference.node.getAttribute("w:id") ?? "",
|
|
20659
|
+
blockId: reference.blockId,
|
|
20660
|
+
text: ""
|
|
20661
|
+
});
|
|
20662
|
+
}
|
|
20663
|
+
const sorted = [...byId.values()].sort((a2, b) => trackedChangeIndex(a2.id) - trackedChangeIndex(b.id));
|
|
20664
|
+
await respond(sorted);
|
|
20665
|
+
return EXIT.OK;
|
|
20666
|
+
}
|
|
20667
|
+
function trackedChangeIndex(id) {
|
|
20668
|
+
const match = id.match(/^tc(\d+)$/);
|
|
20669
|
+
return match?.[1] ? Number(match[1]) : 0;
|
|
20670
|
+
}
|
|
20671
|
+
function trackedChangeKindForTag(tag) {
|
|
20672
|
+
if (tag === "w:ins")
|
|
20673
|
+
return "ins";
|
|
20674
|
+
if (tag === "w:del")
|
|
20675
|
+
return "del";
|
|
20676
|
+
if (tag === "w:moveFrom")
|
|
20677
|
+
return "moveFrom";
|
|
20678
|
+
if (tag === "w:moveTo")
|
|
20679
|
+
return "moveTo";
|
|
20680
|
+
return null;
|
|
20681
|
+
}
|
|
20682
|
+
var HELP27 = `docx track-changes list \u2014 inventory every revision wrapper
|
|
20683
|
+
|
|
20684
|
+
Usage:
|
|
20685
|
+
docx track-changes list FILE [options]
|
|
20686
|
+
|
|
20687
|
+
Options:
|
|
20688
|
+
-h, --help Show this help
|
|
20689
|
+
|
|
20690
|
+
Lists every <w:ins>, <w:del>, <w:moveFrom>, and <w:moveTo> wrapper with
|
|
20691
|
+
stable tcN ids. moveFrom/moveTo halves of the same logical move appear
|
|
20692
|
+
as separate entries (one for each side); their kind tells them apart.
|
|
20693
|
+
|
|
20694
|
+
Output: JSON array of { id, kind, author, date, revisionId, blockId, text }
|
|
20695
|
+
sorted by id (document order). kind is one of: "ins", "del", "moveFrom",
|
|
20696
|
+
"moveTo".
|
|
20697
|
+
|
|
20698
|
+
Examples:
|
|
20699
|
+
docx track-changes list doc.docx
|
|
20700
|
+
docx track-changes list doc.docx | jq '.[] | select(.kind == "del")'
|
|
20701
|
+
docx track-changes list doc.docx | jq '.[] | select(.kind | test("move"))'
|
|
20702
|
+
`;
|
|
20703
|
+
var init_list4 = __esm(() => {
|
|
20704
|
+
init_core();
|
|
20705
|
+
init_respond();
|
|
20706
|
+
});
|
|
20707
|
+
|
|
20708
|
+
// src/cli/track-changes/apply.ts
|
|
20709
|
+
import { parseArgs as parseArgs24 } from "util";
|
|
20710
|
+
async function runApply(args, verb, help) {
|
|
20711
|
+
let parsed;
|
|
20712
|
+
try {
|
|
20713
|
+
parsed = parseArgs24({
|
|
20714
|
+
args,
|
|
20715
|
+
allowPositionals: true,
|
|
20716
|
+
options: {
|
|
20717
|
+
at: { type: "string" },
|
|
20718
|
+
all: { type: "boolean" },
|
|
20719
|
+
output: { type: "string", short: "o" },
|
|
20720
|
+
"dry-run": { type: "boolean" },
|
|
20721
|
+
help: { type: "boolean", short: "h" }
|
|
20722
|
+
}
|
|
20723
|
+
});
|
|
20724
|
+
} catch (parseError) {
|
|
20725
|
+
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
20726
|
+
return fail("USAGE", message, help);
|
|
20727
|
+
}
|
|
20728
|
+
if (parsed.values.help) {
|
|
20729
|
+
await writeStdout(help);
|
|
20730
|
+
return EXIT.OK;
|
|
20731
|
+
}
|
|
20732
|
+
const path = parsed.positionals[0];
|
|
20733
|
+
if (!path)
|
|
20734
|
+
return fail("USAGE", "Missing FILE argument", help);
|
|
20735
|
+
const at = parsed.values.at;
|
|
20736
|
+
const all = Boolean(parsed.values.all);
|
|
20737
|
+
if (at && all) {
|
|
20738
|
+
return fail("USAGE", "--at and --all are mutually exclusive", help);
|
|
20739
|
+
}
|
|
20740
|
+
if (!at && !all) {
|
|
20741
|
+
return fail("USAGE", "Specify --at tcN or --all", help);
|
|
20742
|
+
}
|
|
20743
|
+
const view = await openOrFail(path);
|
|
20744
|
+
if (typeof view === "number")
|
|
20745
|
+
return view;
|
|
20746
|
+
const allChanges = collectTrackedChanges(view.documentTree);
|
|
20747
|
+
let targets;
|
|
20748
|
+
if (all) {
|
|
20749
|
+
targets = allChanges;
|
|
20750
|
+
} else {
|
|
20751
|
+
const found = allChanges.find((change) => change.id === at);
|
|
20752
|
+
if (!found) {
|
|
20753
|
+
return fail("TRACKED_CHANGE_NOT_FOUND", `Tracked change not found: ${at}`);
|
|
20754
|
+
}
|
|
20755
|
+
targets = [found];
|
|
20756
|
+
}
|
|
20757
|
+
const records = targets.map((target) => ({
|
|
20758
|
+
id: target.id,
|
|
20759
|
+
kind: target.kind,
|
|
20760
|
+
action: actionFor(target.kind, verb),
|
|
20761
|
+
author: target.author,
|
|
20762
|
+
date: target.date
|
|
20763
|
+
}));
|
|
20764
|
+
const outputPath = parsed.values.output;
|
|
20765
|
+
if (parsed.values["dry-run"]) {
|
|
20766
|
+
await respond({
|
|
20767
|
+
ok: true,
|
|
20768
|
+
operation: `track-changes.${verb}`,
|
|
20769
|
+
dryRun: true,
|
|
20770
|
+
path,
|
|
20771
|
+
...outputPath ? { output: outputPath } : {},
|
|
20772
|
+
applied: records
|
|
20773
|
+
});
|
|
20774
|
+
return EXIT.OK;
|
|
20775
|
+
}
|
|
20776
|
+
for (const target of [...targets].reverse()) {
|
|
20777
|
+
if (verb === "accept")
|
|
20778
|
+
applyAccept(target.node, target.parent);
|
|
20779
|
+
else
|
|
20780
|
+
applyReject(target.node, target.parent);
|
|
20781
|
+
}
|
|
20782
|
+
await saveDocView(view, outputPath);
|
|
20783
|
+
await respond({
|
|
20784
|
+
ok: true,
|
|
20785
|
+
operation: `track-changes.${verb}`,
|
|
20786
|
+
path: outputPath ?? path,
|
|
20787
|
+
applied: records
|
|
20788
|
+
});
|
|
20789
|
+
return EXIT.OK;
|
|
20790
|
+
}
|
|
20791
|
+
function collectTrackedChanges(tree) {
|
|
20792
|
+
const out = [];
|
|
20793
|
+
let counter = 0;
|
|
20794
|
+
function walk(children) {
|
|
20795
|
+
for (const node of children) {
|
|
20796
|
+
const kind = trackedChangeKindForTag2(node.tag);
|
|
20797
|
+
if (kind) {
|
|
20798
|
+
out.push({
|
|
20799
|
+
node,
|
|
20800
|
+
parent: children,
|
|
20801
|
+
kind,
|
|
20802
|
+
id: `tc${counter++}`,
|
|
20803
|
+
author: node.getAttribute("w:author") ?? "",
|
|
20804
|
+
date: node.getAttribute("w:date") ?? ""
|
|
20805
|
+
});
|
|
20806
|
+
}
|
|
20807
|
+
if (node.children.length > 0)
|
|
20808
|
+
walk(node.children);
|
|
20809
|
+
}
|
|
20810
|
+
}
|
|
20811
|
+
walk(tree);
|
|
20812
|
+
return out;
|
|
20813
|
+
}
|
|
20814
|
+
function trackedChangeKindForTag2(tag) {
|
|
20815
|
+
if (tag === "w:ins")
|
|
20816
|
+
return "ins";
|
|
20817
|
+
if (tag === "w:del")
|
|
20818
|
+
return "del";
|
|
20819
|
+
if (tag === "w:moveFrom")
|
|
20820
|
+
return "moveFrom";
|
|
20821
|
+
if (tag === "w:moveTo")
|
|
20822
|
+
return "moveTo";
|
|
20823
|
+
return null;
|
|
20824
|
+
}
|
|
20825
|
+
function actionFor(kind, verb) {
|
|
20826
|
+
const isAdditive = kind === "ins" || kind === "moveTo";
|
|
20827
|
+
if (verb === "accept")
|
|
20828
|
+
return isAdditive ? "unwrap" : "delete";
|
|
20829
|
+
return isAdditive ? "delete" : "unwrap";
|
|
20830
|
+
}
|
|
20831
|
+
function applyAccept(node, parent) {
|
|
20832
|
+
if (node.tag === "w:ins" || node.tag === "w:moveTo") {
|
|
20833
|
+
unwrapNode(node, parent);
|
|
20834
|
+
return;
|
|
20835
|
+
}
|
|
20836
|
+
deleteNode(node, parent);
|
|
20837
|
+
}
|
|
20838
|
+
function applyReject(node, parent) {
|
|
20839
|
+
if (node.tag === "w:ins" || node.tag === "w:moveTo") {
|
|
20840
|
+
deleteNode(node, parent);
|
|
20841
|
+
return;
|
|
20842
|
+
}
|
|
20843
|
+
renameDelTextToText(node);
|
|
20844
|
+
unwrapNode(node, parent);
|
|
20845
|
+
}
|
|
20846
|
+
function unwrapNode(node, parent) {
|
|
20847
|
+
const index = parent.indexOf(node);
|
|
20848
|
+
if (index === -1)
|
|
20849
|
+
return;
|
|
20850
|
+
parent.splice(index, 1, ...node.children);
|
|
20851
|
+
}
|
|
20852
|
+
function deleteNode(node, parent) {
|
|
20853
|
+
const index = parent.indexOf(node);
|
|
20854
|
+
if (index === -1)
|
|
20855
|
+
return;
|
|
20856
|
+
parent.splice(index, 1);
|
|
20857
|
+
}
|
|
20858
|
+
function renameDelTextToText(node) {
|
|
20859
|
+
if (node.tag === "w:delText")
|
|
20860
|
+
node.tag = "w:t";
|
|
20861
|
+
for (const child of node.children)
|
|
20862
|
+
renameDelTextToText(child);
|
|
20863
|
+
}
|
|
20864
|
+
var init_apply = __esm(() => {
|
|
20865
|
+
init_core();
|
|
20866
|
+
init_respond();
|
|
20867
|
+
});
|
|
20868
|
+
|
|
20869
|
+
// src/cli/track-changes/accept.ts
|
|
20870
|
+
var exports_accept = {};
|
|
20871
|
+
__export(exports_accept, {
|
|
20872
|
+
run: () => run28
|
|
20873
|
+
});
|
|
20874
|
+
async function run28(args) {
|
|
20875
|
+
return runApply(args, "accept", HELP28);
|
|
20876
|
+
}
|
|
20877
|
+
var HELP28 = `docx track-changes accept \u2014 accept tracked changes (incorporate into the doc)
|
|
20878
|
+
|
|
20879
|
+
Usage:
|
|
20880
|
+
docx track-changes accept FILE --at tcN [options]
|
|
20881
|
+
docx track-changes accept FILE --all [options]
|
|
20882
|
+
|
|
20883
|
+
Accepting an insertion (<w:ins>) or move destination (<w:moveTo>) unwraps the
|
|
20884
|
+
wrapper \u2014 the content becomes plain runs at this location. Accepting a
|
|
20885
|
+
deletion (<w:del>) or move source (<w:moveFrom>) removes the element and its
|
|
20886
|
+
<w:delText> entirely (the text disappears for real).
|
|
20887
|
+
|
|
20888
|
+
Out of scope: tracked paragraph marks (<w:rPr><w:ins/></w:rPr> inside <w:pPr>)
|
|
20889
|
+
and formatting changes (<w:rPrChange>/<w:pPrChange>). These aren't modeled in
|
|
20890
|
+
the AST today and --all silently skips them.
|
|
20891
|
+
|
|
20892
|
+
Options:
|
|
20893
|
+
--at tcN Accept a single tracked change by id
|
|
20894
|
+
--all Accept every tracked change (mutually exclusive with --at)
|
|
20895
|
+
-o, --output PATH Write to PATH instead of overwriting FILE
|
|
20896
|
+
--dry-run Print what would change; do not write the file
|
|
20897
|
+
-h, --help Show this help
|
|
20898
|
+
|
|
20899
|
+
Examples:
|
|
20900
|
+
docx track-changes accept doc.docx --at tc0
|
|
20901
|
+
docx track-changes accept doc.docx --all
|
|
20902
|
+
docx track-changes accept doc.docx --all --dry-run
|
|
20903
|
+
`;
|
|
20904
|
+
var init_accept = __esm(() => {
|
|
20905
|
+
init_apply();
|
|
20906
|
+
});
|
|
20907
|
+
|
|
20908
|
+
// src/cli/track-changes/reject.ts
|
|
20909
|
+
var exports_reject = {};
|
|
20910
|
+
__export(exports_reject, {
|
|
20911
|
+
run: () => run29
|
|
20912
|
+
});
|
|
20913
|
+
async function run29(args) {
|
|
20914
|
+
return runApply(args, "reject", HELP29);
|
|
20915
|
+
}
|
|
20916
|
+
var HELP29 = `docx track-changes reject \u2014 reject tracked changes (revert to pre-change state)
|
|
20917
|
+
|
|
20918
|
+
Usage:
|
|
20919
|
+
docx track-changes reject FILE --at tcN [options]
|
|
20920
|
+
docx track-changes reject FILE --all [options]
|
|
20921
|
+
|
|
20922
|
+
Rejecting an insertion (<w:ins>) or move destination (<w:moveTo>) removes the
|
|
20923
|
+
element and its content (it shouldn't have arrived at this location).
|
|
20924
|
+
Rejecting a deletion (<w:del>) or move source (<w:moveFrom>) unwraps the
|
|
20925
|
+
wrapper and converts <w:delText> back to <w:t>, so the text reappears as
|
|
20926
|
+
plain runs.
|
|
20927
|
+
|
|
20928
|
+
moveFrom and moveTo are processed independently. To fully undo a move, target
|
|
20929
|
+
both halves (or use --all). The runtime treats them as paired only by their
|
|
20930
|
+
shared revision id, not by atomic accept/reject.
|
|
20931
|
+
|
|
20932
|
+
Out of scope: tracked paragraph marks (<w:rPr><w:del/></w:rPr> inside <w:pPr>)
|
|
20933
|
+
and formatting changes (<w:rPrChange>/<w:pPrChange>). These aren't modeled in
|
|
20934
|
+
the AST today and --all silently skips them.
|
|
20935
|
+
|
|
20936
|
+
Options:
|
|
20937
|
+
--at tcN Reject a single tracked change by id
|
|
20938
|
+
--all Reject every tracked change (mutually exclusive with --at)
|
|
20939
|
+
-o, --output PATH Write to PATH instead of overwriting FILE
|
|
20940
|
+
--dry-run Print what would change; do not write the file
|
|
20941
|
+
-h, --help Show this help
|
|
20942
|
+
|
|
20943
|
+
Examples:
|
|
20944
|
+
docx track-changes reject doc.docx --at tc0
|
|
20945
|
+
docx track-changes reject doc.docx --all
|
|
20946
|
+
docx track-changes reject doc.docx --all --dry-run
|
|
20947
|
+
`;
|
|
20948
|
+
var init_reject = __esm(() => {
|
|
20949
|
+
init_apply();
|
|
20950
|
+
});
|
|
20951
|
+
|
|
20952
|
+
// src/cli/track-changes/toggle.tsx
|
|
20953
|
+
var exports_toggle = {};
|
|
20954
|
+
__export(exports_toggle, {
|
|
20955
|
+
run: () => run30
|
|
20956
|
+
});
|
|
20957
|
+
import { parseArgs as parseArgs25 } from "util";
|
|
20958
|
+
async function run30(args) {
|
|
20959
|
+
let parsed;
|
|
20960
|
+
try {
|
|
20961
|
+
parsed = parseArgs25({
|
|
20962
|
+
args,
|
|
20963
|
+
allowPositionals: true,
|
|
20964
|
+
options: {
|
|
20965
|
+
output: { type: "string", short: "o" },
|
|
20966
|
+
"dry-run": { type: "boolean" },
|
|
20967
|
+
help: { type: "boolean", short: "h" }
|
|
20968
|
+
}
|
|
20969
|
+
});
|
|
20970
|
+
} catch (parseError) {
|
|
20971
|
+
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
20972
|
+
return fail("USAGE", message, HELP30);
|
|
20973
|
+
}
|
|
20974
|
+
if (parsed.values.help) {
|
|
20975
|
+
await writeStdout(HELP30);
|
|
20976
|
+
return EXIT.OK;
|
|
20977
|
+
}
|
|
20978
|
+
const path = parsed.positionals[0];
|
|
20979
|
+
if (!path)
|
|
20980
|
+
return fail("USAGE", "Missing FILE argument", HELP30);
|
|
19889
20981
|
const mode = parsed.positionals[1];
|
|
19890
20982
|
if (mode !== "on" && mode !== "off") {
|
|
19891
|
-
return fail("USAGE", `Expected "on" or "off", got: ${mode ?? "<nothing>"}`,
|
|
20983
|
+
return fail("USAGE", `Expected "on" or "off", got: ${mode ?? "<nothing>"}`, HELP30);
|
|
19892
20984
|
}
|
|
19893
20985
|
const view = await openOrFail(path);
|
|
19894
20986
|
if (typeof view === "number")
|
|
@@ -19940,7 +21032,7 @@ async function run27(args) {
|
|
|
19940
21032
|
});
|
|
19941
21033
|
return EXIT.OK;
|
|
19942
21034
|
}
|
|
19943
|
-
var
|
|
21035
|
+
var HELP30 = `docx track-changes \u2014 toggle the document's tracked-changes mode
|
|
19944
21036
|
|
|
19945
21037
|
Usage:
|
|
19946
21038
|
docx track-changes FILE on|off [options]
|
|
@@ -19959,7 +21051,7 @@ Examples:
|
|
|
19959
21051
|
docx track-changes doc.docx on
|
|
19960
21052
|
docx track-changes doc.docx off
|
|
19961
21053
|
`, SETTINGS_PART = "word/settings.xml", SETTINGS_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings", SETTINGS_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml", NS_W2 = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
|
|
19962
|
-
var
|
|
21054
|
+
var init_toggle = __esm(() => {
|
|
19963
21055
|
init_core();
|
|
19964
21056
|
init_jsx();
|
|
19965
21057
|
init_package();
|
|
@@ -19968,58 +21060,126 @@ var init_track_changes2 = __esm(() => {
|
|
|
19968
21060
|
init_jsx_dev_runtime();
|
|
19969
21061
|
});
|
|
19970
21062
|
|
|
21063
|
+
// src/cli/track-changes/index.ts
|
|
21064
|
+
var exports_track_changes = {};
|
|
21065
|
+
__export(exports_track_changes, {
|
|
21066
|
+
run: () => run31
|
|
21067
|
+
});
|
|
21068
|
+
async function run31(args) {
|
|
21069
|
+
const first = args[0];
|
|
21070
|
+
if (first === "--help" || first === "-h" || first === "help") {
|
|
21071
|
+
await writeStdout(HELP31);
|
|
21072
|
+
return 0;
|
|
21073
|
+
}
|
|
21074
|
+
if (!first) {
|
|
21075
|
+
return fail("USAGE", "Missing arguments", HELP31);
|
|
21076
|
+
}
|
|
21077
|
+
if (first === "list") {
|
|
21078
|
+
const module_2 = await Promise.resolve().then(() => (init_list4(), exports_list4));
|
|
21079
|
+
return module_2.run(args.slice(1));
|
|
21080
|
+
}
|
|
21081
|
+
if (first === "accept") {
|
|
21082
|
+
const module_2 = await Promise.resolve().then(() => (init_accept(), exports_accept));
|
|
21083
|
+
return module_2.run(args.slice(1));
|
|
21084
|
+
}
|
|
21085
|
+
if (first === "reject") {
|
|
21086
|
+
const module_2 = await Promise.resolve().then(() => (init_reject(), exports_reject));
|
|
21087
|
+
return module_2.run(args.slice(1));
|
|
21088
|
+
}
|
|
21089
|
+
const module_ = await Promise.resolve().then(() => (init_toggle(), exports_toggle));
|
|
21090
|
+
return module_.run(args);
|
|
21091
|
+
}
|
|
21092
|
+
var HELP31 = `docx track-changes \u2014 manage tracked-changes
|
|
21093
|
+
|
|
21094
|
+
Usage:
|
|
21095
|
+
docx track-changes FILE on|off [options]
|
|
21096
|
+
docx track-changes list FILE [options]
|
|
21097
|
+
docx track-changes accept FILE (--at tcN | --all) [options]
|
|
21098
|
+
docx track-changes reject FILE (--at tcN | --all) [options]
|
|
21099
|
+
|
|
21100
|
+
Verbs:
|
|
21101
|
+
on Set <w:trackChanges/> in word/settings.xml
|
|
21102
|
+
off Remove <w:trackChanges/>
|
|
21103
|
+
list Inventory every <w:ins>/<w:del>/<w:moveFrom>/<w:moveTo> with
|
|
21104
|
+
id, kind, author, date, location
|
|
21105
|
+
accept Accept tracked changes \u2014 additive wrappers (<w:ins>, <w:moveTo>)
|
|
21106
|
+
unwrap; subtractive wrappers (<w:del>, <w:moveFrom>) are removed
|
|
21107
|
+
reject Reject tracked changes \u2014 additive wrappers are removed;
|
|
21108
|
+
subtractive wrappers unwrap (with <w:delText> \u2192 <w:t> rename)
|
|
21109
|
+
|
|
21110
|
+
When tracking is on, this CLI's insert/edit/delete/replace commands
|
|
21111
|
+
emit <w:ins>/<w:del> markers (attributed via --author or $DOCX_AUTHOR).
|
|
21112
|
+
moveFrom/moveTo are read, listed, and accept/reject independently \u2014 we
|
|
21113
|
+
don't emit them ourselves (Word does that interactively).
|
|
21114
|
+
Accept/reject themselves bypass tracking \u2014 they're doc surgery, not edits.
|
|
21115
|
+
|
|
21116
|
+
Run "docx track-changes <verb> --help" for verb-specific help.
|
|
21117
|
+
`;
|
|
21118
|
+
var init_track_changes2 = __esm(() => {
|
|
21119
|
+
init_respond();
|
|
21120
|
+
});
|
|
21121
|
+
|
|
19971
21122
|
// src/cli/wc/count.ts
|
|
21123
|
+
function textFor(options) {
|
|
21124
|
+
if (options.view === "accepted")
|
|
21125
|
+
return paragraphTextAccepted;
|
|
21126
|
+
if (options.view === "baseline")
|
|
21127
|
+
return paragraphTextBaseline;
|
|
21128
|
+
return paragraphText;
|
|
21129
|
+
}
|
|
19972
21130
|
function countWords(text) {
|
|
19973
21131
|
const matches = text.match(/\S+/g);
|
|
19974
21132
|
return matches?.length ?? 0;
|
|
19975
21133
|
}
|
|
19976
|
-
function countWordsInBlocks(blocks) {
|
|
21134
|
+
function countWordsInBlocks(blocks, options = {}) {
|
|
21135
|
+
const text = textFor(options);
|
|
19977
21136
|
let total = 0;
|
|
19978
21137
|
for (const block of blocks) {
|
|
19979
21138
|
if (block.type === "paragraph") {
|
|
19980
|
-
total += countWords(
|
|
21139
|
+
total += countWords(text(block));
|
|
19981
21140
|
} else if (block.type === "table") {
|
|
19982
21141
|
for (const row of block.rows) {
|
|
19983
21142
|
for (const cell of row.cells) {
|
|
19984
|
-
total += countWordsInBlocks(cell.blocks);
|
|
21143
|
+
total += countWordsInBlocks(cell.blocks, options);
|
|
19985
21144
|
}
|
|
19986
21145
|
}
|
|
19987
21146
|
}
|
|
19988
21147
|
}
|
|
19989
21148
|
return total;
|
|
19990
21149
|
}
|
|
19991
|
-
function countWordsInParagraphSpan(paragraph, start, end) {
|
|
19992
|
-
const text =
|
|
21150
|
+
function countWordsInParagraphSpan(paragraph, start, end, options = {}) {
|
|
21151
|
+
const text = textFor(options)(paragraph);
|
|
19993
21152
|
const clampedEnd = Math.min(Math.max(end, 0), text.length);
|
|
19994
21153
|
const clampedStart = Math.min(Math.max(start, 0), clampedEnd);
|
|
19995
21154
|
return countWords(text.slice(clampedStart, clampedEnd));
|
|
19996
21155
|
}
|
|
19997
|
-
function countWordsInRange(paragraphsInOrder, startBlockId, startOffset, endBlockId, endOffset) {
|
|
21156
|
+
function countWordsInRange(paragraphsInOrder, startBlockId, startOffset, endBlockId, endOffset, options = {}) {
|
|
19998
21157
|
const startIndex = paragraphsInOrder.findIndex((p) => p.id === startBlockId);
|
|
19999
21158
|
const endIndex = paragraphsInOrder.findIndex((p) => p.id === endBlockId);
|
|
20000
21159
|
if (startIndex === -1 || endIndex === -1)
|
|
20001
21160
|
return 0;
|
|
20002
21161
|
if (endIndex < startIndex)
|
|
20003
21162
|
return 0;
|
|
21163
|
+
const text = textFor(options);
|
|
20004
21164
|
if (startIndex === endIndex) {
|
|
20005
21165
|
const paragraph = paragraphsInOrder[startIndex];
|
|
20006
21166
|
if (!paragraph)
|
|
20007
21167
|
return 0;
|
|
20008
|
-
return countWordsInParagraphSpan(paragraph, startOffset, endOffset);
|
|
21168
|
+
return countWordsInParagraphSpan(paragraph, startOffset, endOffset, options);
|
|
20009
21169
|
}
|
|
20010
21170
|
let total = 0;
|
|
20011
21171
|
const first = paragraphsInOrder[startIndex];
|
|
20012
21172
|
if (first) {
|
|
20013
|
-
total += countWordsInParagraphSpan(first, startOffset,
|
|
21173
|
+
total += countWordsInParagraphSpan(first, startOffset, text(first).length, options);
|
|
20014
21174
|
}
|
|
20015
21175
|
for (let index = startIndex + 1;index < endIndex; index++) {
|
|
20016
21176
|
const middle = paragraphsInOrder[index];
|
|
20017
21177
|
if (middle)
|
|
20018
|
-
total += countWords(
|
|
21178
|
+
total += countWords(text(middle));
|
|
20019
21179
|
}
|
|
20020
21180
|
const last = paragraphsInOrder[endIndex];
|
|
20021
21181
|
if (last)
|
|
20022
|
-
total += countWordsInParagraphSpan(last, 0, endOffset);
|
|
21182
|
+
total += countWordsInParagraphSpan(last, 0, endOffset, options);
|
|
20023
21183
|
return total;
|
|
20024
21184
|
}
|
|
20025
21185
|
var init_count = __esm(() => {
|
|
@@ -20029,41 +21189,51 @@ var init_count = __esm(() => {
|
|
|
20029
21189
|
// src/cli/wc/index.ts
|
|
20030
21190
|
var exports_wc = {};
|
|
20031
21191
|
__export(exports_wc, {
|
|
20032
|
-
run: () =>
|
|
21192
|
+
run: () => run32
|
|
20033
21193
|
});
|
|
20034
|
-
import { parseArgs as
|
|
20035
|
-
async function
|
|
21194
|
+
import { parseArgs as parseArgs26 } from "util";
|
|
21195
|
+
async function run32(args) {
|
|
20036
21196
|
let parsed;
|
|
20037
21197
|
try {
|
|
20038
|
-
parsed =
|
|
21198
|
+
parsed = parseArgs26({
|
|
20039
21199
|
args,
|
|
20040
21200
|
allowPositionals: true,
|
|
20041
21201
|
options: {
|
|
21202
|
+
accepted: { type: "boolean" },
|
|
21203
|
+
baseline: { type: "boolean" },
|
|
20042
21204
|
help: { type: "boolean", short: "h" }
|
|
20043
21205
|
}
|
|
20044
21206
|
});
|
|
20045
21207
|
} catch (parseError) {
|
|
20046
21208
|
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
20047
|
-
return fail("USAGE", message,
|
|
21209
|
+
return fail("USAGE", message, HELP32);
|
|
20048
21210
|
}
|
|
20049
21211
|
if (parsed.values.help) {
|
|
20050
|
-
await writeStdout(
|
|
21212
|
+
await writeStdout(HELP32);
|
|
20051
21213
|
return EXIT.OK;
|
|
20052
21214
|
}
|
|
20053
21215
|
const path = parsed.positionals[0];
|
|
20054
21216
|
const locatorInput = parsed.positionals[1];
|
|
20055
21217
|
if (!path)
|
|
20056
|
-
return fail("USAGE", "Missing FILE argument",
|
|
20057
|
-
const
|
|
20058
|
-
|
|
20059
|
-
|
|
21218
|
+
return fail("USAGE", "Missing FILE argument", HELP32);
|
|
21219
|
+
const wantAccepted = Boolean(parsed.values.accepted);
|
|
21220
|
+
const wantBaseline = Boolean(parsed.values.baseline);
|
|
21221
|
+
if (wantAccepted && wantBaseline) {
|
|
21222
|
+
return fail("USAGE", "--accepted and --baseline are mutually exclusive", HELP32);
|
|
21223
|
+
}
|
|
21224
|
+
const view = wantAccepted ? "accepted" : wantBaseline ? "baseline" : "current";
|
|
21225
|
+
const pickText = paragraphTextFor(view);
|
|
21226
|
+
const docView = await openOrFail(path);
|
|
21227
|
+
if (typeof docView === "number")
|
|
21228
|
+
return docView;
|
|
20060
21229
|
if (!locatorInput) {
|
|
20061
21230
|
await respond({
|
|
20062
21231
|
ok: true,
|
|
20063
21232
|
operation: "wc",
|
|
20064
21233
|
path,
|
|
20065
21234
|
scope: "document",
|
|
20066
|
-
|
|
21235
|
+
view,
|
|
21236
|
+
words: countWordsInBlocks(docView.doc.blocks, { view })
|
|
20067
21237
|
});
|
|
20068
21238
|
return EXIT.OK;
|
|
20069
21239
|
}
|
|
@@ -20076,22 +21246,23 @@ async function run28(args) {
|
|
|
20076
21246
|
}
|
|
20077
21247
|
throw error;
|
|
20078
21248
|
}
|
|
20079
|
-
if (locator.kind === "comment" || locator.kind === "image") {
|
|
21249
|
+
if (locator.kind === "comment" || locator.kind === "image" || locator.kind === "hyperlink" || locator.kind === "trackedChange") {
|
|
20080
21250
|
return fail("USAGE", `Locator ${locatorInput} addresses a ${locator.kind}, not text`, "wc accepts paragraph, span, range, table, and cell locators.");
|
|
20081
21251
|
}
|
|
20082
|
-
const blocks =
|
|
21252
|
+
const blocks = docView.doc.blocks;
|
|
20083
21253
|
if (locator.kind === "block") {
|
|
20084
21254
|
const block = findBlockById(blocks, locator.blockId);
|
|
20085
21255
|
if (!block) {
|
|
20086
21256
|
return fail("BLOCK_NOT_FOUND", `Block not found: ${locator.blockId}`);
|
|
20087
21257
|
}
|
|
20088
|
-
const words = block.type === "paragraph" ? countWords(
|
|
21258
|
+
const words = block.type === "paragraph" ? countWords(pickText(block)) : block.type === "table" ? countWordsInBlocks([block], { view }) : 0;
|
|
20089
21259
|
await respond({
|
|
20090
21260
|
ok: true,
|
|
20091
21261
|
operation: "wc",
|
|
20092
21262
|
path,
|
|
20093
21263
|
locator: locatorInput,
|
|
20094
21264
|
scope: block.type,
|
|
21265
|
+
view,
|
|
20095
21266
|
words
|
|
20096
21267
|
});
|
|
20097
21268
|
return EXIT.OK;
|
|
@@ -20107,7 +21278,10 @@ async function run28(args) {
|
|
|
20107
21278
|
path,
|
|
20108
21279
|
locator: locatorInput,
|
|
20109
21280
|
scope: "paragraphSpan",
|
|
20110
|
-
|
|
21281
|
+
view,
|
|
21282
|
+
words: countWordsInParagraphSpan(block, locator.start, locator.end, {
|
|
21283
|
+
view
|
|
21284
|
+
})
|
|
20111
21285
|
});
|
|
20112
21286
|
return EXIT.OK;
|
|
20113
21287
|
}
|
|
@@ -20127,7 +21301,8 @@ async function run28(args) {
|
|
|
20127
21301
|
path,
|
|
20128
21302
|
locator: locatorInput,
|
|
20129
21303
|
scope: "range",
|
|
20130
|
-
|
|
21304
|
+
view,
|
|
21305
|
+
words: countWordsInRange(paragraphs, locator.start.blockId, locator.start.offset, locator.end.blockId, locator.end.offset, { view })
|
|
20131
21306
|
});
|
|
20132
21307
|
return EXIT.OK;
|
|
20133
21308
|
}
|
|
@@ -20144,7 +21319,8 @@ async function run28(args) {
|
|
|
20144
21319
|
path,
|
|
20145
21320
|
locator: locatorInput,
|
|
20146
21321
|
scope: "cell",
|
|
20147
|
-
|
|
21322
|
+
view,
|
|
21323
|
+
words: countWordsInBlocks(cellBlocks, { view })
|
|
20148
21324
|
});
|
|
20149
21325
|
return EXIT.OK;
|
|
20150
21326
|
}
|
|
@@ -20157,13 +21333,14 @@ async function run28(args) {
|
|
|
20157
21333
|
if (!block || block.type !== "paragraph") {
|
|
20158
21334
|
return fail("BLOCK_NOT_FOUND", `Paragraph not found: ${composedId}`);
|
|
20159
21335
|
}
|
|
20160
|
-
const words = locator.inner.kind === "blockSpan" ? countWordsInParagraphSpan(block, locator.inner.start, locator.inner.end) : countWords(
|
|
21336
|
+
const words = locator.inner.kind === "blockSpan" ? countWordsInParagraphSpan(block, locator.inner.start, locator.inner.end, { view }) : countWords(pickText(block));
|
|
20161
21337
|
await respond({
|
|
20162
21338
|
ok: true,
|
|
20163
21339
|
operation: "wc",
|
|
20164
21340
|
path,
|
|
20165
21341
|
locator: locatorInput,
|
|
20166
21342
|
scope: locator.inner.kind === "blockSpan" ? "paragraphSpan" : "paragraph",
|
|
21343
|
+
view,
|
|
20167
21344
|
words
|
|
20168
21345
|
});
|
|
20169
21346
|
return EXIT.OK;
|
|
@@ -20182,7 +21359,14 @@ function findCellBlocks(blocks, locator) {
|
|
|
20182
21359
|
return null;
|
|
20183
21360
|
return cell.blocks;
|
|
20184
21361
|
}
|
|
20185
|
-
|
|
21362
|
+
function paragraphTextFor(view) {
|
|
21363
|
+
if (view === "accepted")
|
|
21364
|
+
return paragraphTextAccepted;
|
|
21365
|
+
if (view === "baseline")
|
|
21366
|
+
return paragraphTextBaseline;
|
|
21367
|
+
return paragraphText;
|
|
21368
|
+
}
|
|
21369
|
+
var HELP32 = `docx wc \u2014 count words in a document or a locator-addressed slice
|
|
20186
21370
|
|
|
20187
21371
|
Usage:
|
|
20188
21372
|
docx wc FILE [LOCATOR] [options]
|
|
@@ -20197,13 +21381,20 @@ Locators (optional; default: whole document):
|
|
|
20197
21381
|
tN:rRcC:pK:S-E span within a cell paragraph
|
|
20198
21382
|
|
|
20199
21383
|
Options:
|
|
21384
|
+
--accepted Count the accepted view: skip subtractive wrappers
|
|
21385
|
+
(<w:del>, <w:moveFrom>); keep additive wrappers
|
|
21386
|
+
(<w:ins>, <w:moveTo>) as plain text. Mirrors
|
|
21387
|
+
"docx read --markdown --accepted".
|
|
21388
|
+
--baseline Count the baseline view: skip additive wrappers
|
|
21389
|
+
(<w:ins>, <w:moveTo>); keep subtractive wrappers
|
|
21390
|
+
(<w:del>, <w:moveFrom>) as plain text \u2014 i.e., the doc as
|
|
21391
|
+
it was before any tracked changes were made.
|
|
20200
21392
|
-h, --help show this help
|
|
20201
21393
|
|
|
20202
21394
|
Counting is whitespace-segmented (\\S+) over the joined paragraph text. Hidden
|
|
20203
|
-
content like images/breaks/tabs contributes no words.
|
|
20204
|
-
|
|
20205
|
-
|
|
20206
|
-
"accepted" view.
|
|
21395
|
+
content like images/breaks/tabs contributes no words. By default, every
|
|
21396
|
+
tracked-change wrapper's text counts (they're all on disk); pass --accepted
|
|
21397
|
+
or --baseline (mutually exclusive) to count a tracked-change-aware slice.
|
|
20207
21398
|
|
|
20208
21399
|
Examples:
|
|
20209
21400
|
docx wc doc.docx
|
|
@@ -20220,7 +21411,7 @@ var init_wc = __esm(() => {
|
|
|
20220
21411
|
// package.json
|
|
20221
21412
|
var package_default = {
|
|
20222
21413
|
name: "bun-docx",
|
|
20223
|
-
version: "0.
|
|
21414
|
+
version: "0.7.0",
|
|
20224
21415
|
description: "CLI for AI agents (Claude, Codex) to read, edit, and comment on .docx files with full format fidelity.",
|
|
20225
21416
|
keywords: [
|
|
20226
21417
|
"docx",
|
|
@@ -20299,10 +21490,11 @@ Commands:
|
|
|
20299
21490
|
outline FILE List headings as a hierarchical tree
|
|
20300
21491
|
comments \u2026 Add, reply, resolve, delete, list comments
|
|
20301
21492
|
images \u2026 Extract, replace, list images
|
|
20302
|
-
hyperlinks \u2026
|
|
20303
|
-
track-changes FILE on|off
|
|
21493
|
+
hyperlinks \u2026 Add, list, replace, delete hyperlinks
|
|
21494
|
+
track-changes \u2026 Toggle (FILE on|off), list / accept / reject changes
|
|
20304
21495
|
info \u2026 Reference material (schema, locators)
|
|
20305
21496
|
|
|
21497
|
+
It is highly recommended to agents to run "docx info locators" to understand their capabilities.
|
|
20306
21498
|
Run "docx <command> --help" for command-specific help.
|
|
20307
21499
|
|
|
20308
21500
|
Environment:
|
|
@@ -20310,9 +21502,19 @@ Environment:
|
|
|
20310
21502
|
DOCX_CLI_NOW Override the timestamp used for tracked changes (test only)
|
|
20311
21503
|
|
|
20312
21504
|
Tracked changes:
|
|
20313
|
-
|
|
20314
|
-
FILE
|
|
20315
|
-
|
|
21505
|
+
Toggle: docx track-changes FILE on|off
|
|
21506
|
+
Inventory: docx track-changes list FILE (JSON: id, kind, author, date, blockId, text)
|
|
21507
|
+
Accept: docx track-changes accept FILE (--at tcN | --all)
|
|
21508
|
+
Reject: docx track-changes reject FILE (--at tcN | --all)
|
|
21509
|
+
|
|
21510
|
+
When <w:trackChanges/> is set, insert/edit/delete/replace automatically emit
|
|
21511
|
+
<w:ins>/<w:del> markers attributed via --author (or $DOCX_AUTHOR, or "docx-cli").
|
|
21512
|
+
|
|
21513
|
+
"docx read --markdown" surfaces them as CriticMarkup:
|
|
21514
|
+
{++inserted++}[^tcN] {--deleted--}[^tcN]
|
|
21515
|
+
with a [^tcN]: definition appendix. Switch view with --accepted (post-accept:
|
|
21516
|
+
drop del, ins as plain) or --baseline (pre-change: drop ins, del as plain).
|
|
21517
|
+
"docx wc" mirrors the same --accepted / --baseline flags.
|
|
20316
21518
|
`;
|
|
20317
21519
|
async function printTopHelp() {
|
|
20318
21520
|
await writeStdout(TOP_HELP);
|