bun-docx 0.6.1 → 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 +19 -11
- package/dist/index.js +1200 -198
- 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;
|
|
13595
13604
|
continue;
|
|
13596
13605
|
}
|
|
13597
|
-
|
|
13606
|
+
if (SINGLE_CHAR_TAGS.has(child.tag)) {
|
|
13607
|
+
if (offset >= start && offset < end) {
|
|
13608
|
+
sliced.children.push(child.clone());
|
|
13609
|
+
}
|
|
13610
|
+
offset += 1;
|
|
13611
|
+
continue;
|
|
13612
|
+
}
|
|
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
|
-
|
|
13992
|
-
}
|
|
13993
|
-
}
|
|
13994
|
-
let combinedText = "";
|
|
13995
|
-
for (const child of node.children) {
|
|
13996
|
-
if (child.tag === "w:t" || child.tag === "w:delText") {
|
|
13997
|
-
combinedText += child.collectText();
|
|
14404
|
+
out.push({ type: "footnoteRef", kind: "endnote", id: `en${id}` });
|
|
13998
14405
|
}
|
|
13999
14406
|
}
|
|
14000
|
-
|
|
14001
|
-
|
|
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
|
|
|
@@ -14658,7 +15095,7 @@ function convertTextToDelText(node) {
|
|
|
14658
15095
|
function computeMaxRevisionId(view) {
|
|
14659
15096
|
let max = -1;
|
|
14660
15097
|
walkXml(view.documentTree, (node) => {
|
|
14661
|
-
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")
|
|
14662
15099
|
return;
|
|
14663
15100
|
const idAttr = node.getAttribute("w:id");
|
|
14664
15101
|
if (!idAttr)
|
|
@@ -14946,6 +15383,7 @@ function exitCodeFor(code) {
|
|
|
14946
15383
|
case "COMMENT_NOT_FOUND":
|
|
14947
15384
|
case "IMAGE_NOT_FOUND":
|
|
14948
15385
|
case "HYPERLINK_NOT_FOUND":
|
|
15386
|
+
case "TRACKED_CHANGE_NOT_FOUND":
|
|
14949
15387
|
case "MATCH_NOT_FOUND":
|
|
14950
15388
|
return EXIT.NOT_FOUND;
|
|
14951
15389
|
case "NOT_A_ZIP":
|
|
@@ -15065,18 +15503,7 @@ function ensureCommentsExtPart(view) {
|
|
|
15065
15503
|
return root;
|
|
15066
15504
|
}
|
|
15067
15505
|
function paragraphTextLength(paragraph) {
|
|
15068
|
-
return
|
|
15069
|
-
}
|
|
15070
|
-
function sumTextLength(children) {
|
|
15071
|
-
let total = 0;
|
|
15072
|
-
for (const child of children) {
|
|
15073
|
-
if (child.tag === "w:r")
|
|
15074
|
-
total += runTextLength(child);
|
|
15075
|
-
else if (child.tag === "w:ins" || child.tag === "w:del" || child.tag === "w:hyperlink") {
|
|
15076
|
-
total += sumTextLength(child.children);
|
|
15077
|
-
}
|
|
15078
|
-
}
|
|
15079
|
-
return total;
|
|
15506
|
+
return sumRunBearingTextLength(paragraph.children);
|
|
15080
15507
|
}
|
|
15081
15508
|
function addCommentMarkersToParagraph(paragraph, commentId, span) {
|
|
15082
15509
|
const total = paragraphTextLength(paragraph);
|
|
@@ -15121,7 +15548,7 @@ function addCommentMarkersAroundRun(paragraph, target, commentId) {
|
|
|
15121
15548
|
children.splice(index, 1, commentRangeStartMarker(commentId), target, commentRangeEndMarker(commentId), commentReferenceRun(commentId));
|
|
15122
15549
|
return true;
|
|
15123
15550
|
}
|
|
15124
|
-
if (child && (child.tag
|
|
15551
|
+
if (child && isRunBearingWrapper(child.tag)) {
|
|
15125
15552
|
if (walk(child))
|
|
15126
15553
|
return true;
|
|
15127
15554
|
}
|
|
@@ -15137,7 +15564,7 @@ function findElementOffsetsInParagraph(paragraph, target) {
|
|
|
15137
15564
|
for (const child of children) {
|
|
15138
15565
|
if (child === target) {
|
|
15139
15566
|
const start = cursor;
|
|
15140
|
-
cursor +=
|
|
15567
|
+
cursor += sumRunBearingTextLength([child]);
|
|
15141
15568
|
result = { start, end: cursor };
|
|
15142
15569
|
return true;
|
|
15143
15570
|
}
|
|
@@ -15145,7 +15572,7 @@ function findElementOffsetsInParagraph(paragraph, target) {
|
|
|
15145
15572
|
cursor += runTextLength(child);
|
|
15146
15573
|
continue;
|
|
15147
15574
|
}
|
|
15148
|
-
if (child.tag
|
|
15575
|
+
if (isRunBearingWrapper(child.tag)) {
|
|
15149
15576
|
if (walk(child.children))
|
|
15150
15577
|
return true;
|
|
15151
15578
|
}
|
|
@@ -15286,7 +15713,7 @@ function walkAndPlace(children, pending, state) {
|
|
|
15286
15713
|
state.offset = runEnd;
|
|
15287
15714
|
continue;
|
|
15288
15715
|
}
|
|
15289
|
-
if (child.tag
|
|
15716
|
+
if (isRunBearingWrapper(child.tag)) {
|
|
15290
15717
|
flushAtCurrentOffset(result, pending, state);
|
|
15291
15718
|
const innerChildren = walkAndPlace(child.children, pending, state);
|
|
15292
15719
|
const wrapper = new XmlNode2(child.tag, { ...child.attributes });
|
|
@@ -16794,10 +17221,9 @@ function trackedChangesOverlapping(paragraph, start, end) {
|
|
|
16794
17221
|
const change = run10.trackedChange;
|
|
16795
17222
|
if (!change)
|
|
16796
17223
|
continue;
|
|
16797
|
-
|
|
16798
|
-
if (seen.has(key))
|
|
17224
|
+
if (seen.has(change.id))
|
|
16799
17225
|
continue;
|
|
16800
|
-
seen.add(
|
|
17226
|
+
seen.add(change.id);
|
|
16801
17227
|
out.push(change);
|
|
16802
17228
|
}
|
|
16803
17229
|
return out;
|
|
@@ -16955,20 +17381,8 @@ function wrapSpanInHyperlink(paragraph, span, relationshipId) {
|
|
|
16955
17381
|
}
|
|
16956
17382
|
continue;
|
|
16957
17383
|
}
|
|
16958
|
-
if (child.tag
|
|
16959
|
-
const
|
|
16960
|
-
const hyperlinkStart = offset;
|
|
16961
|
-
const hyperlinkEnd = offset + hyperlinkLength;
|
|
16962
|
-
offset = hyperlinkEnd;
|
|
16963
|
-
if (hyperlinkEnd <= span.start || hyperlinkStart >= span.end) {
|
|
16964
|
-
placeWrapper();
|
|
16965
|
-
newChildren.push(child);
|
|
16966
|
-
continue;
|
|
16967
|
-
}
|
|
16968
|
-
throw new HyperlinkWrapError(`Span ${span.start}-${span.end} overlaps an existing hyperlink at ${hyperlinkStart}-${hyperlinkEnd}; nested hyperlinks are not allowed`);
|
|
16969
|
-
}
|
|
16970
|
-
if (child.tag === "w:ins" || child.tag === "w:del") {
|
|
16971
|
-
const innerLength = sumInnerRunLengths(child);
|
|
17384
|
+
if (isRunBearingWrapper(child.tag)) {
|
|
17385
|
+
const innerLength = sumRunBearingTextLength(child.children);
|
|
16972
17386
|
const wrapperStart = offset;
|
|
16973
17387
|
const wrapperEnd = offset + innerLength;
|
|
16974
17388
|
offset = wrapperEnd;
|
|
@@ -16977,27 +17391,28 @@ function wrapSpanInHyperlink(paragraph, span, relationshipId) {
|
|
|
16977
17391
|
newChildren.push(child);
|
|
16978
17392
|
continue;
|
|
16979
17393
|
}
|
|
16980
|
-
throw new HyperlinkWrapError(
|
|
17394
|
+
throw new HyperlinkWrapError(messageForOverlap(child.tag, span));
|
|
16981
17395
|
}
|
|
16982
17396
|
newChildren.push(child);
|
|
16983
17397
|
}
|
|
16984
17398
|
placeWrapper();
|
|
16985
17399
|
paragraph.children = newChildren;
|
|
16986
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
|
+
}
|
|
16987
17410
|
function hyperlinkWrapper(relationshipId, runs) {
|
|
16988
17411
|
return /* @__PURE__ */ jsxDEV(w.hyperlink, {
|
|
16989
17412
|
"r:id": relationshipId,
|
|
16990
17413
|
children: runs
|
|
16991
17414
|
}, undefined, false, undefined, this);
|
|
16992
17415
|
}
|
|
16993
|
-
function sumInnerRunLengths(wrapper) {
|
|
16994
|
-
let total = 0;
|
|
16995
|
-
for (const inner of wrapper.children) {
|
|
16996
|
-
if (inner.tag === "w:r")
|
|
16997
|
-
total += runTextLength(inner);
|
|
16998
|
-
}
|
|
16999
|
-
return total;
|
|
17000
|
-
}
|
|
17001
17416
|
var HyperlinkWrapError;
|
|
17002
17417
|
var init_wrap = __esm(() => {
|
|
17003
17418
|
init_jsx();
|
|
@@ -17131,7 +17546,9 @@ Optional:
|
|
|
17131
17546
|
-h, --help Show this help
|
|
17132
17547
|
|
|
17133
17548
|
The span must lie inside a single paragraph and must not overlap an existing
|
|
17134
|
-
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.
|
|
17135
17552
|
|
|
17136
17553
|
When track-changes is on, an audit comment is anchored to the wrapped span
|
|
17137
17554
|
since OOXML has no native tracked-change form for hyperlink edits.
|
|
@@ -18168,12 +18585,22 @@ export type Footnote = {
|
|
|
18168
18585
|
};
|
|
18169
18586
|
|
|
18170
18587
|
export type TrackedChange = {
|
|
18171
|
-
|
|
18588
|
+
id: string;
|
|
18589
|
+
kind: TrackedChangeKind;
|
|
18172
18590
|
author: string;
|
|
18173
18591
|
date: string;
|
|
18174
18592
|
revisionId: string;
|
|
18175
18593
|
};
|
|
18176
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
|
+
|
|
18177
18604
|
export type Comment = {
|
|
18178
18605
|
id: string;
|
|
18179
18606
|
author: string;
|
|
@@ -18330,9 +18757,10 @@ var init_schema = __esm(() => {
|
|
|
18330
18757
|
comments: { type: "array", items: { type: "string" } },
|
|
18331
18758
|
trackedChange: {
|
|
18332
18759
|
type: "object",
|
|
18333
|
-
required: ["kind", "author", "date", "revisionId"],
|
|
18760
|
+
required: ["id", "kind", "author", "date", "revisionId"],
|
|
18334
18761
|
properties: {
|
|
18335
|
-
|
|
18762
|
+
id: { type: "string" },
|
|
18763
|
+
kind: { enum: ["ins", "del", "moveFrom", "moveTo"] },
|
|
18336
18764
|
author: { type: "string" },
|
|
18337
18765
|
date: { type: "string" },
|
|
18338
18766
|
revisionId: { type: "string" }
|
|
@@ -18538,6 +18966,8 @@ Entity locators:
|
|
|
18538
18966
|
cN Comment id (e.g., c0)
|
|
18539
18967
|
imgN Image id (e.g., img2)
|
|
18540
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
|
|
18541
18971
|
tN:rRcC Cell at row R, column C of table tN
|
|
18542
18972
|
|
|
18543
18973
|
Examples:
|
|
@@ -18547,6 +18977,7 @@ Examples:
|
|
|
18547
18977
|
c1 -> comment c1
|
|
18548
18978
|
img0 -> image img0
|
|
18549
18979
|
link0 -> hyperlink link0
|
|
18980
|
+
tc0 -> first tracked change in the document
|
|
18550
18981
|
t0:r1c2 -> cell at row 1, col 2 of table t0
|
|
18551
18982
|
t0:r1c2:p0 -> first paragraph of that cell
|
|
18552
18983
|
t0:r1c2:p0:5-10 -> chars 5..10 of that paragraph
|
|
@@ -18580,6 +19011,7 @@ var init_locators2 = __esm(() => {
|
|
|
18580
19011
|
comment: { syntax: "cN", example: "c1" },
|
|
18581
19012
|
image: { syntax: "imgN", example: "img0" },
|
|
18582
19013
|
hyperlink: { syntax: "linkN", example: "link0" },
|
|
19014
|
+
trackedChange: { syntax: "tcN", example: "tc0" },
|
|
18583
19015
|
cell: { syntax: "tN:rRcC", example: "t0:r1c2" },
|
|
18584
19016
|
nestedCell: { syntax: "tN:rRcC:pK", example: "t0:r1c2:p0" }
|
|
18585
19017
|
},
|
|
@@ -19001,7 +19433,8 @@ function renderMarkdown(doc, options = {}) {
|
|
|
19001
19433
|
options,
|
|
19002
19434
|
commentIndex,
|
|
19003
19435
|
referencedFootnoteIds: new Set,
|
|
19004
|
-
referencedEndnoteIds: new Set
|
|
19436
|
+
referencedEndnoteIds: new Set,
|
|
19437
|
+
referencedTrackedChanges: new Map
|
|
19005
19438
|
};
|
|
19006
19439
|
const parts = [];
|
|
19007
19440
|
for (const block of blocks) {
|
|
@@ -19021,6 +19454,9 @@ function renderMarkdown(doc, options = {}) {
|
|
|
19021
19454
|
const endnoteDefs = renderNoteDefinitions(doc.endnotes, ctx.referencedEndnoteIds);
|
|
19022
19455
|
if (endnoteDefs.length > 0)
|
|
19023
19456
|
definitions.push(endnoteDefs);
|
|
19457
|
+
const trackedChangeDefs = renderTrackedChangeFootnotes(ctx.referencedTrackedChanges);
|
|
19458
|
+
if (trackedChangeDefs.length > 0)
|
|
19459
|
+
definitions.push(trackedChangeDefs);
|
|
19024
19460
|
if (definitions.length > 0)
|
|
19025
19461
|
parts.push(definitions.join(`
|
|
19026
19462
|
`));
|
|
@@ -19038,8 +19474,18 @@ function emptyCommentIndex() {
|
|
|
19038
19474
|
orderedIds: []
|
|
19039
19475
|
};
|
|
19040
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
|
+
}
|
|
19041
19487
|
function buildCommentIndex(blocks, options) {
|
|
19042
|
-
const
|
|
19488
|
+
const view = options.view ?? "current";
|
|
19043
19489
|
const lastSlot = new Map;
|
|
19044
19490
|
const spanText = new Map;
|
|
19045
19491
|
const orderedIds = [];
|
|
@@ -19047,7 +19493,7 @@ function buildCommentIndex(blocks, options) {
|
|
|
19047
19493
|
paragraph.runs.forEach((run25, index) => {
|
|
19048
19494
|
if (run25.type !== "text")
|
|
19049
19495
|
return;
|
|
19050
|
-
if (!
|
|
19496
|
+
if (!isRunVisible(run25, view))
|
|
19051
19497
|
return;
|
|
19052
19498
|
for (const commentId of run25.comments ?? []) {
|
|
19053
19499
|
if (!spanText.has(commentId))
|
|
@@ -19111,12 +19557,11 @@ function headingLevelFor(style) {
|
|
|
19111
19557
|
return parsed;
|
|
19112
19558
|
}
|
|
19113
19559
|
function renderRuns(paragraphId, runs, ctx) {
|
|
19114
|
-
const
|
|
19560
|
+
const view = ctx.options.view ?? "current";
|
|
19115
19561
|
const visibleEntries = [];
|
|
19116
19562
|
runs.forEach((run25, index) => {
|
|
19117
|
-
if (
|
|
19563
|
+
if (run25.type === "text" && !isRunVisible(run25, view))
|
|
19118
19564
|
return;
|
|
19119
|
-
}
|
|
19120
19565
|
visibleEntries.push({ run: run25, originalIndex: index });
|
|
19121
19566
|
});
|
|
19122
19567
|
let out = "";
|
|
@@ -19139,7 +19584,15 @@ function renderRuns(paragraphId, runs, ctx) {
|
|
|
19139
19584
|
lookahead++;
|
|
19140
19585
|
}
|
|
19141
19586
|
const segment = visibleEntries.slice(cursor, lookahead);
|
|
19142
|
-
|
|
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
|
+
}
|
|
19143
19596
|
out += commentEndingsFor(paragraphId, segment, ctx.commentIndex);
|
|
19144
19597
|
cursor = lookahead;
|
|
19145
19598
|
continue;
|
|
@@ -19182,7 +19635,7 @@ function commentEndingsFor(paragraphId, segment, commentIndex) {
|
|
|
19182
19635
|
return out;
|
|
19183
19636
|
}
|
|
19184
19637
|
function sameDecoration(a2, b) {
|
|
19185
|
-
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);
|
|
19186
19639
|
}
|
|
19187
19640
|
function sameCommentSet(left, right) {
|
|
19188
19641
|
const a2 = left ?? [];
|
|
@@ -19195,7 +19648,7 @@ function sameCommentSet(left, right) {
|
|
|
19195
19648
|
}
|
|
19196
19649
|
return true;
|
|
19197
19650
|
}
|
|
19198
|
-
function renderTextSegment(runs,
|
|
19651
|
+
function renderTextSegment(runs, view) {
|
|
19199
19652
|
const text = runs.map((run25) => run25.text).join("");
|
|
19200
19653
|
if (text.length === 0)
|
|
19201
19654
|
return "";
|
|
@@ -19221,11 +19674,17 @@ function renderTextSegment(runs, showChanges) {
|
|
|
19221
19674
|
const target = first.hyperlink.url ?? `#${first.hyperlink.anchor ?? ""}`;
|
|
19222
19675
|
out = `[${out}](${target})`;
|
|
19223
19676
|
}
|
|
19224
|
-
if (
|
|
19225
|
-
|
|
19677
|
+
if (view === "current" && first.trackedChange) {
|
|
19678
|
+
const marker = criticMarkerFor(first.trackedChange.kind);
|
|
19679
|
+
out = `{${marker}${out}${marker}}[^${first.trackedChange.id}]`;
|
|
19226
19680
|
}
|
|
19227
19681
|
return out;
|
|
19228
19682
|
}
|
|
19683
|
+
function criticMarkerFor(kind) {
|
|
19684
|
+
if (kind === "ins" || kind === "moveTo")
|
|
19685
|
+
return "++";
|
|
19686
|
+
return "--";
|
|
19687
|
+
}
|
|
19229
19688
|
function colorAttrFor(value) {
|
|
19230
19689
|
if (!value)
|
|
19231
19690
|
return null;
|
|
@@ -19330,6 +19789,32 @@ function renderNoteDefinitions(notes, referenced) {
|
|
|
19330
19789
|
return lines.join(`
|
|
19331
19790
|
`);
|
|
19332
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
|
+
}
|
|
19333
19818
|
function noteIdCompare(left, right) {
|
|
19334
19819
|
return numericIdCompare(left, right, /(\d+)$/);
|
|
19335
19820
|
}
|
|
@@ -19395,6 +19880,7 @@ function blockIdForLocator(input, position) {
|
|
|
19395
19880
|
case "comment":
|
|
19396
19881
|
case "image":
|
|
19397
19882
|
case "hyperlink":
|
|
19883
|
+
case "trackedChange":
|
|
19398
19884
|
throw new MarkdownLocatorError(input, `--${position} does not accept a ${parsed.kind} locator \u2014 use a paragraph or table locator`);
|
|
19399
19885
|
}
|
|
19400
19886
|
}
|
|
@@ -19427,7 +19913,8 @@ async function run25(args) {
|
|
|
19427
19913
|
markdown: { type: "boolean" },
|
|
19428
19914
|
from: { type: "string" },
|
|
19429
19915
|
to: { type: "string" },
|
|
19430
|
-
|
|
19916
|
+
accepted: { type: "boolean" },
|
|
19917
|
+
baseline: { type: "boolean" },
|
|
19431
19918
|
comments: { type: "boolean" },
|
|
19432
19919
|
help: { type: "boolean", short: "h" }
|
|
19433
19920
|
}
|
|
@@ -19445,20 +19932,25 @@ async function run25(args) {
|
|
|
19445
19932
|
const markdown = Boolean(parsed.values.markdown);
|
|
19446
19933
|
const from = parsed.values.from;
|
|
19447
19934
|
const to = parsed.values.to;
|
|
19448
|
-
const
|
|
19935
|
+
const accepted = Boolean(parsed.values.accepted);
|
|
19936
|
+
const baseline = Boolean(parsed.values.baseline);
|
|
19449
19937
|
const showComments = Boolean(parsed.values.comments);
|
|
19450
|
-
if (!markdown && (from || to ||
|
|
19451
|
-
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);
|
|
19452
19940
|
}
|
|
19453
|
-
|
|
19454
|
-
|
|
19455
|
-
|
|
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;
|
|
19456
19948
|
if (markdown) {
|
|
19457
19949
|
try {
|
|
19458
|
-
const rendered = renderMarkdown(
|
|
19950
|
+
const rendered = renderMarkdown(docView.doc, {
|
|
19459
19951
|
from,
|
|
19460
19952
|
to,
|
|
19461
|
-
|
|
19953
|
+
view,
|
|
19462
19954
|
showComments
|
|
19463
19955
|
});
|
|
19464
19956
|
await writeStdout(rendered);
|
|
@@ -19470,8 +19962,8 @@ async function run25(args) {
|
|
|
19470
19962
|
throw err;
|
|
19471
19963
|
}
|
|
19472
19964
|
}
|
|
19473
|
-
await enrichImageHashes(
|
|
19474
|
-
await respond(
|
|
19965
|
+
await enrichImageHashes(docView);
|
|
19966
|
+
await respond(docView.doc);
|
|
19475
19967
|
return EXIT.OK;
|
|
19476
19968
|
}
|
|
19477
19969
|
var HELP25 = `docx read \u2014 print AST as JSON, or render document body as Markdown
|
|
@@ -19490,8 +19982,18 @@ Options:
|
|
|
19490
19982
|
Accepts pN, tN, tN:rRcC[:pK[:S-E]], pN:S-E, pN:S-pM:E.
|
|
19491
19983
|
Cell/span/range locators collapse to their enclosing
|
|
19492
19984
|
top-level block (the table or paragraph).
|
|
19493
|
-
--
|
|
19494
|
-
<
|
|
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).
|
|
19495
19997
|
--comments With --markdown, append [^cN] after each commented span
|
|
19496
19998
|
and emit a footnote definition for each comment at the
|
|
19497
19999
|
end of the output (author, date, body).
|
|
@@ -19501,7 +20003,8 @@ Examples:
|
|
|
19501
20003
|
docx read input.docx
|
|
19502
20004
|
docx read input.docx --markdown
|
|
19503
20005
|
docx read input.docx --markdown --from p3 --to p20
|
|
19504
|
-
docx read input.docx --markdown --
|
|
20006
|
+
docx read input.docx --markdown --accepted --comments
|
|
20007
|
+
docx read input.docx --markdown --baseline
|
|
19505
20008
|
docx read input.docx | jq '.blocks[] | select(.type == "paragraph")'
|
|
19506
20009
|
`;
|
|
19507
20010
|
var init_read2 = __esm(() => {
|
|
@@ -19538,33 +20041,25 @@ function replaceSpanInParagraph(paragraph, span, replacement, tracked) {
|
|
|
19538
20041
|
function collectRunSlots(paragraph) {
|
|
19539
20042
|
const slots = [];
|
|
19540
20043
|
let offset = 0;
|
|
19541
|
-
|
|
19542
|
-
|
|
19543
|
-
|
|
19544
|
-
|
|
19545
|
-
parent: paragraph,
|
|
19546
|
-
run: child,
|
|
19547
|
-
offsetBefore: offset,
|
|
19548
|
-
length
|
|
19549
|
-
});
|
|
19550
|
-
offset += length;
|
|
19551
|
-
continue;
|
|
19552
|
-
}
|
|
19553
|
-
if (child.tag === "w:ins" || child.tag === "w:del" || child.tag === "w:hyperlink") {
|
|
19554
|
-
for (const inner of child.children) {
|
|
19555
|
-
if (inner.tag !== "w:r")
|
|
19556
|
-
continue;
|
|
19557
|
-
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);
|
|
19558
20048
|
slots.push({
|
|
19559
|
-
parent
|
|
19560
|
-
run:
|
|
20049
|
+
parent,
|
|
20050
|
+
run: child,
|
|
19561
20051
|
offsetBefore: offset,
|
|
19562
20052
|
length
|
|
19563
20053
|
});
|
|
19564
20054
|
offset += length;
|
|
20055
|
+
continue;
|
|
20056
|
+
}
|
|
20057
|
+
if (isRunBearingWrapper(child.tag)) {
|
|
20058
|
+
walk(child, child.children);
|
|
19565
20059
|
}
|
|
19566
20060
|
}
|
|
19567
20061
|
}
|
|
20062
|
+
walk(paragraph, paragraph.children);
|
|
19568
20063
|
return slots;
|
|
19569
20064
|
}
|
|
19570
20065
|
function rebuildContainer(container, baseOffset, span, replacement, runProperties, isParagraph, tracked) {
|
|
@@ -19618,13 +20113,8 @@ function rebuildContainer(container, baseOffset, span, replacement, runPropertie
|
|
|
19618
20113
|
}
|
|
19619
20114
|
continue;
|
|
19620
20115
|
}
|
|
19621
|
-
if (isParagraph && (child.tag
|
|
19622
|
-
|
|
19623
|
-
for (const inner of child.children) {
|
|
19624
|
-
if (inner.tag === "w:r")
|
|
19625
|
-
innerLength += runTextLength(inner);
|
|
19626
|
-
}
|
|
19627
|
-
offset += innerLength;
|
|
20116
|
+
if (isParagraph && isRunBearingWrapper(child.tag)) {
|
|
20117
|
+
offset += sumRunBearingTextLength(child.children);
|
|
19628
20118
|
newChildren.push(child);
|
|
19629
20119
|
continue;
|
|
19630
20120
|
}
|
|
@@ -19685,8 +20175,8 @@ function rebuildAcrossBoundaries(paragraph, span, replacement, runProperties, tr
|
|
|
19685
20175
|
}
|
|
19686
20176
|
continue;
|
|
19687
20177
|
}
|
|
19688
|
-
if (child.tag === "w:ins" || child.tag === "w:del") {
|
|
19689
|
-
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);
|
|
19690
20180
|
const wrapperStart = offset;
|
|
19691
20181
|
const wrapperEnd = offset + innerLength;
|
|
19692
20182
|
offset = wrapperEnd;
|
|
@@ -19703,7 +20193,7 @@ function rebuildAcrossBoundaries(paragraph, span, replacement, runProperties, tr
|
|
|
19703
20193
|
continue;
|
|
19704
20194
|
}
|
|
19705
20195
|
if (child.tag === "w:hyperlink") {
|
|
19706
|
-
const innerLength =
|
|
20196
|
+
const innerLength = sumRunBearingTextLength(child.children);
|
|
19707
20197
|
const wrapperStart = offset;
|
|
19708
20198
|
const wrapperEnd = offset + innerLength;
|
|
19709
20199
|
offset = wrapperEnd;
|
|
@@ -19721,6 +20211,23 @@ function rebuildAcrossBoundaries(paragraph, span, replacement, runProperties, tr
|
|
|
19721
20211
|
});
|
|
19722
20212
|
continue;
|
|
19723
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
|
+
}
|
|
19724
20231
|
newChildren.push(child);
|
|
19725
20232
|
}
|
|
19726
20233
|
if (!placed)
|
|
@@ -19728,7 +20235,7 @@ function rebuildAcrossBoundaries(paragraph, span, replacement, runProperties, tr
|
|
|
19728
20235
|
paragraph.children = newChildren;
|
|
19729
20236
|
}
|
|
19730
20237
|
function splitWrapperAcrossSpan(wrapper, wrapperStart, span, tracked, out, placeReplacement) {
|
|
19731
|
-
const
|
|
20238
|
+
const isSubtractive = isSubtractiveTrackedChangeWrapper(wrapper.tag);
|
|
19732
20239
|
const preInner = [];
|
|
19733
20240
|
const cutInner = [];
|
|
19734
20241
|
const postInner = [];
|
|
@@ -19759,7 +20266,7 @@ function splitWrapperAcrossSpan(wrapper, wrapperStart, span, tracked, out, place
|
|
|
19759
20266
|
postInner.push(sliceRun(inner, sliceEndInRun, length));
|
|
19760
20267
|
}
|
|
19761
20268
|
const preChildren = preInner.slice();
|
|
19762
|
-
if (
|
|
20269
|
+
if (isSubtractive) {
|
|
19763
20270
|
preChildren.push(...cutInner);
|
|
19764
20271
|
} else if (tracked && cutInner.length > 0) {
|
|
19765
20272
|
for (const cutRun of cutInner)
|
|
@@ -19781,8 +20288,48 @@ function splitWrapperAcrossSpan(wrapper, wrapperStart, span, tracked, out, place
|
|
|
19781
20288
|
out.push(postWrapper);
|
|
19782
20289
|
}
|
|
19783
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
|
+
}
|
|
19784
20331
|
function splitHyperlinkAcrossSpan(wrapper, wrapperStart, span, runProperties, replacement, tracked, out, placeReplacement, markReplacementPlaced) {
|
|
19785
|
-
const wrapperEnd = wrapperStart + wrapper.children
|
|
20332
|
+
const wrapperEnd = wrapperStart + sumRunBearingTextLength(wrapper.children);
|
|
19786
20333
|
const startsInside = span.start > wrapperStart && span.start < wrapperEnd;
|
|
19787
20334
|
const preInner = [];
|
|
19788
20335
|
const postInner = [];
|
|
@@ -19836,14 +20383,6 @@ function splitHyperlinkAcrossSpan(wrapper, wrapperStart, span, runProperties, re
|
|
|
19836
20383
|
out.push(postWrapper);
|
|
19837
20384
|
}
|
|
19838
20385
|
}
|
|
19839
|
-
function sumInnerRunLengths2(wrapper) {
|
|
19840
|
-
let total = 0;
|
|
19841
|
-
for (const inner of wrapper.children) {
|
|
19842
|
-
if (inner.tag === "w:r")
|
|
19843
|
-
total += runTextLength(inner);
|
|
19844
|
-
}
|
|
19845
|
-
return total;
|
|
19846
|
-
}
|
|
19847
20386
|
function mintMeta(tracked) {
|
|
19848
20387
|
return { ...tracked.meta, revisionId: tracked.allocator.next() };
|
|
19849
20388
|
}
|
|
@@ -20057,9 +20596,9 @@ var init_replace3 = __esm(() => {
|
|
|
20057
20596
|
init_replace_span();
|
|
20058
20597
|
});
|
|
20059
20598
|
|
|
20060
|
-
// src/cli/track-changes/
|
|
20061
|
-
var
|
|
20062
|
-
__export(
|
|
20599
|
+
// src/cli/track-changes/list.ts
|
|
20600
|
+
var exports_list4 = {};
|
|
20601
|
+
__export(exports_list4, {
|
|
20063
20602
|
run: () => run27
|
|
20064
20603
|
});
|
|
20065
20604
|
import { parseArgs as parseArgs23 } from "util";
|
|
@@ -20070,8 +20609,6 @@ async function run27(args) {
|
|
|
20070
20609
|
args,
|
|
20071
20610
|
allowPositionals: true,
|
|
20072
20611
|
options: {
|
|
20073
|
-
output: { type: "string", short: "o" },
|
|
20074
|
-
"dry-run": { type: "boolean" },
|
|
20075
20612
|
help: { type: "boolean", short: "h" }
|
|
20076
20613
|
}
|
|
20077
20614
|
});
|
|
@@ -20086,9 +20623,364 @@ async function run27(args) {
|
|
|
20086
20623
|
const path = parsed.positionals[0];
|
|
20087
20624
|
if (!path)
|
|
20088
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);
|
|
20089
20981
|
const mode = parsed.positionals[1];
|
|
20090
20982
|
if (mode !== "on" && mode !== "off") {
|
|
20091
|
-
return fail("USAGE", `Expected "on" or "off", got: ${mode ?? "<nothing>"}`,
|
|
20983
|
+
return fail("USAGE", `Expected "on" or "off", got: ${mode ?? "<nothing>"}`, HELP30);
|
|
20092
20984
|
}
|
|
20093
20985
|
const view = await openOrFail(path);
|
|
20094
20986
|
if (typeof view === "number")
|
|
@@ -20140,7 +21032,7 @@ async function run27(args) {
|
|
|
20140
21032
|
});
|
|
20141
21033
|
return EXIT.OK;
|
|
20142
21034
|
}
|
|
20143
|
-
var
|
|
21035
|
+
var HELP30 = `docx track-changes \u2014 toggle the document's tracked-changes mode
|
|
20144
21036
|
|
|
20145
21037
|
Usage:
|
|
20146
21038
|
docx track-changes FILE on|off [options]
|
|
@@ -20159,7 +21051,7 @@ Examples:
|
|
|
20159
21051
|
docx track-changes doc.docx on
|
|
20160
21052
|
docx track-changes doc.docx off
|
|
20161
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";
|
|
20162
|
-
var
|
|
21054
|
+
var init_toggle = __esm(() => {
|
|
20163
21055
|
init_core();
|
|
20164
21056
|
init_jsx();
|
|
20165
21057
|
init_package();
|
|
@@ -20168,58 +21060,126 @@ var init_track_changes2 = __esm(() => {
|
|
|
20168
21060
|
init_jsx_dev_runtime();
|
|
20169
21061
|
});
|
|
20170
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
|
+
|
|
20171
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
|
+
}
|
|
20172
21130
|
function countWords(text) {
|
|
20173
21131
|
const matches = text.match(/\S+/g);
|
|
20174
21132
|
return matches?.length ?? 0;
|
|
20175
21133
|
}
|
|
20176
|
-
function countWordsInBlocks(blocks) {
|
|
21134
|
+
function countWordsInBlocks(blocks, options = {}) {
|
|
21135
|
+
const text = textFor(options);
|
|
20177
21136
|
let total = 0;
|
|
20178
21137
|
for (const block of blocks) {
|
|
20179
21138
|
if (block.type === "paragraph") {
|
|
20180
|
-
total += countWords(
|
|
21139
|
+
total += countWords(text(block));
|
|
20181
21140
|
} else if (block.type === "table") {
|
|
20182
21141
|
for (const row of block.rows) {
|
|
20183
21142
|
for (const cell of row.cells) {
|
|
20184
|
-
total += countWordsInBlocks(cell.blocks);
|
|
21143
|
+
total += countWordsInBlocks(cell.blocks, options);
|
|
20185
21144
|
}
|
|
20186
21145
|
}
|
|
20187
21146
|
}
|
|
20188
21147
|
}
|
|
20189
21148
|
return total;
|
|
20190
21149
|
}
|
|
20191
|
-
function countWordsInParagraphSpan(paragraph, start, end) {
|
|
20192
|
-
const text =
|
|
21150
|
+
function countWordsInParagraphSpan(paragraph, start, end, options = {}) {
|
|
21151
|
+
const text = textFor(options)(paragraph);
|
|
20193
21152
|
const clampedEnd = Math.min(Math.max(end, 0), text.length);
|
|
20194
21153
|
const clampedStart = Math.min(Math.max(start, 0), clampedEnd);
|
|
20195
21154
|
return countWords(text.slice(clampedStart, clampedEnd));
|
|
20196
21155
|
}
|
|
20197
|
-
function countWordsInRange(paragraphsInOrder, startBlockId, startOffset, endBlockId, endOffset) {
|
|
21156
|
+
function countWordsInRange(paragraphsInOrder, startBlockId, startOffset, endBlockId, endOffset, options = {}) {
|
|
20198
21157
|
const startIndex = paragraphsInOrder.findIndex((p) => p.id === startBlockId);
|
|
20199
21158
|
const endIndex = paragraphsInOrder.findIndex((p) => p.id === endBlockId);
|
|
20200
21159
|
if (startIndex === -1 || endIndex === -1)
|
|
20201
21160
|
return 0;
|
|
20202
21161
|
if (endIndex < startIndex)
|
|
20203
21162
|
return 0;
|
|
21163
|
+
const text = textFor(options);
|
|
20204
21164
|
if (startIndex === endIndex) {
|
|
20205
21165
|
const paragraph = paragraphsInOrder[startIndex];
|
|
20206
21166
|
if (!paragraph)
|
|
20207
21167
|
return 0;
|
|
20208
|
-
return countWordsInParagraphSpan(paragraph, startOffset, endOffset);
|
|
21168
|
+
return countWordsInParagraphSpan(paragraph, startOffset, endOffset, options);
|
|
20209
21169
|
}
|
|
20210
21170
|
let total = 0;
|
|
20211
21171
|
const first = paragraphsInOrder[startIndex];
|
|
20212
21172
|
if (first) {
|
|
20213
|
-
total += countWordsInParagraphSpan(first, startOffset,
|
|
21173
|
+
total += countWordsInParagraphSpan(first, startOffset, text(first).length, options);
|
|
20214
21174
|
}
|
|
20215
21175
|
for (let index = startIndex + 1;index < endIndex; index++) {
|
|
20216
21176
|
const middle = paragraphsInOrder[index];
|
|
20217
21177
|
if (middle)
|
|
20218
|
-
total += countWords(
|
|
21178
|
+
total += countWords(text(middle));
|
|
20219
21179
|
}
|
|
20220
21180
|
const last = paragraphsInOrder[endIndex];
|
|
20221
21181
|
if (last)
|
|
20222
|
-
total += countWordsInParagraphSpan(last, 0, endOffset);
|
|
21182
|
+
total += countWordsInParagraphSpan(last, 0, endOffset, options);
|
|
20223
21183
|
return total;
|
|
20224
21184
|
}
|
|
20225
21185
|
var init_count = __esm(() => {
|
|
@@ -20229,41 +21189,51 @@ var init_count = __esm(() => {
|
|
|
20229
21189
|
// src/cli/wc/index.ts
|
|
20230
21190
|
var exports_wc = {};
|
|
20231
21191
|
__export(exports_wc, {
|
|
20232
|
-
run: () =>
|
|
21192
|
+
run: () => run32
|
|
20233
21193
|
});
|
|
20234
|
-
import { parseArgs as
|
|
20235
|
-
async function
|
|
21194
|
+
import { parseArgs as parseArgs26 } from "util";
|
|
21195
|
+
async function run32(args) {
|
|
20236
21196
|
let parsed;
|
|
20237
21197
|
try {
|
|
20238
|
-
parsed =
|
|
21198
|
+
parsed = parseArgs26({
|
|
20239
21199
|
args,
|
|
20240
21200
|
allowPositionals: true,
|
|
20241
21201
|
options: {
|
|
21202
|
+
accepted: { type: "boolean" },
|
|
21203
|
+
baseline: { type: "boolean" },
|
|
20242
21204
|
help: { type: "boolean", short: "h" }
|
|
20243
21205
|
}
|
|
20244
21206
|
});
|
|
20245
21207
|
} catch (parseError) {
|
|
20246
21208
|
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
20247
|
-
return fail("USAGE", message,
|
|
21209
|
+
return fail("USAGE", message, HELP32);
|
|
20248
21210
|
}
|
|
20249
21211
|
if (parsed.values.help) {
|
|
20250
|
-
await writeStdout(
|
|
21212
|
+
await writeStdout(HELP32);
|
|
20251
21213
|
return EXIT.OK;
|
|
20252
21214
|
}
|
|
20253
21215
|
const path = parsed.positionals[0];
|
|
20254
21216
|
const locatorInput = parsed.positionals[1];
|
|
20255
21217
|
if (!path)
|
|
20256
|
-
return fail("USAGE", "Missing FILE argument",
|
|
20257
|
-
const
|
|
20258
|
-
|
|
20259
|
-
|
|
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;
|
|
20260
21229
|
if (!locatorInput) {
|
|
20261
21230
|
await respond({
|
|
20262
21231
|
ok: true,
|
|
20263
21232
|
operation: "wc",
|
|
20264
21233
|
path,
|
|
20265
21234
|
scope: "document",
|
|
20266
|
-
|
|
21235
|
+
view,
|
|
21236
|
+
words: countWordsInBlocks(docView.doc.blocks, { view })
|
|
20267
21237
|
});
|
|
20268
21238
|
return EXIT.OK;
|
|
20269
21239
|
}
|
|
@@ -20276,22 +21246,23 @@ async function run28(args) {
|
|
|
20276
21246
|
}
|
|
20277
21247
|
throw error;
|
|
20278
21248
|
}
|
|
20279
|
-
if (locator.kind === "comment" || locator.kind === "image") {
|
|
21249
|
+
if (locator.kind === "comment" || locator.kind === "image" || locator.kind === "hyperlink" || locator.kind === "trackedChange") {
|
|
20280
21250
|
return fail("USAGE", `Locator ${locatorInput} addresses a ${locator.kind}, not text`, "wc accepts paragraph, span, range, table, and cell locators.");
|
|
20281
21251
|
}
|
|
20282
|
-
const blocks =
|
|
21252
|
+
const blocks = docView.doc.blocks;
|
|
20283
21253
|
if (locator.kind === "block") {
|
|
20284
21254
|
const block = findBlockById(blocks, locator.blockId);
|
|
20285
21255
|
if (!block) {
|
|
20286
21256
|
return fail("BLOCK_NOT_FOUND", `Block not found: ${locator.blockId}`);
|
|
20287
21257
|
}
|
|
20288
|
-
const words = block.type === "paragraph" ? countWords(
|
|
21258
|
+
const words = block.type === "paragraph" ? countWords(pickText(block)) : block.type === "table" ? countWordsInBlocks([block], { view }) : 0;
|
|
20289
21259
|
await respond({
|
|
20290
21260
|
ok: true,
|
|
20291
21261
|
operation: "wc",
|
|
20292
21262
|
path,
|
|
20293
21263
|
locator: locatorInput,
|
|
20294
21264
|
scope: block.type,
|
|
21265
|
+
view,
|
|
20295
21266
|
words
|
|
20296
21267
|
});
|
|
20297
21268
|
return EXIT.OK;
|
|
@@ -20307,7 +21278,10 @@ async function run28(args) {
|
|
|
20307
21278
|
path,
|
|
20308
21279
|
locator: locatorInput,
|
|
20309
21280
|
scope: "paragraphSpan",
|
|
20310
|
-
|
|
21281
|
+
view,
|
|
21282
|
+
words: countWordsInParagraphSpan(block, locator.start, locator.end, {
|
|
21283
|
+
view
|
|
21284
|
+
})
|
|
20311
21285
|
});
|
|
20312
21286
|
return EXIT.OK;
|
|
20313
21287
|
}
|
|
@@ -20327,7 +21301,8 @@ async function run28(args) {
|
|
|
20327
21301
|
path,
|
|
20328
21302
|
locator: locatorInput,
|
|
20329
21303
|
scope: "range",
|
|
20330
|
-
|
|
21304
|
+
view,
|
|
21305
|
+
words: countWordsInRange(paragraphs, locator.start.blockId, locator.start.offset, locator.end.blockId, locator.end.offset, { view })
|
|
20331
21306
|
});
|
|
20332
21307
|
return EXIT.OK;
|
|
20333
21308
|
}
|
|
@@ -20344,7 +21319,8 @@ async function run28(args) {
|
|
|
20344
21319
|
path,
|
|
20345
21320
|
locator: locatorInput,
|
|
20346
21321
|
scope: "cell",
|
|
20347
|
-
|
|
21322
|
+
view,
|
|
21323
|
+
words: countWordsInBlocks(cellBlocks, { view })
|
|
20348
21324
|
});
|
|
20349
21325
|
return EXIT.OK;
|
|
20350
21326
|
}
|
|
@@ -20357,13 +21333,14 @@ async function run28(args) {
|
|
|
20357
21333
|
if (!block || block.type !== "paragraph") {
|
|
20358
21334
|
return fail("BLOCK_NOT_FOUND", `Paragraph not found: ${composedId}`);
|
|
20359
21335
|
}
|
|
20360
|
-
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));
|
|
20361
21337
|
await respond({
|
|
20362
21338
|
ok: true,
|
|
20363
21339
|
operation: "wc",
|
|
20364
21340
|
path,
|
|
20365
21341
|
locator: locatorInput,
|
|
20366
21342
|
scope: locator.inner.kind === "blockSpan" ? "paragraphSpan" : "paragraph",
|
|
21343
|
+
view,
|
|
20367
21344
|
words
|
|
20368
21345
|
});
|
|
20369
21346
|
return EXIT.OK;
|
|
@@ -20382,7 +21359,14 @@ function findCellBlocks(blocks, locator) {
|
|
|
20382
21359
|
return null;
|
|
20383
21360
|
return cell.blocks;
|
|
20384
21361
|
}
|
|
20385
|
-
|
|
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
|
|
20386
21370
|
|
|
20387
21371
|
Usage:
|
|
20388
21372
|
docx wc FILE [LOCATOR] [options]
|
|
@@ -20397,13 +21381,20 @@ Locators (optional; default: whole document):
|
|
|
20397
21381
|
tN:rRcC:pK:S-E span within a cell paragraph
|
|
20398
21382
|
|
|
20399
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.
|
|
20400
21392
|
-h, --help show this help
|
|
20401
21393
|
|
|
20402
21394
|
Counting is whitespace-segmented (\\S+) over the joined paragraph text. Hidden
|
|
20403
|
-
content like images/breaks/tabs contributes no words.
|
|
20404
|
-
|
|
20405
|
-
|
|
20406
|
-
"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.
|
|
20407
21398
|
|
|
20408
21399
|
Examples:
|
|
20409
21400
|
docx wc doc.docx
|
|
@@ -20420,7 +21411,7 @@ var init_wc = __esm(() => {
|
|
|
20420
21411
|
// package.json
|
|
20421
21412
|
var package_default = {
|
|
20422
21413
|
name: "bun-docx",
|
|
20423
|
-
version: "0.
|
|
21414
|
+
version: "0.7.0",
|
|
20424
21415
|
description: "CLI for AI agents (Claude, Codex) to read, edit, and comment on .docx files with full format fidelity.",
|
|
20425
21416
|
keywords: [
|
|
20426
21417
|
"docx",
|
|
@@ -20500,9 +21491,10 @@ Commands:
|
|
|
20500
21491
|
comments \u2026 Add, reply, resolve, delete, list comments
|
|
20501
21492
|
images \u2026 Extract, replace, list images
|
|
20502
21493
|
hyperlinks \u2026 Add, list, replace, delete hyperlinks
|
|
20503
|
-
track-changes FILE on|off
|
|
21494
|
+
track-changes \u2026 Toggle (FILE on|off), list / accept / reject changes
|
|
20504
21495
|
info \u2026 Reference material (schema, locators)
|
|
20505
21496
|
|
|
21497
|
+
It is highly recommended to agents to run "docx info locators" to understand their capabilities.
|
|
20506
21498
|
Run "docx <command> --help" for command-specific help.
|
|
20507
21499
|
|
|
20508
21500
|
Environment:
|
|
@@ -20510,9 +21502,19 @@ Environment:
|
|
|
20510
21502
|
DOCX_CLI_NOW Override the timestamp used for tracked changes (test only)
|
|
20511
21503
|
|
|
20512
21504
|
Tracked changes:
|
|
20513
|
-
|
|
20514
|
-
FILE
|
|
20515
|
-
|
|
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.
|
|
20516
21518
|
`;
|
|
20517
21519
|
async function printTopHelp() {
|
|
20518
21520
|
await writeStdout(TOP_HELP);
|