bun-docx 0.1.0 → 0.2.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 +16 -14
- package/dist/index.js +1773 -1170
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -47,57 +47,6 @@ var __export = (target, all) => {
|
|
|
47
47
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
48
48
|
var __require = import.meta.require;
|
|
49
49
|
|
|
50
|
-
// src/cli/respond.ts
|
|
51
|
-
async function respond(payload) {
|
|
52
|
-
await Bun.write(Bun.stdout, `${JSON.stringify(payload)}
|
|
53
|
-
`);
|
|
54
|
-
}
|
|
55
|
-
async function writeStdout(text) {
|
|
56
|
-
await Bun.write(Bun.stdout, text);
|
|
57
|
-
}
|
|
58
|
-
async function fail(code, message, hint) {
|
|
59
|
-
const payload = {
|
|
60
|
-
ok: false,
|
|
61
|
-
code,
|
|
62
|
-
error: message
|
|
63
|
-
};
|
|
64
|
-
if (hint)
|
|
65
|
-
payload.hint = hint;
|
|
66
|
-
await respond(payload);
|
|
67
|
-
return exitCodeFor(code);
|
|
68
|
-
}
|
|
69
|
-
function exitCodeFor(code) {
|
|
70
|
-
switch (code) {
|
|
71
|
-
case "USAGE":
|
|
72
|
-
case "INVALID_LOCATOR":
|
|
73
|
-
return EXIT.USAGE_ERROR;
|
|
74
|
-
case "FILE_NOT_FOUND":
|
|
75
|
-
case "PART_NOT_FOUND":
|
|
76
|
-
case "BLOCK_NOT_FOUND":
|
|
77
|
-
case "COMMENT_NOT_FOUND":
|
|
78
|
-
case "IMAGE_NOT_FOUND":
|
|
79
|
-
return EXIT.NOT_FOUND;
|
|
80
|
-
case "PERMISSION_DENIED":
|
|
81
|
-
return EXIT.PERMISSION_DENIED;
|
|
82
|
-
case "ALREADY_APPLIED":
|
|
83
|
-
return EXIT.ALREADY_APPLIED;
|
|
84
|
-
case "NOT_A_ZIP":
|
|
85
|
-
case "UNHANDLED":
|
|
86
|
-
return EXIT.GENERAL_ERROR;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
var EXIT;
|
|
90
|
-
var init_respond = __esm(() => {
|
|
91
|
-
EXIT = {
|
|
92
|
-
OK: 0,
|
|
93
|
-
GENERAL_ERROR: 1,
|
|
94
|
-
USAGE_ERROR: 2,
|
|
95
|
-
NOT_FOUND: 3,
|
|
96
|
-
PERMISSION_DENIED: 4,
|
|
97
|
-
ALREADY_APPLIED: 5
|
|
98
|
-
};
|
|
99
|
-
});
|
|
100
|
-
|
|
101
50
|
// node_modules/process-nextick-args/index.js
|
|
102
51
|
var require_process_nextick_args = __commonJS((exports, module) => {
|
|
103
52
|
if (typeof process === "undefined" || !process.version || process.version.indexOf("v0.") === 0 || process.version.indexOf("v1.") === 0 && process.version.indexOf("v1.8.") !== 0) {
|
|
@@ -9177,92 +9126,6 @@ var require_lib3 = __commonJS((exports, module) => {
|
|
|
9177
9126
|
module.exports = JSZip;
|
|
9178
9127
|
});
|
|
9179
9128
|
|
|
9180
|
-
// src/core/package/index.ts
|
|
9181
|
-
class Pkg {
|
|
9182
|
-
zip;
|
|
9183
|
-
path;
|
|
9184
|
-
constructor(zip, path) {
|
|
9185
|
-
this.zip = zip;
|
|
9186
|
-
this.path = path;
|
|
9187
|
-
}
|
|
9188
|
-
static async open(path) {
|
|
9189
|
-
const file = Bun.file(path);
|
|
9190
|
-
if (!await file.exists()) {
|
|
9191
|
-
throw new PkgError("FILE_NOT_FOUND", `File not found: ${path}`);
|
|
9192
|
-
}
|
|
9193
|
-
const buf = await file.arrayBuffer();
|
|
9194
|
-
let zip;
|
|
9195
|
-
try {
|
|
9196
|
-
zip = await import_jszip.default.loadAsync(buf);
|
|
9197
|
-
} catch (err) {
|
|
9198
|
-
const reason = err instanceof Error ? err.message : String(err);
|
|
9199
|
-
throw new PkgError("NOT_A_ZIP", `Not a valid .docx (zip): ${reason}`);
|
|
9200
|
-
}
|
|
9201
|
-
return new Pkg(zip, path);
|
|
9202
|
-
}
|
|
9203
|
-
hasPart(name) {
|
|
9204
|
-
return this.zip.file(name) !== null;
|
|
9205
|
-
}
|
|
9206
|
-
listParts() {
|
|
9207
|
-
const names = [];
|
|
9208
|
-
this.zip.forEach((p) => {
|
|
9209
|
-
names.push(p);
|
|
9210
|
-
});
|
|
9211
|
-
return names;
|
|
9212
|
-
}
|
|
9213
|
-
async readText(name) {
|
|
9214
|
-
const entry = this.zip.file(name);
|
|
9215
|
-
if (!entry) {
|
|
9216
|
-
throw new PkgError("PART_NOT_FOUND", `Part not found: ${name}`);
|
|
9217
|
-
}
|
|
9218
|
-
return entry.async("string");
|
|
9219
|
-
}
|
|
9220
|
-
async readBytes(name) {
|
|
9221
|
-
const entry = this.zip.file(name);
|
|
9222
|
-
if (!entry) {
|
|
9223
|
-
throw new PkgError("PART_NOT_FOUND", `Part not found: ${name}`);
|
|
9224
|
-
}
|
|
9225
|
-
return entry.async("uint8array");
|
|
9226
|
-
}
|
|
9227
|
-
writeText(name, content) {
|
|
9228
|
-
this.zip.file(name, content);
|
|
9229
|
-
}
|
|
9230
|
-
writeBytes(name, content) {
|
|
9231
|
-
this.zip.file(name, content);
|
|
9232
|
-
}
|
|
9233
|
-
deletePart(name) {
|
|
9234
|
-
this.zip.remove(name);
|
|
9235
|
-
}
|
|
9236
|
-
async save(path) {
|
|
9237
|
-
const target = path ?? this.path;
|
|
9238
|
-
const buf = await this.zip.generateAsync({
|
|
9239
|
-
type: "uint8array",
|
|
9240
|
-
compression: "DEFLATE",
|
|
9241
|
-
compressionOptions: { level: 6 }
|
|
9242
|
-
});
|
|
9243
|
-
await Bun.write(target, buf);
|
|
9244
|
-
}
|
|
9245
|
-
async toBytes() {
|
|
9246
|
-
return this.zip.generateAsync({
|
|
9247
|
-
type: "uint8array",
|
|
9248
|
-
compression: "DEFLATE",
|
|
9249
|
-
compressionOptions: { level: 6 }
|
|
9250
|
-
});
|
|
9251
|
-
}
|
|
9252
|
-
}
|
|
9253
|
-
var import_jszip, PkgError;
|
|
9254
|
-
var init_package = __esm(() => {
|
|
9255
|
-
import_jszip = __toESM(require_lib3(), 1);
|
|
9256
|
-
PkgError = class PkgError extends Error {
|
|
9257
|
-
code;
|
|
9258
|
-
constructor(code, message) {
|
|
9259
|
-
super(message);
|
|
9260
|
-
this.code = code;
|
|
9261
|
-
this.name = "PkgError";
|
|
9262
|
-
}
|
|
9263
|
-
};
|
|
9264
|
-
});
|
|
9265
|
-
|
|
9266
9129
|
// node_modules/path-expression-matcher/src/Expression.js
|
|
9267
9130
|
class Expression {
|
|
9268
9131
|
constructor(pattern, options = {}, data) {
|
|
@@ -13708,70 +13571,245 @@ var init_xml_node = __esm(() => {
|
|
|
13708
13571
|
};
|
|
13709
13572
|
});
|
|
13710
13573
|
|
|
13574
|
+
// src/core/parser/run-ops.ts
|
|
13575
|
+
function runTextLength(run) {
|
|
13576
|
+
let total = 0;
|
|
13577
|
+
for (const child of run.children) {
|
|
13578
|
+
if (child.tag === "w:t")
|
|
13579
|
+
total += child.collectText().length;
|
|
13580
|
+
}
|
|
13581
|
+
return total;
|
|
13582
|
+
}
|
|
13583
|
+
function sliceRun(run, start, end) {
|
|
13584
|
+
const sliced = new XmlNode2("w:r", { ...run.attributes });
|
|
13585
|
+
let consumed = 0;
|
|
13586
|
+
for (const child of run.children) {
|
|
13587
|
+
if (child.tag === "w:t") {
|
|
13588
|
+
const text = child.collectText();
|
|
13589
|
+
const localStart = Math.max(0, start - consumed);
|
|
13590
|
+
const localEnd = Math.min(text.length, end - consumed);
|
|
13591
|
+
if (localStart < localEnd) {
|
|
13592
|
+
const slicedText = new XmlNode2("w:t", { "xml:space": "preserve" });
|
|
13593
|
+
slicedText.children.push(XmlNode2.textNode(text.slice(localStart, localEnd)));
|
|
13594
|
+
sliced.children.push(slicedText);
|
|
13595
|
+
}
|
|
13596
|
+
consumed += text.length;
|
|
13597
|
+
continue;
|
|
13598
|
+
}
|
|
13599
|
+
sliced.children.push(deepCloneNode(child));
|
|
13600
|
+
}
|
|
13601
|
+
return sliced;
|
|
13602
|
+
}
|
|
13603
|
+
function deepCloneNode(node) {
|
|
13604
|
+
const clone = new XmlNode2(node.tag, { ...node.attributes });
|
|
13605
|
+
if (node.text !== undefined)
|
|
13606
|
+
clone.text = node.text;
|
|
13607
|
+
for (const child of node.children) {
|
|
13608
|
+
clone.children.push(deepCloneNode(child));
|
|
13609
|
+
}
|
|
13610
|
+
return clone;
|
|
13611
|
+
}
|
|
13612
|
+
var init_run_ops = __esm(() => {
|
|
13613
|
+
init_xml_node();
|
|
13614
|
+
});
|
|
13615
|
+
|
|
13711
13616
|
// src/core/parser/index.ts
|
|
13712
13617
|
var init_parser = __esm(() => {
|
|
13618
|
+
init_run_ops();
|
|
13713
13619
|
init_xml_node();
|
|
13714
13620
|
});
|
|
13715
13621
|
|
|
13716
|
-
// src/core/
|
|
13717
|
-
function
|
|
13718
|
-
|
|
13719
|
-
const
|
|
13720
|
-
|
|
13721
|
-
if (!documentRoot) {
|
|
13722
|
-
throw new Error("Invalid .docx: missing <w:document>");
|
|
13723
|
-
}
|
|
13724
|
-
const body = documentRoot.findChild("w:body");
|
|
13725
|
-
if (!body) {
|
|
13726
|
-
throw new Error("Invalid .docx: missing <w:body>");
|
|
13727
|
-
}
|
|
13728
|
-
const state = {
|
|
13729
|
-
imageIndex: 0,
|
|
13730
|
-
commentAnchors: new Map,
|
|
13731
|
-
openComments: new Map
|
|
13732
|
-
};
|
|
13733
|
-
const blocks = readBlocks(view, body, state);
|
|
13734
|
-
const comments = readComments(view, state.commentAnchors);
|
|
13735
|
-
return { schemaVersion: 1, path, properties, blocks, comments };
|
|
13736
|
-
}
|
|
13737
|
-
function readBlocks(view, body, state) {
|
|
13738
|
-
const blocks = [];
|
|
13739
|
-
let paragraphIndex = 0;
|
|
13740
|
-
let tableIndex = 0;
|
|
13741
|
-
let sectionIndex = 0;
|
|
13742
|
-
for (const child of body.children) {
|
|
13743
|
-
if (child.tag === "w:p") {
|
|
13744
|
-
const id = `p${paragraphIndex++}`;
|
|
13745
|
-
blocks.push(readParagraph(view, child, id, state));
|
|
13746
|
-
view.blockReferences.set(id, { node: child, parent: body.children });
|
|
13622
|
+
// src/core/package/parts.ts
|
|
13623
|
+
function nextRelationshipId(relationships) {
|
|
13624
|
+
let highest = 0;
|
|
13625
|
+
for (const child of relationships.children) {
|
|
13626
|
+
if (child.tag !== "Relationship")
|
|
13747
13627
|
continue;
|
|
13748
|
-
|
|
13749
|
-
if (
|
|
13750
|
-
const id = `t${tableIndex++}`;
|
|
13751
|
-
blocks.push(readTable(view, child, id, state));
|
|
13752
|
-
view.blockReferences.set(id, { node: child, parent: body.children });
|
|
13628
|
+
const id = child.getAttribute("Id");
|
|
13629
|
+
if (!id)
|
|
13753
13630
|
continue;
|
|
13631
|
+
const match = id.match(/^rId(\d+)$/);
|
|
13632
|
+
if (!match)
|
|
13633
|
+
continue;
|
|
13634
|
+
const numeric = Number(match[1]);
|
|
13635
|
+
if (Number.isFinite(numeric) && numeric > highest)
|
|
13636
|
+
highest = numeric;
|
|
13637
|
+
}
|
|
13638
|
+
return `rId${highest + 1}`;
|
|
13639
|
+
}
|
|
13640
|
+
function registerPart(relationshipsTree, contentTypesTree, part) {
|
|
13641
|
+
const relationships = XmlNode2.findRoot(relationshipsTree, "Relationships");
|
|
13642
|
+
if (relationships) {
|
|
13643
|
+
const alreadyLinked = relationships.children.some((child) => child.tag === "Relationship" && child.getAttribute("Type") === part.relationshipType);
|
|
13644
|
+
if (!alreadyLinked) {
|
|
13645
|
+
relationships.children.push(new XmlNode2("Relationship", {
|
|
13646
|
+
Id: nextRelationshipId(relationships),
|
|
13647
|
+
Type: part.relationshipType,
|
|
13648
|
+
Target: part.target
|
|
13649
|
+
}));
|
|
13754
13650
|
}
|
|
13755
|
-
|
|
13756
|
-
|
|
13757
|
-
|
|
13758
|
-
|
|
13651
|
+
}
|
|
13652
|
+
const types = XmlNode2.findRoot(contentTypesTree, "Types");
|
|
13653
|
+
if (types) {
|
|
13654
|
+
const overrideExists = types.children.some((child) => child.tag === "Override" && child.getAttribute("PartName") === `/${part.partName}`);
|
|
13655
|
+
if (!overrideExists) {
|
|
13656
|
+
types.children.push(new XmlNode2("Override", {
|
|
13657
|
+
PartName: `/${part.partName}`,
|
|
13658
|
+
ContentType: part.contentType
|
|
13659
|
+
}));
|
|
13759
13660
|
}
|
|
13760
13661
|
}
|
|
13761
|
-
return blocks;
|
|
13762
13662
|
}
|
|
13763
|
-
|
|
13764
|
-
|
|
13765
|
-
|
|
13766
|
-
|
|
13767
|
-
|
|
13768
|
-
|
|
13769
|
-
|
|
13770
|
-
|
|
13771
|
-
|
|
13772
|
-
|
|
13773
|
-
|
|
13774
|
-
|
|
13663
|
+
var init_parts = __esm(() => {
|
|
13664
|
+
init_parser();
|
|
13665
|
+
});
|
|
13666
|
+
|
|
13667
|
+
// src/core/package/index.ts
|
|
13668
|
+
class Pkg {
|
|
13669
|
+
zip;
|
|
13670
|
+
path;
|
|
13671
|
+
constructor(zip, path) {
|
|
13672
|
+
this.zip = zip;
|
|
13673
|
+
this.path = path;
|
|
13674
|
+
}
|
|
13675
|
+
static async open(path) {
|
|
13676
|
+
const file = Bun.file(path);
|
|
13677
|
+
if (!await file.exists()) {
|
|
13678
|
+
throw new PkgError("FILE_NOT_FOUND", `File not found: ${path}`);
|
|
13679
|
+
}
|
|
13680
|
+
const buf = await file.arrayBuffer();
|
|
13681
|
+
let zip;
|
|
13682
|
+
try {
|
|
13683
|
+
zip = await import_jszip.default.loadAsync(buf);
|
|
13684
|
+
} catch (err) {
|
|
13685
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
13686
|
+
throw new PkgError("NOT_A_ZIP", `Not a valid .docx (zip): ${reason}`);
|
|
13687
|
+
}
|
|
13688
|
+
return new Pkg(zip, path);
|
|
13689
|
+
}
|
|
13690
|
+
hasPart(name) {
|
|
13691
|
+
return this.zip.file(name) !== null;
|
|
13692
|
+
}
|
|
13693
|
+
listParts() {
|
|
13694
|
+
const names = [];
|
|
13695
|
+
this.zip.forEach((p) => {
|
|
13696
|
+
names.push(p);
|
|
13697
|
+
});
|
|
13698
|
+
return names;
|
|
13699
|
+
}
|
|
13700
|
+
async readText(name) {
|
|
13701
|
+
const entry = this.zip.file(name);
|
|
13702
|
+
if (!entry) {
|
|
13703
|
+
throw new PkgError("PART_NOT_FOUND", `Part not found: ${name}`);
|
|
13704
|
+
}
|
|
13705
|
+
return entry.async("string");
|
|
13706
|
+
}
|
|
13707
|
+
async readBytes(name) {
|
|
13708
|
+
const entry = this.zip.file(name);
|
|
13709
|
+
if (!entry) {
|
|
13710
|
+
throw new PkgError("PART_NOT_FOUND", `Part not found: ${name}`);
|
|
13711
|
+
}
|
|
13712
|
+
return entry.async("uint8array");
|
|
13713
|
+
}
|
|
13714
|
+
writeText(name, content) {
|
|
13715
|
+
this.zip.file(name, content);
|
|
13716
|
+
}
|
|
13717
|
+
writeBytes(name, content) {
|
|
13718
|
+
this.zip.file(name, content);
|
|
13719
|
+
}
|
|
13720
|
+
deletePart(name) {
|
|
13721
|
+
this.zip.remove(name);
|
|
13722
|
+
}
|
|
13723
|
+
async save(path) {
|
|
13724
|
+
const target = path ?? this.path;
|
|
13725
|
+
const buf = await this.zip.generateAsync({
|
|
13726
|
+
type: "uint8array",
|
|
13727
|
+
compression: "DEFLATE",
|
|
13728
|
+
compressionOptions: { level: 6 }
|
|
13729
|
+
});
|
|
13730
|
+
await Bun.write(target, buf);
|
|
13731
|
+
}
|
|
13732
|
+
async toBytes() {
|
|
13733
|
+
return this.zip.generateAsync({
|
|
13734
|
+
type: "uint8array",
|
|
13735
|
+
compression: "DEFLATE",
|
|
13736
|
+
compressionOptions: { level: 6 }
|
|
13737
|
+
});
|
|
13738
|
+
}
|
|
13739
|
+
}
|
|
13740
|
+
var import_jszip, PkgError;
|
|
13741
|
+
var init_package = __esm(() => {
|
|
13742
|
+
init_parts();
|
|
13743
|
+
import_jszip = __toESM(require_lib3(), 1);
|
|
13744
|
+
PkgError = class PkgError extends Error {
|
|
13745
|
+
code;
|
|
13746
|
+
constructor(code, message) {
|
|
13747
|
+
super(message);
|
|
13748
|
+
this.code = code;
|
|
13749
|
+
this.name = "PkgError";
|
|
13750
|
+
}
|
|
13751
|
+
};
|
|
13752
|
+
});
|
|
13753
|
+
|
|
13754
|
+
// src/core/ast/read.ts
|
|
13755
|
+
function buildDoc(view, path) {
|
|
13756
|
+
readImageRelationships(view);
|
|
13757
|
+
const properties = readDocProperties(view);
|
|
13758
|
+
const documentRoot = XmlNode2.findRoot(view.documentTree, "w:document");
|
|
13759
|
+
if (!documentRoot) {
|
|
13760
|
+
throw new Error("Invalid .docx: missing <w:document>");
|
|
13761
|
+
}
|
|
13762
|
+
const body = documentRoot.findChild("w:body");
|
|
13763
|
+
if (!body) {
|
|
13764
|
+
throw new Error("Invalid .docx: missing <w:body>");
|
|
13765
|
+
}
|
|
13766
|
+
const state = {
|
|
13767
|
+
imageIndex: 0,
|
|
13768
|
+
commentAnchors: new Map,
|
|
13769
|
+
openComments: new Map
|
|
13770
|
+
};
|
|
13771
|
+
const blocks = readBlocks(view, body, state);
|
|
13772
|
+
const comments = readComments(view, state.commentAnchors);
|
|
13773
|
+
return { schemaVersion: 1, path, properties, blocks, comments };
|
|
13774
|
+
}
|
|
13775
|
+
function readBlocks(view, body, state) {
|
|
13776
|
+
const blocks = [];
|
|
13777
|
+
let paragraphIndex = 0;
|
|
13778
|
+
let tableIndex = 0;
|
|
13779
|
+
let sectionIndex = 0;
|
|
13780
|
+
for (const child of body.children) {
|
|
13781
|
+
if (child.tag === "w:p") {
|
|
13782
|
+
const id = `p${paragraphIndex++}`;
|
|
13783
|
+
blocks.push(readParagraph(view, child, id, state));
|
|
13784
|
+
view.blockReferences.set(id, { node: child, parent: body.children });
|
|
13785
|
+
continue;
|
|
13786
|
+
}
|
|
13787
|
+
if (child.tag === "w:tbl") {
|
|
13788
|
+
const id = `t${tableIndex++}`;
|
|
13789
|
+
blocks.push(readTable(view, child, id, state));
|
|
13790
|
+
view.blockReferences.set(id, { node: child, parent: body.children });
|
|
13791
|
+
continue;
|
|
13792
|
+
}
|
|
13793
|
+
if (child.tag === "w:sectPr") {
|
|
13794
|
+
const id = `s${sectionIndex++}`;
|
|
13795
|
+
blocks.push({ id, type: "sectionBreak" });
|
|
13796
|
+
view.blockReferences.set(id, { node: child, parent: body.children });
|
|
13797
|
+
}
|
|
13798
|
+
}
|
|
13799
|
+
return blocks;
|
|
13800
|
+
}
|
|
13801
|
+
function readParagraph(view, node, id, state) {
|
|
13802
|
+
const paragraph = { id, type: "paragraph", runs: [] };
|
|
13803
|
+
const paragraphProperties = node.findChild("w:pPr");
|
|
13804
|
+
if (paragraphProperties) {
|
|
13805
|
+
applyParagraphProperties(paragraph, paragraphProperties);
|
|
13806
|
+
}
|
|
13807
|
+
const activeComments = new Set;
|
|
13808
|
+
let offset = 0;
|
|
13809
|
+
for (const child of node.children) {
|
|
13810
|
+
if (child.tag === "w:pPr")
|
|
13811
|
+
continue;
|
|
13812
|
+
if (child.tag === "w:commentRangeStart") {
|
|
13775
13813
|
const commentId = child.getAttribute("w:id");
|
|
13776
13814
|
if (commentId) {
|
|
13777
13815
|
const key = `c${commentId}`;
|
|
@@ -13815,6 +13853,33 @@ function readParagraph(view, node, id, state) {
|
|
|
13815
13853
|
revisionId: child.getAttribute("w:id") ?? ""
|
|
13816
13854
|
};
|
|
13817
13855
|
for (const inner of child.children) {
|
|
13856
|
+
if (inner.tag === "w:commentRangeStart") {
|
|
13857
|
+
const commentId = inner.getAttribute("w:id");
|
|
13858
|
+
if (commentId) {
|
|
13859
|
+
const key = `c${commentId}`;
|
|
13860
|
+
activeComments.add(key);
|
|
13861
|
+
state.openComments.set(key, { blockId: id, offset });
|
|
13862
|
+
}
|
|
13863
|
+
continue;
|
|
13864
|
+
}
|
|
13865
|
+
if (inner.tag === "w:commentRangeEnd") {
|
|
13866
|
+
const commentId = inner.getAttribute("w:id");
|
|
13867
|
+
if (commentId) {
|
|
13868
|
+
const key = `c${commentId}`;
|
|
13869
|
+
activeComments.delete(key);
|
|
13870
|
+
const opened = state.openComments.get(key);
|
|
13871
|
+
if (opened) {
|
|
13872
|
+
state.commentAnchors.set(key, {
|
|
13873
|
+
startBlockId: opened.blockId,
|
|
13874
|
+
startOffset: opened.offset,
|
|
13875
|
+
endBlockId: id,
|
|
13876
|
+
endOffset: offset
|
|
13877
|
+
});
|
|
13878
|
+
state.openComments.delete(key);
|
|
13879
|
+
}
|
|
13880
|
+
}
|
|
13881
|
+
continue;
|
|
13882
|
+
}
|
|
13818
13883
|
if (inner.tag !== "w:r")
|
|
13819
13884
|
continue;
|
|
13820
13885
|
const run = readRun(view, inner, activeComments, change, state);
|
|
@@ -13954,26 +14019,33 @@ function readImageFromDrawing(view, drawing, state) {
|
|
|
13954
14019
|
}
|
|
13955
14020
|
function readTable(view, node, id, state) {
|
|
13956
14021
|
const rows = [];
|
|
14022
|
+
let rowIndex = 0;
|
|
13957
14023
|
for (const child of node.children) {
|
|
13958
14024
|
if (child.tag !== "w:tr")
|
|
13959
14025
|
continue;
|
|
13960
14026
|
const cells = [];
|
|
14027
|
+
let columnIndex = 0;
|
|
13961
14028
|
for (const cellNode of child.children) {
|
|
13962
14029
|
if (cellNode.tag !== "w:tc")
|
|
13963
14030
|
continue;
|
|
13964
|
-
cells.push({
|
|
14031
|
+
cells.push({
|
|
14032
|
+
blocks: readCellBlocks(view, cellNode, id, rowIndex, columnIndex, state)
|
|
14033
|
+
});
|
|
14034
|
+
columnIndex++;
|
|
13965
14035
|
}
|
|
13966
14036
|
rows.push({ cells });
|
|
14037
|
+
rowIndex++;
|
|
13967
14038
|
}
|
|
13968
14039
|
return { id, type: "table", rows };
|
|
13969
14040
|
}
|
|
13970
|
-
function readCellBlocks(view, cell, state) {
|
|
14041
|
+
function readCellBlocks(view, cell, tableId, rowIndex, columnIndex, state) {
|
|
13971
14042
|
const blocks = [];
|
|
13972
14043
|
let paragraphIndex = 0;
|
|
13973
14044
|
for (const child of cell.children) {
|
|
13974
14045
|
if (child.tag === "w:p") {
|
|
13975
|
-
const id =
|
|
14046
|
+
const id = `${tableId}:r${rowIndex}c${columnIndex}:p${paragraphIndex++}`;
|
|
13976
14047
|
blocks.push(readParagraph(view, child, id, state));
|
|
14048
|
+
view.blockReferences.set(id, { node: child, parent: cell.children });
|
|
13977
14049
|
}
|
|
13978
14050
|
}
|
|
13979
14051
|
return blocks;
|
|
@@ -14136,6 +14208,7 @@ async function openDocView(path) {
|
|
|
14136
14208
|
const commentsTree = pkg.hasPart("word/comments.xml") ? XmlNode2.parse(await pkg.readText("word/comments.xml")) : undefined;
|
|
14137
14209
|
const commentsExtTree = pkg.hasPart("word/commentsExtended.xml") ? XmlNode2.parse(await pkg.readText("word/commentsExtended.xml")) : undefined;
|
|
14138
14210
|
const corePropertiesTree = pkg.hasPart("docProps/core.xml") ? XmlNode2.parse(await pkg.readText("docProps/core.xml")) : undefined;
|
|
14211
|
+
const settingsTree = pkg.hasPart("word/settings.xml") ? XmlNode2.parse(await pkg.readText("word/settings.xml")) : undefined;
|
|
14139
14212
|
const view = {
|
|
14140
14213
|
pkg,
|
|
14141
14214
|
documentTree,
|
|
@@ -14144,6 +14217,7 @@ async function openDocView(path) {
|
|
|
14144
14217
|
relationshipsTree,
|
|
14145
14218
|
contentTypesTree,
|
|
14146
14219
|
corePropertiesTree,
|
|
14220
|
+
settingsTree,
|
|
14147
14221
|
doc: undefined,
|
|
14148
14222
|
blockReferences: new Map,
|
|
14149
14223
|
commentReferences: new Map,
|
|
@@ -14163,6 +14237,9 @@ async function saveDocView(view, path) {
|
|
|
14163
14237
|
if (view.commentsExtTree) {
|
|
14164
14238
|
view.pkg.writeText("word/commentsExtended.xml", XmlNode2.serialize(view.commentsExtTree));
|
|
14165
14239
|
}
|
|
14240
|
+
if (view.settingsTree) {
|
|
14241
|
+
view.pkg.writeText("word/settings.xml", XmlNode2.serialize(view.settingsTree));
|
|
14242
|
+
}
|
|
14166
14243
|
await view.pkg.save(path);
|
|
14167
14244
|
}
|
|
14168
14245
|
async function enrichImageHashes(view) {
|
|
@@ -14290,7 +14367,7 @@ var init_parse = __esm(() => {
|
|
|
14290
14367
|
this.name = "LocatorParseError";
|
|
14291
14368
|
}
|
|
14292
14369
|
};
|
|
14293
|
-
BLOCK_RE = /^(p|t|s
|
|
14370
|
+
BLOCK_RE = /^(p|t|s)(\d+)$/;
|
|
14294
14371
|
SPAN_RE = /^p(\d+):(\d+)-(\d+)$/;
|
|
14295
14372
|
RANGE_RE = /^p(\d+):(\d+)-p(\d+):(\d+)$/;
|
|
14296
14373
|
COMMENT_RE = /^c(\d+)$/;
|
|
@@ -14299,6 +14376,26 @@ var init_parse = __esm(() => {
|
|
|
14299
14376
|
});
|
|
14300
14377
|
|
|
14301
14378
|
// src/core/locators/resolve.ts
|
|
14379
|
+
function locatorToBlockTarget(locator) {
|
|
14380
|
+
if (locator.kind === "block")
|
|
14381
|
+
return { blockId: locator.blockId };
|
|
14382
|
+
if (locator.kind === "blockSpan") {
|
|
14383
|
+
return {
|
|
14384
|
+
blockId: locator.blockId,
|
|
14385
|
+
span: { start: locator.start, end: locator.end }
|
|
14386
|
+
};
|
|
14387
|
+
}
|
|
14388
|
+
if (locator.kind === "cell" && locator.inner) {
|
|
14389
|
+
const inner = locatorToBlockTarget(locator.inner);
|
|
14390
|
+
if (!inner)
|
|
14391
|
+
return null;
|
|
14392
|
+
return {
|
|
14393
|
+
blockId: `${locator.tableId}:r${locator.row}c${locator.col}:${inner.blockId}`,
|
|
14394
|
+
span: inner.span
|
|
14395
|
+
};
|
|
14396
|
+
}
|
|
14397
|
+
return null;
|
|
14398
|
+
}
|
|
14302
14399
|
function resolveBlock(view, blockId) {
|
|
14303
14400
|
const reference = view.blockReferences.get(blockId);
|
|
14304
14401
|
if (!reference) {
|
|
@@ -14332,6 +14429,78 @@ var init_core = __esm(() => {
|
|
|
14332
14429
|
init_parser();
|
|
14333
14430
|
});
|
|
14334
14431
|
|
|
14432
|
+
// src/cli/respond.ts
|
|
14433
|
+
async function respond(payload) {
|
|
14434
|
+
await Bun.write(Bun.stdout, `${JSON.stringify(payload)}
|
|
14435
|
+
`);
|
|
14436
|
+
}
|
|
14437
|
+
async function writeStdout(text) {
|
|
14438
|
+
await Bun.write(Bun.stdout, text);
|
|
14439
|
+
}
|
|
14440
|
+
async function fail(code, message, hint) {
|
|
14441
|
+
const payload = {
|
|
14442
|
+
ok: false,
|
|
14443
|
+
code,
|
|
14444
|
+
error: message
|
|
14445
|
+
};
|
|
14446
|
+
if (hint)
|
|
14447
|
+
payload.hint = hint;
|
|
14448
|
+
await respond(payload);
|
|
14449
|
+
return exitCodeFor(code);
|
|
14450
|
+
}
|
|
14451
|
+
function exitCodeFor(code) {
|
|
14452
|
+
switch (code) {
|
|
14453
|
+
case "USAGE":
|
|
14454
|
+
case "INVALID_LOCATOR":
|
|
14455
|
+
return EXIT.USAGE_ERROR;
|
|
14456
|
+
case "FILE_NOT_FOUND":
|
|
14457
|
+
case "PART_NOT_FOUND":
|
|
14458
|
+
case "BLOCK_NOT_FOUND":
|
|
14459
|
+
case "COMMENT_NOT_FOUND":
|
|
14460
|
+
case "IMAGE_NOT_FOUND":
|
|
14461
|
+
case "MATCH_NOT_FOUND":
|
|
14462
|
+
return EXIT.NOT_FOUND;
|
|
14463
|
+
case "NOT_A_ZIP":
|
|
14464
|
+
case "TRACKED_CHANGE_CONFLICT":
|
|
14465
|
+
case "UNHANDLED":
|
|
14466
|
+
return EXIT.GENERAL_ERROR;
|
|
14467
|
+
}
|
|
14468
|
+
}
|
|
14469
|
+
async function openOrFail(path) {
|
|
14470
|
+
try {
|
|
14471
|
+
return await openDocView(path);
|
|
14472
|
+
} catch (err) {
|
|
14473
|
+
if (err instanceof PkgError) {
|
|
14474
|
+
if (err.code === "FILE_NOT_FOUND") {
|
|
14475
|
+
return await fail("FILE_NOT_FOUND", err.message);
|
|
14476
|
+
}
|
|
14477
|
+
if (err.code === "NOT_A_ZIP")
|
|
14478
|
+
return await fail("NOT_A_ZIP", err.message);
|
|
14479
|
+
}
|
|
14480
|
+
throw err;
|
|
14481
|
+
}
|
|
14482
|
+
}
|
|
14483
|
+
async function resolveBlockOrFail(view, locator) {
|
|
14484
|
+
try {
|
|
14485
|
+
return resolveBlock(view, locator);
|
|
14486
|
+
} catch (err) {
|
|
14487
|
+
if (err instanceof LocatorResolveError) {
|
|
14488
|
+
return await fail("BLOCK_NOT_FOUND", err.message);
|
|
14489
|
+
}
|
|
14490
|
+
throw err;
|
|
14491
|
+
}
|
|
14492
|
+
}
|
|
14493
|
+
var EXIT;
|
|
14494
|
+
var init_respond = __esm(() => {
|
|
14495
|
+
init_core();
|
|
14496
|
+
EXIT = {
|
|
14497
|
+
OK: 0,
|
|
14498
|
+
GENERAL_ERROR: 1,
|
|
14499
|
+
USAGE_ERROR: 2,
|
|
14500
|
+
NOT_FOUND: 3
|
|
14501
|
+
};
|
|
14502
|
+
});
|
|
14503
|
+
|
|
14335
14504
|
// src/core/jsx/index.ts
|
|
14336
14505
|
function namespace(prefix, tags) {
|
|
14337
14506
|
const result = {};
|
|
@@ -14548,7 +14717,7 @@ function ensureCommentsPart(view) {
|
|
|
14548
14717
|
"xmlns:w14": NS_W14
|
|
14549
14718
|
}, undefined, false, undefined, this);
|
|
14550
14719
|
view.commentsTree = [root];
|
|
14551
|
-
registerPart(view, {
|
|
14720
|
+
registerPart(view.relationshipsTree, view.contentTypesTree, {
|
|
14552
14721
|
partName: "word/comments.xml",
|
|
14553
14722
|
contentType: COMMENTS_CONTENT_TYPE,
|
|
14554
14723
|
relationshipType: COMMENTS_REL_TYPE,
|
|
@@ -14568,7 +14737,7 @@ function ensureCommentsExtPart(view) {
|
|
|
14568
14737
|
"mc:Ignorable": "w15"
|
|
14569
14738
|
}, undefined, false, undefined, this);
|
|
14570
14739
|
view.commentsExtTree = [root];
|
|
14571
|
-
registerPart(view, {
|
|
14740
|
+
registerPart(view.relationshipsTree, view.contentTypesTree, {
|
|
14572
14741
|
partName: "word/commentsExtended.xml",
|
|
14573
14742
|
contentType: COMMENTS_EXT_CONTENT_TYPE,
|
|
14574
14743
|
relationshipType: COMMENTS_EXT_REL_TYPE,
|
|
@@ -14576,77 +14745,66 @@ function ensureCommentsExtPart(view) {
|
|
|
14576
14745
|
});
|
|
14577
14746
|
return root;
|
|
14578
14747
|
}
|
|
14579
|
-
function
|
|
14580
|
-
|
|
14581
|
-
|
|
14582
|
-
|
|
14583
|
-
|
|
14584
|
-
|
|
14585
|
-
|
|
14586
|
-
|
|
14587
|
-
|
|
14588
|
-
}
|
|
14748
|
+
function paragraphTextLength(paragraph) {
|
|
14749
|
+
let total = 0;
|
|
14750
|
+
for (const child of paragraph.children) {
|
|
14751
|
+
if (child.tag === "w:r")
|
|
14752
|
+
total += runTextLength(child);
|
|
14753
|
+
else if (child.tag === "w:ins" || child.tag === "w:del") {
|
|
14754
|
+
for (const inner of child.children) {
|
|
14755
|
+
if (inner.tag === "w:r")
|
|
14756
|
+
total += runTextLength(inner);
|
|
14757
|
+
}
|
|
14589
14758
|
}
|
|
14590
14759
|
}
|
|
14591
|
-
|
|
14592
|
-
|
|
14593
|
-
|
|
14594
|
-
|
|
14595
|
-
|
|
14596
|
-
|
|
14597
|
-
|
|
14598
|
-
}));
|
|
14599
|
-
}
|
|
14760
|
+
return total;
|
|
14761
|
+
}
|
|
14762
|
+
function addCommentMarkersToParagraph(paragraph, commentId, span) {
|
|
14763
|
+
const total = paragraphTextLength(paragraph);
|
|
14764
|
+
const range = span ?? { start: 0, end: total };
|
|
14765
|
+
if (range.start < 0 || range.end > total || range.start > range.end) {
|
|
14766
|
+
throw new SpanOutOfRangeError(`Span ${range.start}-${range.end} out of paragraph length ${total}`);
|
|
14600
14767
|
}
|
|
14768
|
+
placeMarkersInParagraph(paragraph, [
|
|
14769
|
+
{ offset: range.start, node: commentRangeStartMarker(commentId) },
|
|
14770
|
+
{
|
|
14771
|
+
offset: range.end,
|
|
14772
|
+
node: commentRangeEndMarker(commentId),
|
|
14773
|
+
follower: commentReferenceRun(commentId)
|
|
14774
|
+
}
|
|
14775
|
+
]);
|
|
14601
14776
|
}
|
|
14602
|
-
function
|
|
14603
|
-
|
|
14604
|
-
|
|
14605
|
-
|
|
14606
|
-
|
|
14607
|
-
|
|
14608
|
-
|
|
14609
|
-
continue;
|
|
14610
|
-
const match = id.match(/^rId(\d+)$/);
|
|
14611
|
-
if (!match)
|
|
14612
|
-
continue;
|
|
14613
|
-
const numeric = Number(match[1]);
|
|
14614
|
-
if (Number.isFinite(numeric) && numeric > highest)
|
|
14615
|
-
highest = numeric;
|
|
14777
|
+
function addCommentRangeMarkers(startParagraph, startOffset, endParagraph, endOffset, commentId) {
|
|
14778
|
+
if (startParagraph === endParagraph) {
|
|
14779
|
+
addCommentMarkersToParagraph(startParagraph, commentId, {
|
|
14780
|
+
start: startOffset,
|
|
14781
|
+
end: endOffset
|
|
14782
|
+
});
|
|
14783
|
+
return;
|
|
14616
14784
|
}
|
|
14617
|
-
|
|
14618
|
-
}
|
|
14619
|
-
|
|
14620
|
-
|
|
14621
|
-
|
|
14622
|
-
|
|
14623
|
-
|
|
14624
|
-
|
|
14625
|
-
for (const inner of child.children) {
|
|
14626
|
-
if (inner.tag === "w:r")
|
|
14627
|
-
total += runTextLength(inner);
|
|
14628
|
-
}
|
|
14785
|
+
placeMarkersInParagraph(startParagraph, [
|
|
14786
|
+
{ offset: startOffset, node: commentRangeStartMarker(commentId) }
|
|
14787
|
+
]);
|
|
14788
|
+
placeMarkersInParagraph(endParagraph, [
|
|
14789
|
+
{
|
|
14790
|
+
offset: endOffset,
|
|
14791
|
+
node: commentRangeEndMarker(commentId),
|
|
14792
|
+
follower: commentReferenceRun(commentId)
|
|
14629
14793
|
}
|
|
14630
|
-
|
|
14631
|
-
return total;
|
|
14794
|
+
]);
|
|
14632
14795
|
}
|
|
14633
|
-
function
|
|
14634
|
-
|
|
14635
|
-
const range = span ?? { start: 0, end: total };
|
|
14636
|
-
if (range.start < 0 || range.end > total || range.start > range.end) {
|
|
14637
|
-
throw new SpanOutOfRangeError(`Span ${range.start}-${range.end} out of paragraph length ${total}`);
|
|
14638
|
-
}
|
|
14639
|
-
const newChildren = [];
|
|
14640
|
-
let offset = 0;
|
|
14641
|
-
let placedStart = false;
|
|
14642
|
-
let placedEnd = false;
|
|
14643
|
-
const startMarker = /* @__PURE__ */ jsxDEV(w.commentRangeStart, {
|
|
14796
|
+
function commentRangeStartMarker(commentId) {
|
|
14797
|
+
return /* @__PURE__ */ jsxDEV(w.commentRangeStart, {
|
|
14644
14798
|
"w-id": commentId
|
|
14645
14799
|
}, undefined, false, undefined, this);
|
|
14646
|
-
|
|
14800
|
+
}
|
|
14801
|
+
function commentRangeEndMarker(commentId) {
|
|
14802
|
+
return /* @__PURE__ */ jsxDEV(w.commentRangeEnd, {
|
|
14647
14803
|
"w-id": commentId
|
|
14648
14804
|
}, undefined, false, undefined, this);
|
|
14649
|
-
|
|
14805
|
+
}
|
|
14806
|
+
function commentReferenceRun(commentId) {
|
|
14807
|
+
return /* @__PURE__ */ jsxDEV(w.r, {
|
|
14650
14808
|
children: [
|
|
14651
14809
|
/* @__PURE__ */ jsxDEV(w.rPr, {
|
|
14652
14810
|
children: /* @__PURE__ */ jsxDEV(w.rStyle, {
|
|
@@ -14658,108 +14816,97 @@ function addCommentMarkersToParagraph(paragraph, commentId, span) {
|
|
|
14658
14816
|
}, undefined, false, undefined, this)
|
|
14659
14817
|
]
|
|
14660
14818
|
}, undefined, true, undefined, this);
|
|
14661
|
-
|
|
14662
|
-
|
|
14663
|
-
|
|
14664
|
-
|
|
14665
|
-
|
|
14666
|
-
|
|
14667
|
-
|
|
14819
|
+
}
|
|
14820
|
+
function placeMarkersInParagraph(paragraph, markers) {
|
|
14821
|
+
if (markers.length === 0)
|
|
14822
|
+
return;
|
|
14823
|
+
const total = paragraphTextLength(paragraph);
|
|
14824
|
+
for (const marker of markers) {
|
|
14825
|
+
if (marker.offset < 0 || marker.offset > total) {
|
|
14826
|
+
throw new SpanOutOfRangeError(`Marker offset ${marker.offset} out of paragraph length ${total}`);
|
|
14827
|
+
}
|
|
14828
|
+
}
|
|
14829
|
+
const pending = markers.slice();
|
|
14830
|
+
const state = { offset: 0, placedCount: 0 };
|
|
14831
|
+
paragraph.children = walkAndPlace(paragraph.children, pending, true, state);
|
|
14832
|
+
flushAtCurrentOffset(paragraph.children, pending, state);
|
|
14833
|
+
if (state.placedCount !== markers.length) {
|
|
14834
|
+
throw new SpanOutOfRangeError(`Could not place comment markers (placed ${state.placedCount} of ${markers.length})`);
|
|
14835
|
+
}
|
|
14836
|
+
}
|
|
14837
|
+
function walkAndPlace(children, pending, isParagraphLevel, state) {
|
|
14838
|
+
const result = [];
|
|
14839
|
+
for (const child of children) {
|
|
14840
|
+
if (child.tag === "w:r") {
|
|
14841
|
+
const length = runTextLength(child);
|
|
14842
|
+
const runStart = state.offset;
|
|
14843
|
+
const runEnd = state.offset + length;
|
|
14844
|
+
const splits = [];
|
|
14845
|
+
for (let i = 0;i < pending.length; i++) {
|
|
14846
|
+
const marker = pending[i];
|
|
14847
|
+
if (!marker)
|
|
14668
14848
|
continue;
|
|
14849
|
+
if (runStart <= marker.offset && marker.offset <= runEnd) {
|
|
14850
|
+
splits.push({ at: marker.offset - runStart, index: i });
|
|
14669
14851
|
}
|
|
14670
|
-
newChildren.push(startMarker);
|
|
14671
14852
|
}
|
|
14672
|
-
|
|
14673
|
-
|
|
14674
|
-
|
|
14675
|
-
|
|
14853
|
+
splits.sort((left, right) => left.at - right.at || left.index - right.index);
|
|
14854
|
+
if (splits.length === 0) {
|
|
14855
|
+
result.push(child);
|
|
14856
|
+
} else {
|
|
14857
|
+
let cursor = 0;
|
|
14858
|
+
for (const split of splits) {
|
|
14859
|
+
if (split.at > cursor) {
|
|
14860
|
+
result.push(sliceRun(child, cursor, split.at));
|
|
14861
|
+
}
|
|
14862
|
+
const marker = pending[split.index];
|
|
14863
|
+
if (!marker)
|
|
14864
|
+
continue;
|
|
14865
|
+
result.push(marker.node);
|
|
14866
|
+
if (marker.follower)
|
|
14867
|
+
result.push(marker.follower);
|
|
14868
|
+
pending[split.index] = null;
|
|
14869
|
+
state.placedCount++;
|
|
14870
|
+
cursor = split.at;
|
|
14871
|
+
}
|
|
14872
|
+
if (cursor < length) {
|
|
14873
|
+
result.push(sliceRun(child, cursor, length));
|
|
14874
|
+
}
|
|
14676
14875
|
}
|
|
14677
|
-
|
|
14876
|
+
state.offset = runEnd;
|
|
14678
14877
|
continue;
|
|
14679
14878
|
}
|
|
14680
|
-
|
|
14681
|
-
|
|
14682
|
-
|
|
14683
|
-
|
|
14684
|
-
|
|
14685
|
-
|
|
14686
|
-
|
|
14687
|
-
}
|
|
14688
|
-
if (!placedEnd && runStart <= range.end && range.end <= runEnd) {
|
|
14689
|
-
splits.push({ at: range.end - runStart, node: endMarker });
|
|
14690
|
-
placedEnd = true;
|
|
14691
|
-
}
|
|
14692
|
-
splits.sort((leftSplit, rightSplit) => leftSplit.at - rightSplit.at);
|
|
14693
|
-
if (splits.length === 0) {
|
|
14694
|
-
newChildren.push(child);
|
|
14695
|
-
} else {
|
|
14696
|
-
let cursor = 0;
|
|
14697
|
-
for (const split of splits) {
|
|
14698
|
-
if (split.at > cursor) {
|
|
14699
|
-
newChildren.push(sliceRun(child, cursor, split.at));
|
|
14700
|
-
}
|
|
14701
|
-
newChildren.push(split.node);
|
|
14702
|
-
cursor = split.at;
|
|
14703
|
-
}
|
|
14704
|
-
if (cursor < length) {
|
|
14705
|
-
newChildren.push(sliceRun(child, cursor, length));
|
|
14706
|
-
}
|
|
14707
|
-
if (splits.some((split) => split.node === endMarker)) {
|
|
14708
|
-
newChildren.push(referenceRun);
|
|
14709
|
-
}
|
|
14879
|
+
if (isParagraphLevel && (child.tag === "w:ins" || child.tag === "w:del")) {
|
|
14880
|
+
flushAtCurrentOffset(result, pending, state);
|
|
14881
|
+
const innerChildren = walkAndPlace(child.children, pending, false, state);
|
|
14882
|
+
const wrapper = new XmlNode2(child.tag, { ...child.attributes });
|
|
14883
|
+
wrapper.children = innerChildren;
|
|
14884
|
+
result.push(wrapper);
|
|
14885
|
+
continue;
|
|
14710
14886
|
}
|
|
14711
|
-
|
|
14712
|
-
|
|
14713
|
-
|
|
14714
|
-
newChildren.push(startMarker);
|
|
14715
|
-
placedStart = true;
|
|
14716
|
-
}
|
|
14717
|
-
if (!placedEnd && offset === range.end) {
|
|
14718
|
-
newChildren.push(endMarker);
|
|
14719
|
-
newChildren.push(referenceRun);
|
|
14720
|
-
placedEnd = true;
|
|
14721
|
-
}
|
|
14722
|
-
if (!placedStart || !placedEnd) {
|
|
14723
|
-
throw new SpanOutOfRangeError(`Could not place comment markers (start placed: ${placedStart}, end placed: ${placedEnd})`);
|
|
14724
|
-
}
|
|
14725
|
-
paragraph.children = newChildren;
|
|
14726
|
-
}
|
|
14727
|
-
function runTextLength(run) {
|
|
14728
|
-
let total = 0;
|
|
14729
|
-
for (const child of run.children) {
|
|
14730
|
-
if (child.tag === "w:t")
|
|
14731
|
-
total += child.collectText().length;
|
|
14732
|
-
}
|
|
14733
|
-
return total;
|
|
14734
|
-
}
|
|
14735
|
-
function sliceRun(run, start, end) {
|
|
14736
|
-
const sliced = new XmlNode2("w:r", { ...run.attributes });
|
|
14737
|
-
let consumed = 0;
|
|
14738
|
-
for (const child of run.children) {
|
|
14739
|
-
if (child.tag === "w:t") {
|
|
14740
|
-
const text = child.collectText();
|
|
14741
|
-
const localStart = Math.max(0, start - consumed);
|
|
14742
|
-
const localEnd = Math.min(text.length, end - consumed);
|
|
14743
|
-
if (localStart < localEnd) {
|
|
14744
|
-
const slicedText = new XmlNode2("w:t", { "xml:space": "preserve" });
|
|
14745
|
-
slicedText.children.push(XmlNode2.textNode(text.slice(localStart, localEnd)));
|
|
14746
|
-
sliced.children.push(slicedText);
|
|
14747
|
-
}
|
|
14748
|
-
consumed += text.length;
|
|
14887
|
+
if (child.tag === "w:pPr") {
|
|
14888
|
+
result.push(child);
|
|
14889
|
+
flushAtCurrentOffset(result, pending, state);
|
|
14749
14890
|
continue;
|
|
14750
14891
|
}
|
|
14751
|
-
|
|
14892
|
+
flushAtCurrentOffset(result, pending, state);
|
|
14893
|
+
result.push(child);
|
|
14752
14894
|
}
|
|
14753
|
-
return
|
|
14895
|
+
return result;
|
|
14754
14896
|
}
|
|
14755
|
-
function
|
|
14756
|
-
|
|
14757
|
-
|
|
14758
|
-
|
|
14759
|
-
|
|
14760
|
-
|
|
14897
|
+
function flushAtCurrentOffset(out, pending, state) {
|
|
14898
|
+
for (let i = 0;i < pending.length; i++) {
|
|
14899
|
+
const marker = pending[i];
|
|
14900
|
+
if (!marker)
|
|
14901
|
+
continue;
|
|
14902
|
+
if (marker.offset !== state.offset)
|
|
14903
|
+
continue;
|
|
14904
|
+
out.push(marker.node);
|
|
14905
|
+
if (marker.follower)
|
|
14906
|
+
out.push(marker.follower);
|
|
14907
|
+
pending[i] = null;
|
|
14908
|
+
state.placedCount++;
|
|
14761
14909
|
}
|
|
14762
|
-
return clone;
|
|
14763
14910
|
}
|
|
14764
14911
|
function CommentBody({
|
|
14765
14912
|
options
|
|
@@ -14871,6 +15018,7 @@ function containsCommentReference(run, numericId) {
|
|
|
14871
15018
|
var COMMENTS_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments", COMMENTS_EXT_REL_TYPE = "http://schemas.microsoft.com/office/2011/relationships/commentsExtended", COMMENTS_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml", COMMENTS_EXT_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.commentsExtended+xml", NS_W = "http://schemas.openxmlformats.org/wordprocessingml/2006/main", NS_W14 = "http://schemas.microsoft.com/office/word/2010/wordml", NS_W15 = "http://schemas.microsoft.com/office/word/2012/wordml", SpanOutOfRangeError;
|
|
14872
15019
|
var init_helpers = __esm(() => {
|
|
14873
15020
|
init_jsx();
|
|
15021
|
+
init_package();
|
|
14874
15022
|
init_parser();
|
|
14875
15023
|
init_jsx_dev_runtime();
|
|
14876
15024
|
SpanOutOfRangeError = class SpanOutOfRangeError extends Error {
|
|
@@ -14927,34 +15075,75 @@ async function run(args) {
|
|
|
14927
15075
|
}
|
|
14928
15076
|
throw error;
|
|
14929
15077
|
}
|
|
14930
|
-
|
|
14931
|
-
|
|
14932
|
-
|
|
14933
|
-
|
|
14934
|
-
|
|
14935
|
-
|
|
14936
|
-
|
|
14937
|
-
|
|
14938
|
-
|
|
14939
|
-
|
|
14940
|
-
|
|
14941
|
-
|
|
14942
|
-
|
|
14943
|
-
|
|
14944
|
-
|
|
14945
|
-
|
|
14946
|
-
|
|
15078
|
+
if (locator.kind === "range") {
|
|
15079
|
+
return runCrossBlock(parsed, path, rangeInput, locator, text);
|
|
15080
|
+
}
|
|
15081
|
+
const target = locatorToBlockTarget(locator);
|
|
15082
|
+
if (!target) {
|
|
15083
|
+
return fail("INVALID_LOCATOR", "comments add supports paragraph locators only (pN, pN:start-end, pN:S-pM:E, or tT:rRcC:pK[:start-end])", "Comments and images are not valid anchors.");
|
|
15084
|
+
}
|
|
15085
|
+
const blockId = target.blockId;
|
|
15086
|
+
const view = await openOrFail(path);
|
|
15087
|
+
if (typeof view === "number")
|
|
15088
|
+
return view;
|
|
15089
|
+
const paragraphRef = await resolveBlockOrFail(view, blockId);
|
|
15090
|
+
if (typeof paragraphRef === "number")
|
|
15091
|
+
return paragraphRef;
|
|
15092
|
+
const span = target.span;
|
|
15093
|
+
const author = parsed.values.author ?? Bun.env.DOCX_AUTHOR ?? "";
|
|
15094
|
+
const date = new Date().toISOString();
|
|
15095
|
+
const numericId = nextCommentId(view);
|
|
15096
|
+
const paraId = generateParaId();
|
|
15097
|
+
if (parsed.values["dry-run"]) {
|
|
15098
|
+
await respond({
|
|
15099
|
+
ok: true,
|
|
15100
|
+
operation: "comments.add",
|
|
15101
|
+
dryRun: true,
|
|
15102
|
+
path,
|
|
15103
|
+
commentId: `c${numericId}`,
|
|
15104
|
+
locator: rangeInput
|
|
15105
|
+
});
|
|
15106
|
+
return EXIT.OK;
|
|
14947
15107
|
}
|
|
14948
|
-
let paragraphRef;
|
|
14949
15108
|
try {
|
|
14950
|
-
paragraphRef
|
|
15109
|
+
addCommentMarkersToParagraph(paragraphRef.node, numericId, span);
|
|
14951
15110
|
} catch (error) {
|
|
14952
|
-
if (error instanceof
|
|
14953
|
-
return fail("
|
|
15111
|
+
if (error instanceof SpanOutOfRangeError) {
|
|
15112
|
+
return fail("INVALID_LOCATOR", error.message);
|
|
14954
15113
|
}
|
|
14955
15114
|
throw error;
|
|
14956
15115
|
}
|
|
14957
|
-
const
|
|
15116
|
+
const commentsRoot = ensureCommentsPart(view);
|
|
15117
|
+
commentsRoot.children.push(/* @__PURE__ */ jsxDEV(CommentBody, {
|
|
15118
|
+
options: {
|
|
15119
|
+
id: numericId,
|
|
15120
|
+
author,
|
|
15121
|
+
date,
|
|
15122
|
+
initials: authorInitials(author),
|
|
15123
|
+
paraId,
|
|
15124
|
+
text
|
|
15125
|
+
}
|
|
15126
|
+
}, undefined, false, undefined, this));
|
|
15127
|
+
await saveDocView(view);
|
|
15128
|
+
await respond({
|
|
15129
|
+
ok: true,
|
|
15130
|
+
operation: "comments.add",
|
|
15131
|
+
path,
|
|
15132
|
+
commentId: `c${numericId}`,
|
|
15133
|
+
locator: rangeInput
|
|
15134
|
+
});
|
|
15135
|
+
return EXIT.OK;
|
|
15136
|
+
}
|
|
15137
|
+
async function runCrossBlock(parsed, path, rangeInput, locator, text) {
|
|
15138
|
+
const view = await openOrFail(path);
|
|
15139
|
+
if (typeof view === "number")
|
|
15140
|
+
return view;
|
|
15141
|
+
const startRef = await resolveBlockOrFail(view, locator.start.blockId);
|
|
15142
|
+
if (typeof startRef === "number")
|
|
15143
|
+
return startRef;
|
|
15144
|
+
const endRef = await resolveBlockOrFail(view, locator.end.blockId);
|
|
15145
|
+
if (typeof endRef === "number")
|
|
15146
|
+
return endRef;
|
|
14958
15147
|
const author = parsed.values.author ?? Bun.env.DOCX_AUTHOR ?? "";
|
|
14959
15148
|
const date = new Date().toISOString();
|
|
14960
15149
|
const numericId = nextCommentId(view);
|
|
@@ -14971,7 +15160,7 @@ async function run(args) {
|
|
|
14971
15160
|
return EXIT.OK;
|
|
14972
15161
|
}
|
|
14973
15162
|
try {
|
|
14974
|
-
|
|
15163
|
+
addCommentRangeMarkers(startRef.node, locator.start.offset, endRef.node, locator.end.offset, numericId);
|
|
14975
15164
|
} catch (error) {
|
|
14976
15165
|
if (error instanceof SpanOutOfRangeError) {
|
|
14977
15166
|
return fail("INVALID_LOCATOR", error.message);
|
|
@@ -15005,8 +15194,12 @@ Usage:
|
|
|
15005
15194
|
docx comments add FILE [options]
|
|
15006
15195
|
|
|
15007
15196
|
Required:
|
|
15008
|
-
--range LOCATOR Where to anchor
|
|
15009
|
-
|
|
15197
|
+
--range LOCATOR Where to anchor. Supports:
|
|
15198
|
+
pN whole paragraph
|
|
15199
|
+
pN:S-E chars S..E of pN
|
|
15200
|
+
pN:S-pM:E chars S of pN through char E of pM (cross-paragraph)
|
|
15201
|
+
tT:rRcC:pK whole cell paragraph
|
|
15202
|
+
tT:rRcC:pK:S-E chars S..E of cell paragraph
|
|
15010
15203
|
--text TEXT Comment body
|
|
15011
15204
|
|
|
15012
15205
|
Optional:
|
|
@@ -15017,6 +15210,7 @@ Optional:
|
|
|
15017
15210
|
Examples:
|
|
15018
15211
|
docx comments add doc.docx --range p3 --text "Reconsider this paragraph"
|
|
15019
15212
|
docx comments add doc.docx --range p3:5-20 --text "Sharper wording?" --author "Jane"
|
|
15213
|
+
docx comments add doc.docx --range p3:5-p5:10 --text "Whole section?" --author "Reviewer"
|
|
15020
15214
|
`;
|
|
15021
15215
|
var init_add = __esm(() => {
|
|
15022
15216
|
init_core();
|
|
@@ -15106,20 +15300,9 @@ async function run2(args) {
|
|
|
15106
15300
|
return fail("USAGE", "Missing --id COMMENT_ID", HELP2);
|
|
15107
15301
|
const numericId = idInput.startsWith("c") ? idInput.slice(1) : idInput;
|
|
15108
15302
|
const commentId = `c${numericId}`;
|
|
15109
|
-
|
|
15110
|
-
|
|
15111
|
-
view
|
|
15112
|
-
} catch (openError) {
|
|
15113
|
-
if (openError instanceof PkgError) {
|
|
15114
|
-
if (openError.code === "FILE_NOT_FOUND") {
|
|
15115
|
-
return fail("FILE_NOT_FOUND", openError.message);
|
|
15116
|
-
}
|
|
15117
|
-
if (openError.code === "NOT_A_ZIP") {
|
|
15118
|
-
return fail("NOT_A_ZIP", openError.message);
|
|
15119
|
-
}
|
|
15120
|
-
}
|
|
15121
|
-
throw openError;
|
|
15122
|
-
}
|
|
15303
|
+
const view = await openOrFail(path);
|
|
15304
|
+
if (typeof view === "number")
|
|
15305
|
+
return view;
|
|
15123
15306
|
const commentReference = findCommentByNumericId(view, numericId);
|
|
15124
15307
|
if (!commentReference) {
|
|
15125
15308
|
return fail("COMMENT_NOT_FOUND", `Comment not found: ${commentId}`);
|
|
@@ -15236,20 +15419,9 @@ async function run3(args) {
|
|
|
15236
15419
|
const path = parsed.positionals[0];
|
|
15237
15420
|
if (!path)
|
|
15238
15421
|
return fail("USAGE", "Missing FILE argument", HELP3);
|
|
15239
|
-
|
|
15240
|
-
|
|
15241
|
-
view
|
|
15242
|
-
} catch (openError) {
|
|
15243
|
-
if (openError instanceof PkgError) {
|
|
15244
|
-
if (openError.code === "FILE_NOT_FOUND") {
|
|
15245
|
-
return fail("FILE_NOT_FOUND", openError.message);
|
|
15246
|
-
}
|
|
15247
|
-
if (openError.code === "NOT_A_ZIP") {
|
|
15248
|
-
return fail("NOT_A_ZIP", openError.message);
|
|
15249
|
-
}
|
|
15250
|
-
}
|
|
15251
|
-
throw openError;
|
|
15252
|
-
}
|
|
15422
|
+
const view = await openOrFail(path);
|
|
15423
|
+
if (typeof view === "number")
|
|
15424
|
+
return view;
|
|
15253
15425
|
let comments = view.doc.comments;
|
|
15254
15426
|
if (!parsed.values["include-resolved"]) {
|
|
15255
15427
|
comments = comments.filter((comment) => !comment.resolved);
|
|
@@ -15293,7 +15465,6 @@ Examples:
|
|
|
15293
15465
|
docx comments list doc.docx --include-resolved | jq '.[] | select(.author == "Jane")'
|
|
15294
15466
|
`;
|
|
15295
15467
|
var init_list = __esm(() => {
|
|
15296
|
-
init_core();
|
|
15297
15468
|
init_respond();
|
|
15298
15469
|
});
|
|
15299
15470
|
|
|
@@ -15335,20 +15506,9 @@ async function run4(args) {
|
|
|
15335
15506
|
if (!text)
|
|
15336
15507
|
return fail("USAGE", "Missing --text TEXT", HELP4);
|
|
15337
15508
|
const parentNumericId = parentInput.startsWith("c") ? parentInput.slice(1) : parentInput;
|
|
15338
|
-
|
|
15339
|
-
|
|
15340
|
-
view
|
|
15341
|
-
} catch (openError) {
|
|
15342
|
-
if (openError instanceof PkgError) {
|
|
15343
|
-
if (openError.code === "FILE_NOT_FOUND") {
|
|
15344
|
-
return fail("FILE_NOT_FOUND", openError.message);
|
|
15345
|
-
}
|
|
15346
|
-
if (openError.code === "NOT_A_ZIP") {
|
|
15347
|
-
return fail("NOT_A_ZIP", openError.message);
|
|
15348
|
-
}
|
|
15349
|
-
}
|
|
15350
|
-
throw openError;
|
|
15351
|
-
}
|
|
15509
|
+
const view = await openOrFail(path);
|
|
15510
|
+
if (typeof view === "number")
|
|
15511
|
+
return view;
|
|
15352
15512
|
const parentReference = findCommentByNumericId(view, parentNumericId);
|
|
15353
15513
|
if (!parentReference) {
|
|
15354
15514
|
return fail("COMMENT_NOT_FOUND", `Parent comment not found: c${parentNumericId}`);
|
|
@@ -15459,20 +15619,9 @@ async function run5(args) {
|
|
|
15459
15619
|
return fail("USAGE", "Missing --id COMMENT_ID", HELP5);
|
|
15460
15620
|
const numericId = idInput.startsWith("c") ? idInput.slice(1) : idInput;
|
|
15461
15621
|
const resolved = !parsed.values.unset;
|
|
15462
|
-
|
|
15463
|
-
|
|
15464
|
-
view
|
|
15465
|
-
} catch (openError) {
|
|
15466
|
-
if (openError instanceof PkgError) {
|
|
15467
|
-
if (openError.code === "FILE_NOT_FOUND") {
|
|
15468
|
-
return fail("FILE_NOT_FOUND", openError.message);
|
|
15469
|
-
}
|
|
15470
|
-
if (openError.code === "NOT_A_ZIP") {
|
|
15471
|
-
return fail("NOT_A_ZIP", openError.message);
|
|
15472
|
-
}
|
|
15473
|
-
}
|
|
15474
|
-
throw openError;
|
|
15475
|
-
}
|
|
15622
|
+
const view = await openOrFail(path);
|
|
15623
|
+
if (typeof view === "number")
|
|
15624
|
+
return view;
|
|
15476
15625
|
const commentReference = findCommentByNumericId(view, numericId);
|
|
15477
15626
|
if (!commentReference) {
|
|
15478
15627
|
return fail("COMMENT_NOT_FOUND", `Comment not found: c${numericId}`);
|
|
@@ -15584,34 +15733,19 @@ async function run6(args) {
|
|
|
15584
15733
|
if (!entry) {
|
|
15585
15734
|
return fail("COMMENT_NOT_FOUND", `No trashed entry for ${commentId} in ${path}`, "Trash lives at <dir>/.docx-cli/trash.json \u2014 make sure it's the same directory.");
|
|
15586
15735
|
}
|
|
15587
|
-
|
|
15588
|
-
|
|
15589
|
-
|
|
15590
|
-
|
|
15591
|
-
|
|
15592
|
-
|
|
15593
|
-
} catch (openError) {
|
|
15594
|
-
if (openError instanceof PkgError) {
|
|
15595
|
-
if (openError.code === "FILE_NOT_FOUND") {
|
|
15596
|
-
return fail("FILE_NOT_FOUND", openError.message);
|
|
15597
|
-
}
|
|
15598
|
-
if (openError.code === "NOT_A_ZIP") {
|
|
15599
|
-
return fail("NOT_A_ZIP", openError.message);
|
|
15600
|
-
}
|
|
15601
|
-
}
|
|
15602
|
-
throw openError;
|
|
15736
|
+
const view = await openOrFail(path);
|
|
15737
|
+
if (typeof view === "number")
|
|
15738
|
+
return view;
|
|
15739
|
+
const startBlock = view.blockReferences.get(entry.anchor.startBlockId);
|
|
15740
|
+
if (!startBlock) {
|
|
15741
|
+
return fail("BLOCK_NOT_FOUND", `Original anchor block ${entry.anchor.startBlockId} no longer exists`);
|
|
15603
15742
|
}
|
|
15604
|
-
const
|
|
15605
|
-
|
|
15606
|
-
|
|
15607
|
-
return fail("BLOCK_NOT_FOUND", `Original anchor block ${blockId} no longer exists`);
|
|
15743
|
+
const endBlock = view.blockReferences.get(entry.anchor.endBlockId);
|
|
15744
|
+
if (!endBlock) {
|
|
15745
|
+
return fail("BLOCK_NOT_FOUND", `Original anchor block ${entry.anchor.endBlockId} no longer exists`);
|
|
15608
15746
|
}
|
|
15609
|
-
const span = {
|
|
15610
|
-
start: entry.anchor.startOffset,
|
|
15611
|
-
end: entry.anchor.endOffset
|
|
15612
|
-
};
|
|
15613
15747
|
try {
|
|
15614
|
-
|
|
15748
|
+
addCommentRangeMarkers(startBlock.node, entry.anchor.startOffset, endBlock.node, entry.anchor.endOffset, numericId);
|
|
15615
15749
|
} catch (error) {
|
|
15616
15750
|
if (error instanceof SpanOutOfRangeError) {
|
|
15617
15751
|
return fail("INVALID_LOCATOR", `Saved span no longer fits the block: ${error.message}`);
|
|
@@ -15836,7 +15970,7 @@ async function run8(args) {
|
|
|
15836
15970
|
if (await Bun.file(path).exists() && !parsed.values.force) {
|
|
15837
15971
|
return fail("USAGE", `File already exists: ${path}`, "Pass --force to overwrite.");
|
|
15838
15972
|
}
|
|
15839
|
-
const author = parsed.values.author ??
|
|
15973
|
+
const author = parsed.values.author ?? Bun.env.DOCX_AUTHOR ?? "";
|
|
15840
15974
|
const title = parsed.values.title ?? "";
|
|
15841
15975
|
const text = parsed.values.text;
|
|
15842
15976
|
const now = new Date().toISOString();
|
|
@@ -15915,29 +16049,12 @@ async function run9(args) {
|
|
|
15915
16049
|
const at = parsed.values.at;
|
|
15916
16050
|
if (!at)
|
|
15917
16051
|
return fail("USAGE", "Missing --at LOCATOR", HELP9);
|
|
15918
|
-
|
|
15919
|
-
|
|
15920
|
-
view
|
|
15921
|
-
|
|
15922
|
-
|
|
15923
|
-
|
|
15924
|
-
return fail("FILE_NOT_FOUND", openError.message);
|
|
15925
|
-
}
|
|
15926
|
-
if (openError.code === "NOT_A_ZIP") {
|
|
15927
|
-
return fail("NOT_A_ZIP", openError.message);
|
|
15928
|
-
}
|
|
15929
|
-
}
|
|
15930
|
-
throw openError;
|
|
15931
|
-
}
|
|
15932
|
-
let blockRef;
|
|
15933
|
-
try {
|
|
15934
|
-
blockRef = resolveBlock(view, at);
|
|
15935
|
-
} catch (resolveError) {
|
|
15936
|
-
if (resolveError instanceof LocatorResolveError) {
|
|
15937
|
-
return fail("BLOCK_NOT_FOUND", resolveError.message);
|
|
15938
|
-
}
|
|
15939
|
-
throw resolveError;
|
|
15940
|
-
}
|
|
16052
|
+
const view = await openOrFail(path);
|
|
16053
|
+
if (typeof view === "number")
|
|
16054
|
+
return view;
|
|
16055
|
+
const blockRef = await resolveBlockOrFail(view, at);
|
|
16056
|
+
if (typeof blockRef === "number")
|
|
16057
|
+
return blockRef;
|
|
15941
16058
|
const targetIndex = blockRef.parent.indexOf(blockRef.node);
|
|
15942
16059
|
if (targetIndex === -1) {
|
|
15943
16060
|
return fail("BLOCK_NOT_FOUND", "Block reference is stale (parent does not contain it)");
|
|
@@ -16152,29 +16269,12 @@ async function run10(args) {
|
|
|
16152
16269
|
}
|
|
16153
16270
|
paragraphOptions.alignment = alignmentValue;
|
|
16154
16271
|
}
|
|
16155
|
-
|
|
16156
|
-
|
|
16157
|
-
view
|
|
16158
|
-
|
|
16159
|
-
|
|
16160
|
-
|
|
16161
|
-
return fail("FILE_NOT_FOUND", openError.message);
|
|
16162
|
-
}
|
|
16163
|
-
if (openError.code === "NOT_A_ZIP") {
|
|
16164
|
-
return fail("NOT_A_ZIP", openError.message);
|
|
16165
|
-
}
|
|
16166
|
-
}
|
|
16167
|
-
throw openError;
|
|
16168
|
-
}
|
|
16169
|
-
let blockRef;
|
|
16170
|
-
try {
|
|
16171
|
-
blockRef = resolveBlock(view, at);
|
|
16172
|
-
} catch (resolveError) {
|
|
16173
|
-
if (resolveError instanceof LocatorResolveError) {
|
|
16174
|
-
return fail("BLOCK_NOT_FOUND", resolveError.message);
|
|
16175
|
-
}
|
|
16176
|
-
throw resolveError;
|
|
16177
|
-
}
|
|
16272
|
+
const view = await openOrFail(path);
|
|
16273
|
+
if (typeof view === "number")
|
|
16274
|
+
return view;
|
|
16275
|
+
const blockRef = await resolveBlockOrFail(view, at);
|
|
16276
|
+
if (typeof blockRef === "number")
|
|
16277
|
+
return blockRef;
|
|
16178
16278
|
let paragraphNode;
|
|
16179
16279
|
if (text !== undefined) {
|
|
16180
16280
|
const color = parsed.values.color;
|
|
@@ -16255,12 +16355,86 @@ var init_edit = __esm(() => {
|
|
|
16255
16355
|
init_jsx_dev_runtime();
|
|
16256
16356
|
});
|
|
16257
16357
|
|
|
16258
|
-
// src/
|
|
16259
|
-
|
|
16260
|
-
|
|
16358
|
+
// src/core/find/index.ts
|
|
16359
|
+
function findTextSpans(doc, query, options = {}) {
|
|
16360
|
+
const matcher = options.regex ? regexMatcher(query, options.ignoreCase ?? false) : literalMatcher(query, options.ignoreCase ?? false);
|
|
16361
|
+
const out = [];
|
|
16362
|
+
collectMatches(doc.blocks, matcher, out);
|
|
16363
|
+
return out;
|
|
16364
|
+
}
|
|
16365
|
+
function literalMatcher(query, ignoreCase) {
|
|
16366
|
+
if (query.length === 0) {
|
|
16367
|
+
throw new Error("query cannot be empty");
|
|
16368
|
+
}
|
|
16369
|
+
const needle = ignoreCase ? query.toLowerCase() : query;
|
|
16370
|
+
return (paragraphText) => {
|
|
16371
|
+
const haystack = ignoreCase ? paragraphText.toLowerCase() : paragraphText;
|
|
16372
|
+
const matches = [];
|
|
16373
|
+
let cursor = haystack.indexOf(needle);
|
|
16374
|
+
while (cursor !== -1) {
|
|
16375
|
+
matches.push({
|
|
16376
|
+
start: cursor,
|
|
16377
|
+
end: cursor + needle.length,
|
|
16378
|
+
text: paragraphText.slice(cursor, cursor + needle.length)
|
|
16379
|
+
});
|
|
16380
|
+
cursor = haystack.indexOf(needle, cursor + needle.length);
|
|
16381
|
+
}
|
|
16382
|
+
return matches;
|
|
16383
|
+
};
|
|
16384
|
+
}
|
|
16385
|
+
function regexMatcher(pattern, ignoreCase) {
|
|
16386
|
+
const flags = `g${ignoreCase ? "i" : ""}`;
|
|
16387
|
+
const regex = new RegExp(pattern, flags);
|
|
16388
|
+
return (paragraphText) => {
|
|
16389
|
+
const matches = [];
|
|
16390
|
+
regex.lastIndex = 0;
|
|
16391
|
+
let result = regex.exec(paragraphText);
|
|
16392
|
+
while (result !== null) {
|
|
16393
|
+
const matched = result[0];
|
|
16394
|
+
if (matched.length === 0) {
|
|
16395
|
+
regex.lastIndex += 1;
|
|
16396
|
+
result = regex.exec(paragraphText);
|
|
16397
|
+
continue;
|
|
16398
|
+
}
|
|
16399
|
+
matches.push({
|
|
16400
|
+
start: result.index,
|
|
16401
|
+
end: result.index + matched.length,
|
|
16402
|
+
text: matched
|
|
16403
|
+
});
|
|
16404
|
+
result = regex.exec(paragraphText);
|
|
16405
|
+
}
|
|
16406
|
+
return matches;
|
|
16407
|
+
};
|
|
16408
|
+
}
|
|
16409
|
+
function collectMatches(blocks, matcher, out) {
|
|
16410
|
+
for (const block of blocks) {
|
|
16411
|
+
if (block.type === "paragraph") {
|
|
16412
|
+
const paragraphText = block.runs.map((run11) => run11.type === "text" ? run11.text : "").join("");
|
|
16413
|
+
for (const span of matcher(paragraphText)) {
|
|
16414
|
+
out.push({
|
|
16415
|
+
blockId: block.id,
|
|
16416
|
+
start: span.start,
|
|
16417
|
+
end: span.end,
|
|
16418
|
+
text: span.text
|
|
16419
|
+
});
|
|
16420
|
+
}
|
|
16421
|
+
continue;
|
|
16422
|
+
}
|
|
16423
|
+
if (block.type === "table") {
|
|
16424
|
+
for (const row of block.rows) {
|
|
16425
|
+
for (const cell of row.cells) {
|
|
16426
|
+
collectMatches(cell.blocks, matcher, out);
|
|
16427
|
+
}
|
|
16428
|
+
}
|
|
16429
|
+
}
|
|
16430
|
+
}
|
|
16431
|
+
}
|
|
16432
|
+
|
|
16433
|
+
// src/cli/find/index.ts
|
|
16434
|
+
var exports_find = {};
|
|
16435
|
+
__export(exports_find, {
|
|
16261
16436
|
run: () => run11
|
|
16262
16437
|
});
|
|
16263
|
-
import { join as join2 } from "path";
|
|
16264
16438
|
import { parseArgs as parseArgs10 } from "util";
|
|
16265
16439
|
async function run11(args) {
|
|
16266
16440
|
let parsed;
|
|
@@ -16269,8 +16443,10 @@ async function run11(args) {
|
|
|
16269
16443
|
args,
|
|
16270
16444
|
allowPositionals: true,
|
|
16271
16445
|
options: {
|
|
16272
|
-
|
|
16273
|
-
|
|
16446
|
+
regex: { type: "boolean" },
|
|
16447
|
+
"ignore-case": { type: "boolean" },
|
|
16448
|
+
all: { type: "boolean" },
|
|
16449
|
+
nth: { type: "string" },
|
|
16274
16450
|
help: { type: "boolean", short: "h" }
|
|
16275
16451
|
}
|
|
16276
16452
|
});
|
|
@@ -16283,43 +16459,143 @@ async function run11(args) {
|
|
|
16283
16459
|
return EXIT.OK;
|
|
16284
16460
|
}
|
|
16285
16461
|
const path = parsed.positionals[0];
|
|
16462
|
+
const query = parsed.positionals[1];
|
|
16286
16463
|
if (!path)
|
|
16287
16464
|
return fail("USAGE", "Missing FILE argument", HELP11);
|
|
16288
|
-
|
|
16289
|
-
|
|
16290
|
-
|
|
16291
|
-
const
|
|
16292
|
-
|
|
16465
|
+
if (query == null)
|
|
16466
|
+
return fail("USAGE", "Missing QUERY argument", HELP11);
|
|
16467
|
+
const ignoreCase = Boolean(parsed.values["ignore-case"]);
|
|
16468
|
+
const useRegex = Boolean(parsed.values.regex);
|
|
16469
|
+
const wantAll = Boolean(parsed.values.all);
|
|
16470
|
+
const nthRaw = parsed.values.nth;
|
|
16471
|
+
const nth = nthRaw === undefined ? undefined : Number(nthRaw);
|
|
16472
|
+
if (nth !== undefined && (!Number.isInteger(nth) || nth < 0)) {
|
|
16473
|
+
return fail("USAGE", `--nth must be a non-negative integer, got "${nthRaw}"`);
|
|
16474
|
+
}
|
|
16475
|
+
const view = await openOrFail(path);
|
|
16476
|
+
if (typeof view === "number")
|
|
16477
|
+
return view;
|
|
16478
|
+
let allMatches;
|
|
16293
16479
|
try {
|
|
16294
|
-
|
|
16295
|
-
|
|
16296
|
-
|
|
16297
|
-
|
|
16298
|
-
|
|
16299
|
-
|
|
16300
|
-
|
|
16301
|
-
|
|
16302
|
-
|
|
16303
|
-
|
|
16304
|
-
|
|
16305
|
-
|
|
16306
|
-
|
|
16307
|
-
|
|
16308
|
-
|
|
16309
|
-
|
|
16310
|
-
|
|
16311
|
-
|
|
16480
|
+
allMatches = findTextSpans(view.doc, query, {
|
|
16481
|
+
regex: useRegex,
|
|
16482
|
+
ignoreCase
|
|
16483
|
+
});
|
|
16484
|
+
} catch (matcherError) {
|
|
16485
|
+
const message = matcherError instanceof Error ? matcherError.message : String(matcherError);
|
|
16486
|
+
return fail("USAGE", `Invalid query: ${message}`);
|
|
16487
|
+
}
|
|
16488
|
+
let selected;
|
|
16489
|
+
if (nth !== undefined) {
|
|
16490
|
+
const single = allMatches[nth];
|
|
16491
|
+
if (!single) {
|
|
16492
|
+
return fail("MATCH_NOT_FOUND", `Only ${allMatches.length} match(es); --nth ${nth} is out of range`);
|
|
16493
|
+
}
|
|
16494
|
+
selected = [single];
|
|
16495
|
+
} else if (wantAll) {
|
|
16496
|
+
selected = allMatches;
|
|
16497
|
+
} else {
|
|
16498
|
+
selected = allMatches.slice(0, 1);
|
|
16312
16499
|
}
|
|
16313
|
-
|
|
16314
|
-
|
|
16315
|
-
|
|
16316
|
-
|
|
16317
|
-
|
|
16318
|
-
|
|
16319
|
-
|
|
16320
|
-
|
|
16321
|
-
|
|
16322
|
-
|
|
16500
|
+
await respond({
|
|
16501
|
+
ok: true,
|
|
16502
|
+
operation: "find",
|
|
16503
|
+
path,
|
|
16504
|
+
query,
|
|
16505
|
+
regex: useRegex,
|
|
16506
|
+
ignoreCase,
|
|
16507
|
+
totalMatches: allMatches.length,
|
|
16508
|
+
matches: selected.map((match) => ({
|
|
16509
|
+
locator: `${match.blockId}:${match.start}-${match.end}`,
|
|
16510
|
+
...match
|
|
16511
|
+
}))
|
|
16512
|
+
});
|
|
16513
|
+
return EXIT.OK;
|
|
16514
|
+
}
|
|
16515
|
+
var HELP11 = `docx find \u2014 locate text spans and return their locators
|
|
16516
|
+
|
|
16517
|
+
Usage:
|
|
16518
|
+
docx find FILE QUERY [options]
|
|
16519
|
+
|
|
16520
|
+
Required positional:
|
|
16521
|
+
QUERY literal substring (or regex if --regex)
|
|
16522
|
+
|
|
16523
|
+
Options:
|
|
16524
|
+
--regex treat QUERY as a JavaScript regular expression
|
|
16525
|
+
--ignore-case case-insensitive match
|
|
16526
|
+
--all return every match (default: just the first)
|
|
16527
|
+
--nth N return only the Nth match (0-indexed)
|
|
16528
|
+
-h, --help show this help
|
|
16529
|
+
|
|
16530
|
+
Within-paragraph matches only \u2014 cross-paragraph ranges aren't supported
|
|
16531
|
+
yet. Searches the concatenated text of each paragraph in document order,
|
|
16532
|
+
including paragraphs nested in table cells (locators look like
|
|
16533
|
+
tT:rRcC:pK:S-E for those).
|
|
16534
|
+
|
|
16535
|
+
Examples:
|
|
16536
|
+
docx find doc.docx "fox"
|
|
16537
|
+
docx find doc.docx "Action Item:" --all
|
|
16538
|
+
docx find doc.docx "TODO|FIXME" --regex --ignore-case
|
|
16539
|
+
docx comments add doc.docx --range "$(docx find doc.docx fox | jq -r .matches[0].locator)" --text "..."
|
|
16540
|
+
`;
|
|
16541
|
+
var init_find = __esm(() => {
|
|
16542
|
+
init_respond();
|
|
16543
|
+
});
|
|
16544
|
+
|
|
16545
|
+
// src/cli/images/extract.ts
|
|
16546
|
+
var exports_extract = {};
|
|
16547
|
+
__export(exports_extract, {
|
|
16548
|
+
run: () => run12
|
|
16549
|
+
});
|
|
16550
|
+
import { join as join2 } from "path";
|
|
16551
|
+
import { parseArgs as parseArgs11 } from "util";
|
|
16552
|
+
async function run12(args) {
|
|
16553
|
+
let parsed;
|
|
16554
|
+
try {
|
|
16555
|
+
parsed = parseArgs11({
|
|
16556
|
+
args,
|
|
16557
|
+
allowPositionals: true,
|
|
16558
|
+
options: {
|
|
16559
|
+
to: { type: "string" },
|
|
16560
|
+
id: { type: "string" },
|
|
16561
|
+
help: { type: "boolean", short: "h" }
|
|
16562
|
+
}
|
|
16563
|
+
});
|
|
16564
|
+
} catch (parseError) {
|
|
16565
|
+
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
16566
|
+
return fail("USAGE", message, HELP12);
|
|
16567
|
+
}
|
|
16568
|
+
if (parsed.values.help) {
|
|
16569
|
+
await writeStdout(HELP12);
|
|
16570
|
+
return EXIT.OK;
|
|
16571
|
+
}
|
|
16572
|
+
const path = parsed.positionals[0];
|
|
16573
|
+
if (!path)
|
|
16574
|
+
return fail("USAGE", "Missing FILE argument", HELP12);
|
|
16575
|
+
const outputDir = parsed.values.to;
|
|
16576
|
+
if (!outputDir)
|
|
16577
|
+
return fail("USAGE", "Missing --to DIR", HELP12);
|
|
16578
|
+
const targetId = parsed.values.id;
|
|
16579
|
+
const view = await openOrFail(path);
|
|
16580
|
+
if (typeof view === "number")
|
|
16581
|
+
return view;
|
|
16582
|
+
await enrichImageHashes(view);
|
|
16583
|
+
const allImages = [];
|
|
16584
|
+
collectImages(view.doc.blocks, allImages);
|
|
16585
|
+
const targets = targetId ? allImages.filter((image) => image.id === targetId) : allImages;
|
|
16586
|
+
if (targetId && targets.length === 0) {
|
|
16587
|
+
return fail("IMAGE_NOT_FOUND", `Image not found: ${targetId}`);
|
|
16588
|
+
}
|
|
16589
|
+
const manifest = [];
|
|
16590
|
+
const seenHashes = new Set;
|
|
16591
|
+
for (const image of targets) {
|
|
16592
|
+
const reference = view.imageById.get(image.id);
|
|
16593
|
+
if (!reference)
|
|
16594
|
+
continue;
|
|
16595
|
+
const extension = extensionFor(image.contentType, reference.partName);
|
|
16596
|
+
const fileName = `${image.hash}.${extension}`;
|
|
16597
|
+
const outputPath = join2(outputDir, fileName);
|
|
16598
|
+
if (!seenHashes.has(image.hash)) {
|
|
16323
16599
|
const bytes = await view.pkg.readBytes(reference.partName);
|
|
16324
16600
|
await Bun.write(outputPath, bytes);
|
|
16325
16601
|
seenHashes.add(image.hash);
|
|
@@ -16336,9 +16612,9 @@ async function run11(args) {
|
|
|
16336
16612
|
function collectImages(blocks, out) {
|
|
16337
16613
|
for (const block of blocks) {
|
|
16338
16614
|
if (block.type === "paragraph") {
|
|
16339
|
-
for (const
|
|
16340
|
-
if (
|
|
16341
|
-
out.push(
|
|
16615
|
+
for (const run13 of block.runs) {
|
|
16616
|
+
if (run13.type === "image")
|
|
16617
|
+
out.push(run13);
|
|
16342
16618
|
}
|
|
16343
16619
|
continue;
|
|
16344
16620
|
}
|
|
@@ -16358,7 +16634,7 @@ function extensionFor(contentType, partName) {
|
|
|
16358
16634
|
const fromName = partName.split(".").pop()?.toLowerCase();
|
|
16359
16635
|
return fromName ?? "bin";
|
|
16360
16636
|
}
|
|
16361
|
-
var
|
|
16637
|
+
var HELP12 = `docx images extract \u2014 dump image bytes to a directory
|
|
16362
16638
|
|
|
16363
16639
|
Usage:
|
|
16364
16640
|
docx images extract FILE --to DIR [options]
|
|
@@ -16399,13 +16675,13 @@ var init_extract = __esm(() => {
|
|
|
16399
16675
|
// src/cli/images/list.ts
|
|
16400
16676
|
var exports_list2 = {};
|
|
16401
16677
|
__export(exports_list2, {
|
|
16402
|
-
run: () =>
|
|
16678
|
+
run: () => run13
|
|
16403
16679
|
});
|
|
16404
|
-
import { parseArgs as
|
|
16405
|
-
async function
|
|
16680
|
+
import { parseArgs as parseArgs12 } from "util";
|
|
16681
|
+
async function run13(args) {
|
|
16406
16682
|
let parsed;
|
|
16407
16683
|
try {
|
|
16408
|
-
parsed =
|
|
16684
|
+
parsed = parseArgs12({
|
|
16409
16685
|
args,
|
|
16410
16686
|
allowPositionals: true,
|
|
16411
16687
|
options: {
|
|
@@ -16414,29 +16690,18 @@ async function run12(args) {
|
|
|
16414
16690
|
});
|
|
16415
16691
|
} catch (parseError) {
|
|
16416
16692
|
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
16417
|
-
return fail("USAGE", message,
|
|
16693
|
+
return fail("USAGE", message, HELP13);
|
|
16418
16694
|
}
|
|
16419
16695
|
if (parsed.values.help) {
|
|
16420
|
-
await writeStdout(
|
|
16696
|
+
await writeStdout(HELP13);
|
|
16421
16697
|
return EXIT.OK;
|
|
16422
16698
|
}
|
|
16423
16699
|
const path = parsed.positionals[0];
|
|
16424
16700
|
if (!path)
|
|
16425
|
-
return fail("USAGE", "Missing FILE argument",
|
|
16426
|
-
|
|
16427
|
-
|
|
16428
|
-
view
|
|
16429
|
-
} catch (openError) {
|
|
16430
|
-
if (openError instanceof PkgError) {
|
|
16431
|
-
if (openError.code === "FILE_NOT_FOUND") {
|
|
16432
|
-
return fail("FILE_NOT_FOUND", openError.message);
|
|
16433
|
-
}
|
|
16434
|
-
if (openError.code === "NOT_A_ZIP") {
|
|
16435
|
-
return fail("NOT_A_ZIP", openError.message);
|
|
16436
|
-
}
|
|
16437
|
-
}
|
|
16438
|
-
throw openError;
|
|
16439
|
-
}
|
|
16701
|
+
return fail("USAGE", "Missing FILE argument", HELP13);
|
|
16702
|
+
const view = await openOrFail(path);
|
|
16703
|
+
if (typeof view === "number")
|
|
16704
|
+
return view;
|
|
16440
16705
|
await enrichImageHashes(view);
|
|
16441
16706
|
const images = [];
|
|
16442
16707
|
collectImages2(view.doc.blocks, images);
|
|
@@ -16446,9 +16711,9 @@ async function run12(args) {
|
|
|
16446
16711
|
function collectImages2(blocks, out) {
|
|
16447
16712
|
for (const block of blocks) {
|
|
16448
16713
|
if (block.type === "paragraph") {
|
|
16449
|
-
for (const
|
|
16450
|
-
if (
|
|
16451
|
-
out.push(
|
|
16714
|
+
for (const run14 of block.runs) {
|
|
16715
|
+
if (run14.type === "image")
|
|
16716
|
+
out.push(run14);
|
|
16452
16717
|
}
|
|
16453
16718
|
continue;
|
|
16454
16719
|
}
|
|
@@ -16461,7 +16726,7 @@ function collectImages2(blocks, out) {
|
|
|
16461
16726
|
}
|
|
16462
16727
|
}
|
|
16463
16728
|
}
|
|
16464
|
-
var
|
|
16729
|
+
var HELP13 = `docx images list \u2014 print image manifest as JSON
|
|
16465
16730
|
|
|
16466
16731
|
Usage:
|
|
16467
16732
|
docx images list FILE [options]
|
|
@@ -16480,13 +16745,13 @@ var init_list2 = __esm(() => {
|
|
|
16480
16745
|
// src/cli/images/replace.ts
|
|
16481
16746
|
var exports_replace = {};
|
|
16482
16747
|
__export(exports_replace, {
|
|
16483
|
-
run: () =>
|
|
16748
|
+
run: () => run14
|
|
16484
16749
|
});
|
|
16485
|
-
import { parseArgs as
|
|
16486
|
-
async function
|
|
16750
|
+
import { parseArgs as parseArgs13 } from "util";
|
|
16751
|
+
async function run14(args) {
|
|
16487
16752
|
let parsed;
|
|
16488
16753
|
try {
|
|
16489
|
-
parsed =
|
|
16754
|
+
parsed = parseArgs13({
|
|
16490
16755
|
args,
|
|
16491
16756
|
allowPositionals: true,
|
|
16492
16757
|
options: {
|
|
@@ -16498,21 +16763,21 @@ async function run13(args) {
|
|
|
16498
16763
|
});
|
|
16499
16764
|
} catch (parseError) {
|
|
16500
16765
|
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
16501
|
-
return fail("USAGE", message,
|
|
16766
|
+
return fail("USAGE", message, HELP14);
|
|
16502
16767
|
}
|
|
16503
16768
|
if (parsed.values.help) {
|
|
16504
|
-
await writeStdout(
|
|
16769
|
+
await writeStdout(HELP14);
|
|
16505
16770
|
return EXIT.OK;
|
|
16506
16771
|
}
|
|
16507
16772
|
const path = parsed.positionals[0];
|
|
16508
16773
|
if (!path)
|
|
16509
|
-
return fail("USAGE", "Missing FILE argument",
|
|
16774
|
+
return fail("USAGE", "Missing FILE argument", HELP14);
|
|
16510
16775
|
const targetId = parsed.values.at;
|
|
16511
16776
|
if (!targetId)
|
|
16512
|
-
return fail("USAGE", "Missing --at IMG_ID",
|
|
16777
|
+
return fail("USAGE", "Missing --at IMG_ID", HELP14);
|
|
16513
16778
|
const sourcePath = parsed.values.with;
|
|
16514
16779
|
if (!sourcePath)
|
|
16515
|
-
return fail("USAGE", "Missing --with PATH",
|
|
16780
|
+
return fail("USAGE", "Missing --with PATH", HELP14);
|
|
16516
16781
|
const sourceFile = Bun.file(sourcePath);
|
|
16517
16782
|
if (!await sourceFile.exists()) {
|
|
16518
16783
|
return fail("FILE_NOT_FOUND", `Replacement file not found: ${sourcePath}`);
|
|
@@ -16522,20 +16787,9 @@ async function run13(args) {
|
|
|
16522
16787
|
if (!newExtension) {
|
|
16523
16788
|
return fail("USAGE", `Unsupported replacement image type: ${newMimeType}`, "Supported: png, jpeg, gif, webp, bmp, tiff, svg, emf, wmf, ico.");
|
|
16524
16789
|
}
|
|
16525
|
-
|
|
16526
|
-
|
|
16527
|
-
view
|
|
16528
|
-
} catch (openError) {
|
|
16529
|
-
if (openError instanceof PkgError) {
|
|
16530
|
-
if (openError.code === "FILE_NOT_FOUND") {
|
|
16531
|
-
return fail("FILE_NOT_FOUND", openError.message);
|
|
16532
|
-
}
|
|
16533
|
-
if (openError.code === "NOT_A_ZIP") {
|
|
16534
|
-
return fail("NOT_A_ZIP", openError.message);
|
|
16535
|
-
}
|
|
16536
|
-
}
|
|
16537
|
-
throw openError;
|
|
16538
|
-
}
|
|
16790
|
+
const view = await openOrFail(path);
|
|
16791
|
+
if (typeof view === "number")
|
|
16792
|
+
return view;
|
|
16539
16793
|
const reference = view.imageById.get(targetId);
|
|
16540
16794
|
if (!reference) {
|
|
16541
16795
|
return fail("IMAGE_NOT_FOUND", `Image not found: ${targetId}`);
|
|
@@ -16613,7 +16867,7 @@ function ensureContentTypeDefault(contentTypesTree, extension, mimeType) {
|
|
|
16613
16867
|
}
|
|
16614
16868
|
types.children.push(new XmlNode2("Default", { Extension: extension, ContentType: mimeType }));
|
|
16615
16869
|
}
|
|
16616
|
-
var
|
|
16870
|
+
var HELP14 = `docx images replace \u2014 swap an image's bytes
|
|
16617
16871
|
|
|
16618
16872
|
Usage:
|
|
16619
16873
|
docx images replace FILE --at IMG_ID --with PATH [options]
|
|
@@ -16655,12 +16909,12 @@ var init_replace = __esm(() => {
|
|
|
16655
16909
|
// src/cli/images/index.ts
|
|
16656
16910
|
var exports_images = {};
|
|
16657
16911
|
__export(exports_images, {
|
|
16658
|
-
run: () =>
|
|
16912
|
+
run: () => run15
|
|
16659
16913
|
});
|
|
16660
|
-
async function
|
|
16914
|
+
async function run15(args) {
|
|
16661
16915
|
const verb = args[0];
|
|
16662
16916
|
if (!verb || verb === "--help" || verb === "-h" || verb === "help") {
|
|
16663
|
-
await writeStdout(
|
|
16917
|
+
await writeStdout(HELP15);
|
|
16664
16918
|
return verb ? 0 : 2;
|
|
16665
16919
|
}
|
|
16666
16920
|
const loader = SUBCOMMANDS2[verb];
|
|
@@ -16670,7 +16924,7 @@ async function run14(args) {
|
|
|
16670
16924
|
const module_ = await loader();
|
|
16671
16925
|
return module_.run(args.slice(1));
|
|
16672
16926
|
}
|
|
16673
|
-
var SUBCOMMANDS2,
|
|
16927
|
+
var SUBCOMMANDS2, HELP15 = `docx images \u2014 manage embedded images
|
|
16674
16928
|
|
|
16675
16929
|
Usage:
|
|
16676
16930
|
docx images <verb> FILE [options]
|
|
@@ -16691,58 +16945,536 @@ var init_images = __esm(() => {
|
|
|
16691
16945
|
};
|
|
16692
16946
|
});
|
|
16693
16947
|
|
|
16694
|
-
// src/
|
|
16695
|
-
var
|
|
16696
|
-
|
|
16697
|
-
|
|
16948
|
+
// src/core/ast/types.ts
|
|
16949
|
+
var types_default = `export type Doc = {
|
|
16950
|
+
schemaVersion: 1;
|
|
16951
|
+
path: string;
|
|
16952
|
+
properties: DocProperties;
|
|
16953
|
+
blocks: Block[];
|
|
16954
|
+
comments: Comment[];
|
|
16955
|
+
};
|
|
16956
|
+
|
|
16957
|
+
export type DocProperties = {
|
|
16958
|
+
title?: string;
|
|
16959
|
+
author?: string;
|
|
16960
|
+
created?: string;
|
|
16961
|
+
modified?: string;
|
|
16962
|
+
};
|
|
16963
|
+
|
|
16964
|
+
export type Block = Paragraph | Table | SectionBreak;
|
|
16965
|
+
|
|
16966
|
+
export type Paragraph = {
|
|
16967
|
+
id: string;
|
|
16968
|
+
type: "paragraph";
|
|
16969
|
+
style?: string;
|
|
16970
|
+
alignment?: "left" | "center" | "right" | "justify";
|
|
16971
|
+
list?: { level: number; numId: string };
|
|
16972
|
+
runs: Run[];
|
|
16973
|
+
};
|
|
16974
|
+
|
|
16975
|
+
export type Table = {
|
|
16976
|
+
id: string;
|
|
16977
|
+
type: "table";
|
|
16978
|
+
rows: TableRow[];
|
|
16979
|
+
};
|
|
16980
|
+
|
|
16981
|
+
export type TableRow = {
|
|
16982
|
+
cells: TableCell[];
|
|
16983
|
+
};
|
|
16984
|
+
|
|
16985
|
+
export type TableCell = {
|
|
16986
|
+
blocks: Block[];
|
|
16987
|
+
};
|
|
16988
|
+
|
|
16989
|
+
export type SectionBreak = {
|
|
16990
|
+
id: string;
|
|
16991
|
+
type: "sectionBreak";
|
|
16992
|
+
};
|
|
16993
|
+
|
|
16994
|
+
export type Run = TextRun | ImageRun | BreakRun | TabRun;
|
|
16995
|
+
|
|
16996
|
+
export type TextRun = {
|
|
16997
|
+
type: "text";
|
|
16998
|
+
text: string;
|
|
16999
|
+
color?: string;
|
|
17000
|
+
highlight?: string;
|
|
17001
|
+
bold?: boolean;
|
|
17002
|
+
italic?: boolean;
|
|
17003
|
+
underline?: string;
|
|
17004
|
+
strike?: boolean;
|
|
17005
|
+
font?: string;
|
|
17006
|
+
sizeHalfPoints?: number;
|
|
17007
|
+
comments?: string[];
|
|
17008
|
+
trackedChange?: TrackedChange;
|
|
17009
|
+
};
|
|
17010
|
+
|
|
17011
|
+
export type ImageRun = {
|
|
17012
|
+
type: "image";
|
|
17013
|
+
id: string;
|
|
17014
|
+
contentType: string;
|
|
17015
|
+
hash: string;
|
|
17016
|
+
widthEmu?: number;
|
|
17017
|
+
heightEmu?: number;
|
|
17018
|
+
alt?: string;
|
|
17019
|
+
};
|
|
17020
|
+
|
|
17021
|
+
export type BreakRun = {
|
|
17022
|
+
type: "break";
|
|
17023
|
+
kind: "page" | "line" | "column";
|
|
17024
|
+
};
|
|
17025
|
+
|
|
17026
|
+
export type TabRun = {
|
|
17027
|
+
type: "tab";
|
|
17028
|
+
};
|
|
17029
|
+
|
|
17030
|
+
export type TrackedChange = {
|
|
17031
|
+
kind: "ins" | "del";
|
|
17032
|
+
author: string;
|
|
17033
|
+
date: string;
|
|
17034
|
+
revisionId: string;
|
|
17035
|
+
};
|
|
17036
|
+
|
|
17037
|
+
export type Comment = {
|
|
17038
|
+
id: string;
|
|
17039
|
+
author: string;
|
|
17040
|
+
initials?: string;
|
|
17041
|
+
date: string;
|
|
17042
|
+
text: string;
|
|
17043
|
+
parentId?: string;
|
|
17044
|
+
resolved?: boolean;
|
|
17045
|
+
anchor: CommentAnchor;
|
|
17046
|
+
};
|
|
17047
|
+
|
|
17048
|
+
export type CommentAnchor = {
|
|
17049
|
+
startBlockId: string;
|
|
17050
|
+
startOffset: number;
|
|
17051
|
+
endBlockId: string;
|
|
17052
|
+
endOffset: number;
|
|
17053
|
+
};
|
|
17054
|
+
`;
|
|
17055
|
+
var init_types = () => {};
|
|
17056
|
+
|
|
17057
|
+
// src/cli/info/schema.ts
|
|
17058
|
+
var exports_schema = {};
|
|
17059
|
+
__export(exports_schema, {
|
|
17060
|
+
run: () => run16
|
|
16698
17061
|
});
|
|
16699
|
-
import { parseArgs as
|
|
16700
|
-
async function
|
|
17062
|
+
import { parseArgs as parseArgs14 } from "util";
|
|
17063
|
+
async function run16(args) {
|
|
16701
17064
|
let parsed;
|
|
16702
17065
|
try {
|
|
16703
|
-
parsed =
|
|
17066
|
+
parsed = parseArgs14({
|
|
16704
17067
|
args,
|
|
16705
17068
|
allowPositionals: true,
|
|
16706
17069
|
options: {
|
|
16707
|
-
|
|
16708
|
-
|
|
16709
|
-
text: { type: "string" },
|
|
16710
|
-
runs: { type: "string" },
|
|
16711
|
-
style: { type: "string" },
|
|
16712
|
-
alignment: { type: "string" },
|
|
16713
|
-
color: { type: "string" },
|
|
16714
|
-
bold: { type: "boolean" },
|
|
16715
|
-
italic: { type: "boolean" },
|
|
16716
|
-
"dry-run": { type: "boolean" },
|
|
17070
|
+
json: { type: "boolean" },
|
|
17071
|
+
ts: { type: "boolean" },
|
|
16717
17072
|
help: { type: "boolean", short: "h" }
|
|
16718
17073
|
}
|
|
16719
17074
|
});
|
|
16720
17075
|
} catch (parseError) {
|
|
16721
17076
|
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
16722
|
-
return fail("USAGE", message,
|
|
17077
|
+
return fail("USAGE", message, HELP16);
|
|
16723
17078
|
}
|
|
16724
17079
|
if (parsed.values.help) {
|
|
16725
|
-
await writeStdout(
|
|
17080
|
+
await writeStdout(HELP16);
|
|
16726
17081
|
return EXIT.OK;
|
|
16727
17082
|
}
|
|
16728
|
-
|
|
16729
|
-
|
|
16730
|
-
return
|
|
16731
|
-
|
|
17083
|
+
if (parsed.values.ts) {
|
|
17084
|
+
await writeStdout(types_default);
|
|
17085
|
+
return EXIT.OK;
|
|
17086
|
+
}
|
|
17087
|
+
await respond(JSON_SCHEMA);
|
|
17088
|
+
return EXIT.OK;
|
|
17089
|
+
}
|
|
17090
|
+
var HELP16 = `docx schema \u2014 print the AST type definitions
|
|
17091
|
+
|
|
17092
|
+
Usage:
|
|
17093
|
+
docx schema [options]
|
|
17094
|
+
|
|
17095
|
+
Options:
|
|
17096
|
+
--json Print as a JSON Schema document (default)
|
|
17097
|
+
--ts Print TypeScript type source (read live from src/core/ast/types.ts)
|
|
17098
|
+
-h, --help Show this help
|
|
17099
|
+
|
|
17100
|
+
Examples:
|
|
17101
|
+
docx schema | jq '.definitions.Run'
|
|
17102
|
+
docx schema --ts > ast.d.ts
|
|
17103
|
+
`, JSON_SCHEMA;
|
|
17104
|
+
var init_schema = __esm(() => {
|
|
17105
|
+
init_types();
|
|
17106
|
+
init_respond();
|
|
17107
|
+
JSON_SCHEMA = {
|
|
17108
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
17109
|
+
$id: "https://github.com/kklimuk/docx-cli/schema",
|
|
17110
|
+
title: "docx-cli AST",
|
|
17111
|
+
type: "object",
|
|
17112
|
+
required: ["schemaVersion", "path", "properties", "blocks", "comments"],
|
|
17113
|
+
properties: {
|
|
17114
|
+
schemaVersion: { const: 1 },
|
|
17115
|
+
path: { type: "string" },
|
|
17116
|
+
properties: {
|
|
17117
|
+
type: "object",
|
|
17118
|
+
properties: {
|
|
17119
|
+
title: { type: "string" },
|
|
17120
|
+
author: { type: "string" },
|
|
17121
|
+
created: { type: "string" },
|
|
17122
|
+
modified: { type: "string" }
|
|
17123
|
+
}
|
|
17124
|
+
},
|
|
17125
|
+
blocks: { type: "array", items: { $ref: "#/$defs/Block" } },
|
|
17126
|
+
comments: { type: "array", items: { $ref: "#/$defs/Comment" } }
|
|
17127
|
+
},
|
|
17128
|
+
$defs: {
|
|
17129
|
+
Block: {
|
|
17130
|
+
oneOf: [
|
|
17131
|
+
{ $ref: "#/$defs/Paragraph" },
|
|
17132
|
+
{ $ref: "#/$defs/Table" },
|
|
17133
|
+
{ $ref: "#/$defs/SectionBreak" }
|
|
17134
|
+
]
|
|
17135
|
+
},
|
|
17136
|
+
Paragraph: {
|
|
17137
|
+
type: "object",
|
|
17138
|
+
required: ["id", "type", "runs"],
|
|
17139
|
+
properties: {
|
|
17140
|
+
id: { type: "string" },
|
|
17141
|
+
type: { const: "paragraph" },
|
|
17142
|
+
style: { type: "string" },
|
|
17143
|
+
alignment: { enum: ["left", "center", "right", "justify"] },
|
|
17144
|
+
list: {
|
|
17145
|
+
type: "object",
|
|
17146
|
+
required: ["level", "numId"],
|
|
17147
|
+
properties: {
|
|
17148
|
+
level: { type: "number" },
|
|
17149
|
+
numId: { type: "string" }
|
|
17150
|
+
}
|
|
17151
|
+
},
|
|
17152
|
+
runs: { type: "array", items: { $ref: "#/$defs/Run" } }
|
|
17153
|
+
}
|
|
17154
|
+
},
|
|
17155
|
+
Run: {
|
|
17156
|
+
oneOf: [
|
|
17157
|
+
{ $ref: "#/$defs/TextRun" },
|
|
17158
|
+
{ $ref: "#/$defs/ImageRun" },
|
|
17159
|
+
{ $ref: "#/$defs/BreakRun" },
|
|
17160
|
+
{ $ref: "#/$defs/TabRun" }
|
|
17161
|
+
]
|
|
17162
|
+
},
|
|
17163
|
+
TextRun: {
|
|
17164
|
+
type: "object",
|
|
17165
|
+
required: ["type", "text"],
|
|
17166
|
+
properties: {
|
|
17167
|
+
type: { const: "text" },
|
|
17168
|
+
text: { type: "string" },
|
|
17169
|
+
color: { type: "string" },
|
|
17170
|
+
highlight: { type: "string" },
|
|
17171
|
+
bold: { type: "boolean" },
|
|
17172
|
+
italic: { type: "boolean" },
|
|
17173
|
+
underline: { type: "string" },
|
|
17174
|
+
strike: { type: "boolean" },
|
|
17175
|
+
font: { type: "string" },
|
|
17176
|
+
sizeHalfPoints: { type: "number" },
|
|
17177
|
+
comments: { type: "array", items: { type: "string" } },
|
|
17178
|
+
trackedChange: {
|
|
17179
|
+
type: "object",
|
|
17180
|
+
required: ["kind", "author", "date", "revisionId"],
|
|
17181
|
+
properties: {
|
|
17182
|
+
kind: { enum: ["ins", "del"] },
|
|
17183
|
+
author: { type: "string" },
|
|
17184
|
+
date: { type: "string" },
|
|
17185
|
+
revisionId: { type: "string" }
|
|
17186
|
+
}
|
|
17187
|
+
}
|
|
17188
|
+
}
|
|
17189
|
+
},
|
|
17190
|
+
ImageRun: {
|
|
17191
|
+
type: "object",
|
|
17192
|
+
required: ["type", "id", "contentType", "hash"],
|
|
17193
|
+
properties: {
|
|
17194
|
+
type: { const: "image" },
|
|
17195
|
+
id: { type: "string" },
|
|
17196
|
+
contentType: { type: "string" },
|
|
17197
|
+
hash: { type: "string" },
|
|
17198
|
+
widthEmu: { type: "number" },
|
|
17199
|
+
heightEmu: { type: "number" },
|
|
17200
|
+
alt: { type: "string" }
|
|
17201
|
+
}
|
|
17202
|
+
},
|
|
17203
|
+
BreakRun: {
|
|
17204
|
+
type: "object",
|
|
17205
|
+
required: ["type", "kind"],
|
|
17206
|
+
properties: {
|
|
17207
|
+
type: { const: "break" },
|
|
17208
|
+
kind: { enum: ["page", "line", "column"] }
|
|
17209
|
+
}
|
|
17210
|
+
},
|
|
17211
|
+
TabRun: {
|
|
17212
|
+
type: "object",
|
|
17213
|
+
required: ["type"],
|
|
17214
|
+
properties: { type: { const: "tab" } }
|
|
17215
|
+
},
|
|
17216
|
+
Table: {
|
|
17217
|
+
type: "object",
|
|
17218
|
+
required: ["id", "type", "rows"],
|
|
17219
|
+
properties: {
|
|
17220
|
+
id: { type: "string" },
|
|
17221
|
+
type: { const: "table" },
|
|
17222
|
+
rows: {
|
|
17223
|
+
type: "array",
|
|
17224
|
+
items: {
|
|
17225
|
+
type: "object",
|
|
17226
|
+
properties: {
|
|
17227
|
+
cells: {
|
|
17228
|
+
type: "array",
|
|
17229
|
+
items: {
|
|
17230
|
+
type: "object",
|
|
17231
|
+
properties: {
|
|
17232
|
+
blocks: {
|
|
17233
|
+
type: "array",
|
|
17234
|
+
items: { $ref: "#/$defs/Block" }
|
|
17235
|
+
}
|
|
17236
|
+
}
|
|
17237
|
+
}
|
|
17238
|
+
}
|
|
17239
|
+
}
|
|
17240
|
+
}
|
|
17241
|
+
}
|
|
17242
|
+
}
|
|
17243
|
+
},
|
|
17244
|
+
SectionBreak: {
|
|
17245
|
+
type: "object",
|
|
17246
|
+
required: ["id", "type"],
|
|
17247
|
+
properties: {
|
|
17248
|
+
id: { type: "string" },
|
|
17249
|
+
type: { const: "sectionBreak" }
|
|
17250
|
+
}
|
|
17251
|
+
},
|
|
17252
|
+
Comment: {
|
|
17253
|
+
type: "object",
|
|
17254
|
+
required: ["id", "author", "date", "text", "anchor"],
|
|
17255
|
+
properties: {
|
|
17256
|
+
id: { type: "string" },
|
|
17257
|
+
author: { type: "string" },
|
|
17258
|
+
initials: { type: "string" },
|
|
17259
|
+
date: { type: "string" },
|
|
17260
|
+
text: { type: "string" },
|
|
17261
|
+
parentId: { type: "string" },
|
|
17262
|
+
resolved: { type: "boolean" },
|
|
17263
|
+
anchor: {
|
|
17264
|
+
type: "object",
|
|
17265
|
+
required: ["startBlockId", "startOffset", "endBlockId", "endOffset"],
|
|
17266
|
+
properties: {
|
|
17267
|
+
startBlockId: { type: "string" },
|
|
17268
|
+
startOffset: { type: "number" },
|
|
17269
|
+
endBlockId: { type: "string" },
|
|
17270
|
+
endOffset: { type: "number" }
|
|
17271
|
+
}
|
|
17272
|
+
}
|
|
17273
|
+
}
|
|
17274
|
+
}
|
|
17275
|
+
}
|
|
17276
|
+
};
|
|
17277
|
+
});
|
|
17278
|
+
|
|
17279
|
+
// src/cli/info/locators.ts
|
|
17280
|
+
var exports_locators = {};
|
|
17281
|
+
__export(exports_locators, {
|
|
17282
|
+
run: () => run17
|
|
17283
|
+
});
|
|
17284
|
+
import { parseArgs as parseArgs15 } from "util";
|
|
17285
|
+
async function run17(args) {
|
|
17286
|
+
let parsed;
|
|
17287
|
+
try {
|
|
17288
|
+
parsed = parseArgs15({
|
|
17289
|
+
args,
|
|
17290
|
+
allowPositionals: true,
|
|
17291
|
+
options: {
|
|
17292
|
+
json: { type: "boolean" },
|
|
17293
|
+
help: { type: "boolean", short: "h" }
|
|
17294
|
+
}
|
|
17295
|
+
});
|
|
17296
|
+
} catch (parseError) {
|
|
17297
|
+
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
17298
|
+
return fail("USAGE", message, HELP17);
|
|
17299
|
+
}
|
|
17300
|
+
if (parsed.values.help) {
|
|
17301
|
+
await writeStdout(HELP17);
|
|
17302
|
+
return EXIT.OK;
|
|
17303
|
+
}
|
|
17304
|
+
if (parsed.values.json) {
|
|
17305
|
+
await writeStdout(`${JSON.stringify(JSON_REFERENCE, null, 2)}
|
|
17306
|
+
`);
|
|
17307
|
+
return EXIT.OK;
|
|
17308
|
+
}
|
|
17309
|
+
await writeStdout(REFERENCE);
|
|
17310
|
+
return EXIT.OK;
|
|
17311
|
+
}
|
|
17312
|
+
var HELP17 = `docx locators \u2014 print the locator grammar reference
|
|
17313
|
+
|
|
17314
|
+
Usage:
|
|
17315
|
+
docx locators [options]
|
|
17316
|
+
|
|
17317
|
+
Options:
|
|
17318
|
+
--json Print as JSON
|
|
17319
|
+
-h, --help Show this help
|
|
17320
|
+
`, REFERENCE = `LOCATOR GRAMMAR
|
|
17321
|
+
|
|
17322
|
+
Block locators:
|
|
17323
|
+
pN Paragraph N (e.g., p3)
|
|
17324
|
+
tN Table N
|
|
17325
|
+
sN Section break N
|
|
17326
|
+
tT:rRcC:pK Paragraph K of cell (R,C) in table T
|
|
17327
|
+
|
|
17328
|
+
Span locators (within a single paragraph):
|
|
17329
|
+
pN:S-E Characters S..E of paragraph N (inclusive start, exclusive end)
|
|
17330
|
+
tT:rRcC:pK:S-E Characters S..E of a cell paragraph
|
|
17331
|
+
|
|
17332
|
+
Range locators (across blocks):
|
|
17333
|
+
pN:S-pM:E From char S of paragraph N to char E of paragraph M
|
|
17334
|
+
|
|
17335
|
+
Entity locators:
|
|
17336
|
+
cN Comment id (e.g., c0)
|
|
17337
|
+
imgN Image id (e.g., img2)
|
|
17338
|
+
tN:rRcC Cell at row R, column C of table tN
|
|
17339
|
+
|
|
17340
|
+
Examples:
|
|
17341
|
+
p3 -> the entire paragraph p3
|
|
17342
|
+
p3:5-20 -> characters 5..20 of p3
|
|
17343
|
+
p3:5-p5:10 -> from char 5 of p3 to char 10 of p5
|
|
17344
|
+
c1 -> comment c1
|
|
17345
|
+
img0 -> image img0
|
|
17346
|
+
t0:r1c2 -> cell at row 1, col 2 of table t0
|
|
17347
|
+
t0:r1c2:p0 -> first paragraph of that cell
|
|
17348
|
+
t0:r1c2:p0:5-10 -> chars 5..10 of that paragraph
|
|
17349
|
+
|
|
17350
|
+
Notes:
|
|
17351
|
+
Block ids are positional and shift after structural edits \u2014 re-read
|
|
17352
|
+
between non-trivial mutations. Mutating commands print before/after
|
|
17353
|
+
locator info in their JSON ack so agents can chain operations.
|
|
17354
|
+
`, JSON_REFERENCE;
|
|
17355
|
+
var init_locators2 = __esm(() => {
|
|
17356
|
+
init_respond();
|
|
17357
|
+
JSON_REFERENCE = {
|
|
17358
|
+
blockLocators: {
|
|
17359
|
+
paragraph: { syntax: "pN", example: "p3" },
|
|
17360
|
+
table: { syntax: "tN", example: "t0" },
|
|
17361
|
+
sectionBreak: { syntax: "sN", example: "s0" },
|
|
17362
|
+
cellParagraph: { syntax: "tT:rRcC:pK", example: "t0:r1c2:p0" }
|
|
17363
|
+
},
|
|
17364
|
+
spanLocator: {
|
|
17365
|
+
syntax: "pN:S-E",
|
|
17366
|
+
example: "p3:5-20",
|
|
17367
|
+
semantics: "Characters S..E within paragraph N (start inclusive, end exclusive)",
|
|
17368
|
+
cellSyntax: "tT:rRcC:pK:S-E"
|
|
17369
|
+
},
|
|
17370
|
+
rangeLocator: {
|
|
17371
|
+
syntax: "pN:S-pM:E",
|
|
17372
|
+
example: "p3:5-p5:10",
|
|
17373
|
+
semantics: "From char S of paragraph N to char E of paragraph M"
|
|
17374
|
+
},
|
|
17375
|
+
entityLocators: {
|
|
17376
|
+
comment: { syntax: "cN", example: "c1" },
|
|
17377
|
+
image: { syntax: "imgN", example: "img0" },
|
|
17378
|
+
cell: { syntax: "tN:rRcC", example: "t0:r1c2" },
|
|
17379
|
+
nestedCell: { syntax: "tN:rRcC:pK", example: "t0:r1c2:p0" }
|
|
17380
|
+
},
|
|
17381
|
+
notes: [
|
|
17382
|
+
"Block ids are positional and shift after structural edits.",
|
|
17383
|
+
"Re-read between non-trivial mutations.",
|
|
17384
|
+
"Mutating commands print before/after locator info in their JSON ack."
|
|
17385
|
+
]
|
|
17386
|
+
};
|
|
17387
|
+
});
|
|
17388
|
+
|
|
17389
|
+
// src/cli/info/index.ts
|
|
17390
|
+
var exports_info = {};
|
|
17391
|
+
__export(exports_info, {
|
|
17392
|
+
run: () => run18
|
|
17393
|
+
});
|
|
17394
|
+
async function run18(args) {
|
|
17395
|
+
const topic = args[0];
|
|
17396
|
+
if (!topic || topic === "--help" || topic === "-h" || topic === "help") {
|
|
17397
|
+
await writeStdout(HELP18);
|
|
17398
|
+
return topic ? 0 : 2;
|
|
17399
|
+
}
|
|
17400
|
+
const loader = SUBCOMMANDS3[topic];
|
|
17401
|
+
if (!loader) {
|
|
17402
|
+
return fail("USAGE", `Unknown info topic: ${topic}`, 'Run "docx info --help".');
|
|
17403
|
+
}
|
|
17404
|
+
const module_ = await loader();
|
|
17405
|
+
return module_.run(args.slice(1));
|
|
17406
|
+
}
|
|
17407
|
+
var SUBCOMMANDS3, HELP18 = `docx info \u2014 print reference material about the CLI
|
|
17408
|
+
|
|
17409
|
+
Usage:
|
|
17410
|
+
docx info <topic> [options]
|
|
17411
|
+
|
|
17412
|
+
Topics:
|
|
17413
|
+
schema Dump AST JSON Schema (or TS source via --ts)
|
|
17414
|
+
locators Dump locator grammar reference
|
|
17415
|
+
|
|
17416
|
+
Run "docx info <topic> --help" for topic-specific help.
|
|
17417
|
+
`;
|
|
17418
|
+
var init_info = __esm(() => {
|
|
17419
|
+
init_respond();
|
|
17420
|
+
SUBCOMMANDS3 = {
|
|
17421
|
+
schema: () => Promise.resolve().then(() => (init_schema(), exports_schema)),
|
|
17422
|
+
locators: () => Promise.resolve().then(() => (init_locators2(), exports_locators))
|
|
17423
|
+
};
|
|
17424
|
+
});
|
|
17425
|
+
|
|
17426
|
+
// src/cli/insert/index.tsx
|
|
17427
|
+
var exports_insert = {};
|
|
17428
|
+
__export(exports_insert, {
|
|
17429
|
+
run: () => run19
|
|
17430
|
+
});
|
|
17431
|
+
import { parseArgs as parseArgs16 } from "util";
|
|
17432
|
+
async function run19(args) {
|
|
17433
|
+
let parsed;
|
|
17434
|
+
try {
|
|
17435
|
+
parsed = parseArgs16({
|
|
17436
|
+
args,
|
|
17437
|
+
allowPositionals: true,
|
|
17438
|
+
options: {
|
|
17439
|
+
after: { type: "string" },
|
|
17440
|
+
before: { type: "string" },
|
|
17441
|
+
text: { type: "string" },
|
|
17442
|
+
runs: { type: "string" },
|
|
17443
|
+
style: { type: "string" },
|
|
17444
|
+
alignment: { type: "string" },
|
|
17445
|
+
color: { type: "string" },
|
|
17446
|
+
bold: { type: "boolean" },
|
|
17447
|
+
italic: { type: "boolean" },
|
|
17448
|
+
"dry-run": { type: "boolean" },
|
|
17449
|
+
help: { type: "boolean", short: "h" }
|
|
17450
|
+
}
|
|
17451
|
+
});
|
|
17452
|
+
} catch (parseError) {
|
|
17453
|
+
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
17454
|
+
return fail("USAGE", message, HELP19);
|
|
17455
|
+
}
|
|
17456
|
+
if (parsed.values.help) {
|
|
17457
|
+
await writeStdout(HELP19);
|
|
17458
|
+
return EXIT.OK;
|
|
17459
|
+
}
|
|
17460
|
+
const path = parsed.positionals[0];
|
|
17461
|
+
if (!path)
|
|
17462
|
+
return fail("USAGE", "Missing FILE argument", HELP19);
|
|
17463
|
+
const after = parsed.values.after;
|
|
16732
17464
|
const before = parsed.values.before;
|
|
16733
17465
|
if (!after && !before) {
|
|
16734
|
-
return fail("USAGE", "Missing locator: pass --after or --before",
|
|
17466
|
+
return fail("USAGE", "Missing locator: pass --after or --before", HELP19);
|
|
16735
17467
|
}
|
|
16736
17468
|
if (after && before) {
|
|
16737
|
-
return fail("USAGE", "Pass either --after or --before, not both",
|
|
17469
|
+
return fail("USAGE", "Pass either --after or --before, not both", HELP19);
|
|
16738
17470
|
}
|
|
16739
17471
|
const text = parsed.values.text;
|
|
16740
17472
|
const runsJson = parsed.values.runs;
|
|
16741
17473
|
if (!text && !runsJson) {
|
|
16742
|
-
return fail("USAGE", "Missing content: pass --text or --runs",
|
|
17474
|
+
return fail("USAGE", "Missing content: pass --text or --runs", HELP19);
|
|
16743
17475
|
}
|
|
16744
17476
|
if (text && runsJson) {
|
|
16745
|
-
return fail("USAGE", "Pass either --text or --runs, not both",
|
|
17477
|
+
return fail("USAGE", "Pass either --text or --runs, not both", HELP19);
|
|
16746
17478
|
}
|
|
16747
17479
|
const paragraphOptions = {};
|
|
16748
17480
|
const styleValue = parsed.values.style;
|
|
@@ -16755,30 +17487,13 @@ async function run15(args) {
|
|
|
16755
17487
|
}
|
|
16756
17488
|
paragraphOptions.alignment = alignmentValue;
|
|
16757
17489
|
}
|
|
16758
|
-
|
|
16759
|
-
|
|
16760
|
-
view
|
|
16761
|
-
} catch (openError) {
|
|
16762
|
-
if (openError instanceof PkgError) {
|
|
16763
|
-
if (openError.code === "FILE_NOT_FOUND") {
|
|
16764
|
-
return fail("FILE_NOT_FOUND", openError.message);
|
|
16765
|
-
}
|
|
16766
|
-
if (openError.code === "NOT_A_ZIP") {
|
|
16767
|
-
return fail("NOT_A_ZIP", openError.message);
|
|
16768
|
-
}
|
|
16769
|
-
}
|
|
16770
|
-
throw openError;
|
|
16771
|
-
}
|
|
17490
|
+
const view = await openOrFail(path);
|
|
17491
|
+
if (typeof view === "number")
|
|
17492
|
+
return view;
|
|
16772
17493
|
const targetLocator = after ?? before;
|
|
16773
|
-
|
|
16774
|
-
|
|
16775
|
-
blockRef
|
|
16776
|
-
} catch (resolveError) {
|
|
16777
|
-
if (resolveError instanceof LocatorResolveError) {
|
|
16778
|
-
return fail("BLOCK_NOT_FOUND", resolveError.message);
|
|
16779
|
-
}
|
|
16780
|
-
throw resolveError;
|
|
16781
|
-
}
|
|
17494
|
+
const blockRef = await resolveBlockOrFail(view, targetLocator);
|
|
17495
|
+
if (typeof blockRef === "number")
|
|
17496
|
+
return blockRef;
|
|
16782
17497
|
let paragraphNode;
|
|
16783
17498
|
if (text !== undefined) {
|
|
16784
17499
|
const color = parsed.values.color;
|
|
@@ -16832,7 +17547,7 @@ async function run15(args) {
|
|
|
16832
17547
|
});
|
|
16833
17548
|
return EXIT.OK;
|
|
16834
17549
|
}
|
|
16835
|
-
var
|
|
17550
|
+
var HELP19 = `docx insert \u2014 insert a paragraph at a locator
|
|
16836
17551
|
|
|
16837
17552
|
Usage:
|
|
16838
17553
|
docx insert FILE [options]
|
|
@@ -16855,137 +17570,30 @@ Run options (only with --text):
|
|
|
16855
17570
|
--italic Italic
|
|
16856
17571
|
|
|
16857
17572
|
--dry-run Print what would be inserted; do not write the file
|
|
16858
|
-
-h, --help Show this help
|
|
16859
|
-
|
|
16860
|
-
Examples:
|
|
16861
|
-
docx insert doc.docx --after p3 --text "Section header" --style Heading2
|
|
16862
|
-
docx insert doc.docx --before p0 --text "ALERT" --color CC0000 --bold
|
|
16863
|
-
docx insert doc.docx --after p2 --runs '[{"type":"text","text":"X","bold":true}]'
|
|
16864
|
-
`;
|
|
16865
|
-
var init_insert = __esm(() => {
|
|
16866
|
-
init_core();
|
|
16867
|
-
init_respond();
|
|
16868
|
-
init_emit();
|
|
16869
|
-
init_jsx_dev_runtime();
|
|
16870
|
-
});
|
|
16871
|
-
|
|
16872
|
-
// src/cli/locators-cmd/index.ts
|
|
16873
|
-
var exports_locators_cmd = {};
|
|
16874
|
-
__export(exports_locators_cmd, {
|
|
16875
|
-
run: () => run16
|
|
16876
|
-
});
|
|
16877
|
-
import { parseArgs as parseArgs14 } from "util";
|
|
16878
|
-
async function run16(args) {
|
|
16879
|
-
let parsed;
|
|
16880
|
-
try {
|
|
16881
|
-
parsed = parseArgs14({
|
|
16882
|
-
args,
|
|
16883
|
-
allowPositionals: true,
|
|
16884
|
-
options: {
|
|
16885
|
-
json: { type: "boolean" },
|
|
16886
|
-
help: { type: "boolean", short: "h" }
|
|
16887
|
-
}
|
|
16888
|
-
});
|
|
16889
|
-
} catch (parseError) {
|
|
16890
|
-
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
16891
|
-
return fail("USAGE", message, HELP16);
|
|
16892
|
-
}
|
|
16893
|
-
if (parsed.values.help) {
|
|
16894
|
-
await writeStdout(HELP16);
|
|
16895
|
-
return EXIT.OK;
|
|
16896
|
-
}
|
|
16897
|
-
if (parsed.values.json) {
|
|
16898
|
-
await Bun.write(Bun.stdout, `${JSON.stringify(JSON_REFERENCE, null, 2)}
|
|
16899
|
-
`);
|
|
16900
|
-
return EXIT.OK;
|
|
16901
|
-
}
|
|
16902
|
-
await Bun.write(Bun.stdout, REFERENCE);
|
|
16903
|
-
return EXIT.OK;
|
|
16904
|
-
}
|
|
16905
|
-
var HELP16 = `docx locators \u2014 print the locator grammar reference
|
|
16906
|
-
|
|
16907
|
-
Usage:
|
|
16908
|
-
docx locators [options]
|
|
16909
|
-
|
|
16910
|
-
Options:
|
|
16911
|
-
--json Print as JSON
|
|
16912
|
-
-h, --help Show this help
|
|
16913
|
-
`, REFERENCE = `LOCATOR GRAMMAR
|
|
16914
|
-
|
|
16915
|
-
Block locators:
|
|
16916
|
-
pN Paragraph N (e.g., p3)
|
|
16917
|
-
tN Table N
|
|
16918
|
-
sN Section break N
|
|
16919
|
-
cellpN Paragraph inside a table cell
|
|
16920
|
-
|
|
16921
|
-
Span locators (within a single paragraph):
|
|
16922
|
-
pN:S-E Characters S..E of paragraph N (inclusive start, exclusive end)
|
|
16923
|
-
|
|
16924
|
-
Range locators (across blocks):
|
|
16925
|
-
pN:S-pM:E From char S of paragraph N to char E of paragraph M
|
|
16926
|
-
|
|
16927
|
-
Entity locators:
|
|
16928
|
-
cN Comment id (e.g., c0)
|
|
16929
|
-
imgN Image id (e.g., img2)
|
|
16930
|
-
tN:rRcC Cell at row R, column C of table tN
|
|
17573
|
+
-h, --help Show this help
|
|
16931
17574
|
|
|
16932
17575
|
Examples:
|
|
16933
|
-
p3
|
|
16934
|
-
|
|
16935
|
-
|
|
16936
|
-
|
|
16937
|
-
|
|
16938
|
-
|
|
16939
|
-
t0:r1c2:p0 -> first paragraph of that cell
|
|
16940
|
-
|
|
16941
|
-
Notes:
|
|
16942
|
-
Block ids are positional and shift after structural edits \u2014 re-read
|
|
16943
|
-
between non-trivial mutations. Mutating commands print before/after
|
|
16944
|
-
locator info in their JSON ack so agents can chain operations.
|
|
16945
|
-
`, JSON_REFERENCE;
|
|
16946
|
-
var init_locators_cmd = __esm(() => {
|
|
17576
|
+
docx insert doc.docx --after p3 --text "Section header" --style Heading2
|
|
17577
|
+
docx insert doc.docx --before p0 --text "ALERT" --color CC0000 --bold
|
|
17578
|
+
docx insert doc.docx --after p2 --runs '[{"type":"text","text":"X","bold":true}]'
|
|
17579
|
+
`;
|
|
17580
|
+
var init_insert = __esm(() => {
|
|
17581
|
+
init_core();
|
|
16947
17582
|
init_respond();
|
|
16948
|
-
|
|
16949
|
-
|
|
16950
|
-
paragraph: { syntax: "pN", example: "p3" },
|
|
16951
|
-
table: { syntax: "tN", example: "t0" },
|
|
16952
|
-
sectionBreak: { syntax: "sN", example: "s0" },
|
|
16953
|
-
cellParagraph: { syntax: "cellpN", example: "cellp0" }
|
|
16954
|
-
},
|
|
16955
|
-
spanLocator: {
|
|
16956
|
-
syntax: "pN:S-E",
|
|
16957
|
-
example: "p3:5-20",
|
|
16958
|
-
semantics: "Characters S..E within paragraph N (start inclusive, end exclusive)"
|
|
16959
|
-
},
|
|
16960
|
-
rangeLocator: {
|
|
16961
|
-
syntax: "pN:S-pM:E",
|
|
16962
|
-
example: "p3:5-p5:10",
|
|
16963
|
-
semantics: "From char S of paragraph N to char E of paragraph M"
|
|
16964
|
-
},
|
|
16965
|
-
entityLocators: {
|
|
16966
|
-
comment: { syntax: "cN", example: "c1" },
|
|
16967
|
-
image: { syntax: "imgN", example: "img0" },
|
|
16968
|
-
cell: { syntax: "tN:rRcC", example: "t0:r1c2" },
|
|
16969
|
-
nestedCell: { syntax: "tN:rRcC:pK", example: "t0:r1c2:p0" }
|
|
16970
|
-
},
|
|
16971
|
-
notes: [
|
|
16972
|
-
"Block ids are positional and shift after structural edits.",
|
|
16973
|
-
"Re-read between non-trivial mutations.",
|
|
16974
|
-
"Mutating commands print before/after locator info in their JSON ack."
|
|
16975
|
-
]
|
|
16976
|
-
};
|
|
17583
|
+
init_emit();
|
|
17584
|
+
init_jsx_dev_runtime();
|
|
16977
17585
|
});
|
|
16978
17586
|
|
|
16979
17587
|
// src/cli/read/index.ts
|
|
16980
17588
|
var exports_read = {};
|
|
16981
17589
|
__export(exports_read, {
|
|
16982
|
-
run: () =>
|
|
17590
|
+
run: () => run20
|
|
16983
17591
|
});
|
|
16984
|
-
import { parseArgs as
|
|
16985
|
-
async function
|
|
17592
|
+
import { parseArgs as parseArgs17 } from "util";
|
|
17593
|
+
async function run20(args) {
|
|
16986
17594
|
let parsed;
|
|
16987
17595
|
try {
|
|
16988
|
-
parsed =
|
|
17596
|
+
parsed = parseArgs17({
|
|
16989
17597
|
args,
|
|
16990
17598
|
allowPositionals: true,
|
|
16991
17599
|
options: {
|
|
@@ -16994,32 +17602,23 @@ async function run17(args) {
|
|
|
16994
17602
|
}
|
|
16995
17603
|
});
|
|
16996
17604
|
} catch (e) {
|
|
16997
|
-
return fail("USAGE", e instanceof Error ? e.message : String(e),
|
|
17605
|
+
return fail("USAGE", e instanceof Error ? e.message : String(e), HELP20);
|
|
16998
17606
|
}
|
|
16999
17607
|
if (parsed.values.help) {
|
|
17000
|
-
await writeStdout(
|
|
17608
|
+
await writeStdout(HELP20);
|
|
17001
17609
|
return EXIT.OK;
|
|
17002
17610
|
}
|
|
17003
17611
|
const path = parsed.positionals[0];
|
|
17004
17612
|
if (!path)
|
|
17005
|
-
return fail("USAGE", "Missing FILE argument",
|
|
17006
|
-
|
|
17007
|
-
|
|
17008
|
-
view
|
|
17009
|
-
} catch (e) {
|
|
17010
|
-
if (e instanceof PkgError) {
|
|
17011
|
-
if (e.code === "FILE_NOT_FOUND")
|
|
17012
|
-
return fail("FILE_NOT_FOUND", e.message);
|
|
17013
|
-
if (e.code === "NOT_A_ZIP")
|
|
17014
|
-
return fail("NOT_A_ZIP", e.message);
|
|
17015
|
-
}
|
|
17016
|
-
throw e;
|
|
17017
|
-
}
|
|
17613
|
+
return fail("USAGE", "Missing FILE argument", HELP20);
|
|
17614
|
+
const view = await openOrFail(path);
|
|
17615
|
+
if (typeof view === "number")
|
|
17616
|
+
return view;
|
|
17018
17617
|
await enrichImageHashes(view);
|
|
17019
17618
|
await respond(view.doc);
|
|
17020
17619
|
return EXIT.OK;
|
|
17021
17620
|
}
|
|
17022
|
-
var
|
|
17621
|
+
var HELP20 = `docx read \u2014 print AST as JSON
|
|
17023
17622
|
|
|
17024
17623
|
Usage:
|
|
17025
17624
|
docx read FILE [options]
|
|
@@ -17037,348 +17636,336 @@ var init_read2 = __esm(() => {
|
|
|
17037
17636
|
init_respond();
|
|
17038
17637
|
});
|
|
17039
17638
|
|
|
17040
|
-
// src/
|
|
17041
|
-
|
|
17042
|
-
|
|
17043
|
-
|
|
17044
|
-
|
|
17045
|
-
|
|
17046
|
-
|
|
17047
|
-
|
|
17048
|
-
|
|
17049
|
-
|
|
17050
|
-
|
|
17051
|
-
|
|
17052
|
-
|
|
17053
|
-
|
|
17054
|
-
|
|
17055
|
-
|
|
17056
|
-
|
|
17057
|
-
|
|
17058
|
-
|
|
17059
|
-
|
|
17060
|
-
|
|
17061
|
-
|
|
17062
|
-
|
|
17063
|
-
|
|
17064
|
-
|
|
17065
|
-
|
|
17066
|
-
|
|
17067
|
-
|
|
17068
|
-
|
|
17069
|
-
|
|
17070
|
-
|
|
17071
|
-
|
|
17072
|
-
|
|
17073
|
-
|
|
17074
|
-
|
|
17075
|
-
}
|
|
17076
|
-
|
|
17077
|
-
|
|
17078
|
-
|
|
17079
|
-
|
|
17080
|
-
|
|
17081
|
-
|
|
17082
|
-
|
|
17083
|
-
|
|
17084
|
-
|
|
17085
|
-
|
|
17086
|
-
|
|
17087
|
-
|
|
17088
|
-
|
|
17089
|
-
|
|
17090
|
-
|
|
17091
|
-
|
|
17092
|
-
|
|
17093
|
-
|
|
17094
|
-
|
|
17095
|
-
|
|
17096
|
-
|
|
17097
|
-
|
|
17098
|
-
|
|
17099
|
-
|
|
17100
|
-
|
|
17101
|
-
|
|
17102
|
-
|
|
17103
|
-
|
|
17104
|
-
|
|
17105
|
-
|
|
17106
|
-
|
|
17107
|
-
|
|
17108
|
-
|
|
17109
|
-
|
|
17110
|
-
|
|
17111
|
-
|
|
17112
|
-
|
|
17113
|
-
|
|
17114
|
-
|
|
17115
|
-
|
|
17116
|
-
|
|
17117
|
-
|
|
17118
|
-
|
|
17119
|
-
|
|
17120
|
-
|
|
17121
|
-
|
|
17122
|
-
|
|
17123
|
-
|
|
17124
|
-
|
|
17125
|
-
|
|
17126
|
-
|
|
17127
|
-
|
|
17128
|
-
}
|
|
17129
|
-
|
|
17130
|
-
|
|
17131
|
-
|
|
17132
|
-
|
|
17133
|
-
|
|
17134
|
-
|
|
17135
|
-
|
|
17136
|
-
|
|
17137
|
-
|
|
17138
|
-
|
|
17139
|
-
|
|
17140
|
-
|
|
17141
|
-
|
|
17142
|
-
|
|
17143
|
-
|
|
17144
|
-
|
|
17145
|
-
|
|
17146
|
-
|
|
17147
|
-
|
|
17148
|
-
|
|
17639
|
+
// src/cli/replace/replace-span.tsx
|
|
17640
|
+
function replaceSpanInParagraph(paragraph, span, replacement) {
|
|
17641
|
+
if (span.start > span.end) {
|
|
17642
|
+
throw new Error(`replaceSpanInParagraph: invalid span ${span.start}-${span.end}`);
|
|
17643
|
+
}
|
|
17644
|
+
const slots = collectRunSlots(paragraph);
|
|
17645
|
+
const overlapping = slots.filter((slot) => slot.offsetBefore + slot.length > span.start && slot.offsetBefore < span.end);
|
|
17646
|
+
const firstSlot = overlapping[0];
|
|
17647
|
+
if (!firstSlot) {
|
|
17648
|
+
paragraph.children.push(replacementRun(null, replacement));
|
|
17649
|
+
return;
|
|
17650
|
+
}
|
|
17651
|
+
const firstParent = firstSlot.parent;
|
|
17652
|
+
if (overlapping.some((slot) => slot.parent !== firstParent)) {
|
|
17653
|
+
throw new TrackedChangeBoundaryError("Span crosses a tracked-change (<w:ins>/<w:del>) boundary; accept or reject the tracked change first.");
|
|
17654
|
+
}
|
|
17655
|
+
const firstRunProperties = firstSlot.run.findChild("w:rPr");
|
|
17656
|
+
const inheritedProperties = firstRunProperties ? deepCloneNode(firstRunProperties) : null;
|
|
17657
|
+
const containerStart = firstParent === paragraph ? 0 : firstSlot.offsetBefore;
|
|
17658
|
+
rebuildContainer(firstParent, containerStart, span, replacement, inheritedProperties, firstParent === paragraph);
|
|
17659
|
+
}
|
|
17660
|
+
function collectRunSlots(paragraph) {
|
|
17661
|
+
const slots = [];
|
|
17662
|
+
let offset = 0;
|
|
17663
|
+
for (const child of paragraph.children) {
|
|
17664
|
+
if (child.tag === "w:r") {
|
|
17665
|
+
const length = runTextLength(child);
|
|
17666
|
+
slots.push({
|
|
17667
|
+
parent: paragraph,
|
|
17668
|
+
run: child,
|
|
17669
|
+
offsetBefore: offset,
|
|
17670
|
+
length
|
|
17671
|
+
});
|
|
17672
|
+
offset += length;
|
|
17673
|
+
continue;
|
|
17674
|
+
}
|
|
17675
|
+
if (child.tag === "w:ins" || child.tag === "w:del") {
|
|
17676
|
+
for (const inner of child.children) {
|
|
17677
|
+
if (inner.tag !== "w:r")
|
|
17678
|
+
continue;
|
|
17679
|
+
const length = runTextLength(inner);
|
|
17680
|
+
slots.push({
|
|
17681
|
+
parent: child,
|
|
17682
|
+
run: inner,
|
|
17683
|
+
offsetBefore: offset,
|
|
17684
|
+
length
|
|
17685
|
+
});
|
|
17686
|
+
offset += length;
|
|
17687
|
+
}
|
|
17688
|
+
}
|
|
17689
|
+
}
|
|
17690
|
+
return slots;
|
|
17691
|
+
}
|
|
17692
|
+
function rebuildContainer(container, baseOffset, span, replacement, runProperties, isParagraph) {
|
|
17693
|
+
const newChildren = [];
|
|
17694
|
+
let offset = baseOffset;
|
|
17695
|
+
let placedReplacement = false;
|
|
17696
|
+
for (const child of container.children) {
|
|
17697
|
+
if (child.tag === "w:r") {
|
|
17698
|
+
const length = runTextLength(child);
|
|
17699
|
+
const runStart = offset;
|
|
17700
|
+
const runEnd = offset + length;
|
|
17701
|
+
offset = runEnd;
|
|
17702
|
+
if (runEnd <= span.start) {
|
|
17703
|
+
newChildren.push(child);
|
|
17704
|
+
continue;
|
|
17705
|
+
}
|
|
17706
|
+
if (runStart >= span.end) {
|
|
17707
|
+
if (!placedReplacement) {
|
|
17708
|
+
newChildren.push(replacementRun(runProperties, replacement));
|
|
17709
|
+
placedReplacement = true;
|
|
17710
|
+
}
|
|
17711
|
+
newChildren.push(child);
|
|
17712
|
+
continue;
|
|
17713
|
+
}
|
|
17714
|
+
const sliceStartInRun = Math.max(0, span.start - runStart);
|
|
17715
|
+
const sliceEndInRun = Math.min(length, span.end - runStart);
|
|
17716
|
+
if (sliceStartInRun > 0) {
|
|
17717
|
+
newChildren.push(sliceRun(child, 0, sliceStartInRun));
|
|
17718
|
+
}
|
|
17719
|
+
if (!placedReplacement) {
|
|
17720
|
+
newChildren.push(replacementRun(runProperties, replacement));
|
|
17721
|
+
placedReplacement = true;
|
|
17722
|
+
}
|
|
17723
|
+
if (sliceEndInRun < length) {
|
|
17724
|
+
newChildren.push(sliceRun(child, sliceEndInRun, length));
|
|
17725
|
+
}
|
|
17726
|
+
continue;
|
|
17727
|
+
}
|
|
17728
|
+
if (isParagraph && (child.tag === "w:ins" || child.tag === "w:del")) {
|
|
17729
|
+
let innerLength = 0;
|
|
17730
|
+
for (const inner of child.children) {
|
|
17731
|
+
if (inner.tag === "w:r")
|
|
17732
|
+
innerLength += runTextLength(inner);
|
|
17733
|
+
}
|
|
17734
|
+
offset += innerLength;
|
|
17735
|
+
newChildren.push(child);
|
|
17736
|
+
continue;
|
|
17737
|
+
}
|
|
17738
|
+
newChildren.push(child);
|
|
17739
|
+
}
|
|
17740
|
+
if (!placedReplacement) {
|
|
17741
|
+
newChildren.push(replacementRun(runProperties, replacement));
|
|
17742
|
+
}
|
|
17743
|
+
container.children = newChildren;
|
|
17744
|
+
}
|
|
17745
|
+
function replacementRun(runProperties, text) {
|
|
17746
|
+
if (text.length === 0) {
|
|
17747
|
+
return /* @__PURE__ */ jsxDEV(w.r, {
|
|
17748
|
+
children: [
|
|
17749
|
+
runProperties,
|
|
17750
|
+
/* @__PURE__ */ jsxDEV(w.t, {
|
|
17751
|
+
"xml:space": "preserve",
|
|
17752
|
+
children: ""
|
|
17753
|
+
}, undefined, false, undefined, this)
|
|
17754
|
+
]
|
|
17755
|
+
}, undefined, true, undefined, this);
|
|
17756
|
+
}
|
|
17757
|
+
return /* @__PURE__ */ jsxDEV(w.r, {
|
|
17758
|
+
children: [
|
|
17759
|
+
runProperties,
|
|
17760
|
+
/* @__PURE__ */ jsxDEV(w.t, {
|
|
17761
|
+
"xml:space": "preserve",
|
|
17762
|
+
children: text
|
|
17763
|
+
}, undefined, false, undefined, this)
|
|
17764
|
+
]
|
|
17765
|
+
}, undefined, true, undefined, this);
|
|
17766
|
+
}
|
|
17767
|
+
var TrackedChangeBoundaryError;
|
|
17768
|
+
var init_replace_span = __esm(() => {
|
|
17769
|
+
init_jsx();
|
|
17770
|
+
init_parser();
|
|
17771
|
+
init_jsx_dev_runtime();
|
|
17772
|
+
TrackedChangeBoundaryError = class TrackedChangeBoundaryError extends Error {
|
|
17773
|
+
constructor(message) {
|
|
17774
|
+
super(message);
|
|
17775
|
+
this.name = "TrackedChangeBoundaryError";
|
|
17776
|
+
}
|
|
17777
|
+
};
|
|
17778
|
+
});
|
|
17149
17779
|
|
|
17150
|
-
// src/cli/
|
|
17151
|
-
var
|
|
17152
|
-
__export(
|
|
17153
|
-
run: () =>
|
|
17780
|
+
// src/cli/replace/index.ts
|
|
17781
|
+
var exports_replace2 = {};
|
|
17782
|
+
__export(exports_replace2, {
|
|
17783
|
+
run: () => run21
|
|
17154
17784
|
});
|
|
17155
|
-
import { parseArgs as
|
|
17156
|
-
async function
|
|
17785
|
+
import { parseArgs as parseArgs18 } from "util";
|
|
17786
|
+
async function run21(args) {
|
|
17157
17787
|
let parsed;
|
|
17158
17788
|
try {
|
|
17159
|
-
parsed =
|
|
17789
|
+
parsed = parseArgs18({
|
|
17160
17790
|
args,
|
|
17161
17791
|
allowPositionals: true,
|
|
17162
17792
|
options: {
|
|
17163
|
-
|
|
17164
|
-
|
|
17793
|
+
regex: { type: "boolean" },
|
|
17794
|
+
"ignore-case": { type: "boolean" },
|
|
17795
|
+
all: { type: "boolean" },
|
|
17796
|
+
limit: { type: "string" },
|
|
17797
|
+
"dry-run": { type: "boolean" },
|
|
17165
17798
|
help: { type: "boolean", short: "h" }
|
|
17166
17799
|
}
|
|
17167
17800
|
});
|
|
17168
|
-
} catch (parseError) {
|
|
17169
|
-
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
17170
|
-
return fail("USAGE", message,
|
|
17171
|
-
}
|
|
17172
|
-
if (parsed.values.help) {
|
|
17173
|
-
await writeStdout(
|
|
17801
|
+
} catch (parseError) {
|
|
17802
|
+
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
17803
|
+
return fail("USAGE", message, HELP21);
|
|
17804
|
+
}
|
|
17805
|
+
if (parsed.values.help) {
|
|
17806
|
+
await writeStdout(HELP21);
|
|
17807
|
+
return EXIT.OK;
|
|
17808
|
+
}
|
|
17809
|
+
const path = parsed.positionals[0];
|
|
17810
|
+
const pattern = parsed.positionals[1];
|
|
17811
|
+
const replacement = parsed.positionals[2];
|
|
17812
|
+
if (!path)
|
|
17813
|
+
return fail("USAGE", "Missing FILE argument", HELP21);
|
|
17814
|
+
if (pattern == null)
|
|
17815
|
+
return fail("USAGE", "Missing PATTERN argument", HELP21);
|
|
17816
|
+
if (replacement == null) {
|
|
17817
|
+
return fail("USAGE", "Missing REPLACEMENT argument", HELP21);
|
|
17818
|
+
}
|
|
17819
|
+
const ignoreCase = Boolean(parsed.values["ignore-case"]);
|
|
17820
|
+
const useRegex = Boolean(parsed.values.regex);
|
|
17821
|
+
const wantAll = Boolean(parsed.values.all);
|
|
17822
|
+
const limitRaw = parsed.values.limit;
|
|
17823
|
+
const limit = limitRaw === undefined ? undefined : Number(limitRaw);
|
|
17824
|
+
if (limit !== undefined && (!Number.isInteger(limit) || limit <= 0)) {
|
|
17825
|
+
return fail("USAGE", `--limit must be a positive integer, got "${limitRaw}"`);
|
|
17826
|
+
}
|
|
17827
|
+
const view = await openOrFail(path);
|
|
17828
|
+
if (typeof view === "number")
|
|
17829
|
+
return view;
|
|
17830
|
+
let allMatches;
|
|
17831
|
+
try {
|
|
17832
|
+
allMatches = findTextSpans(view.doc, pattern, {
|
|
17833
|
+
regex: useRegex,
|
|
17834
|
+
ignoreCase
|
|
17835
|
+
});
|
|
17836
|
+
} catch (matcherError) {
|
|
17837
|
+
const message = matcherError instanceof Error ? matcherError.message : String(matcherError);
|
|
17838
|
+
return fail("USAGE", `Invalid pattern: ${message}`);
|
|
17839
|
+
}
|
|
17840
|
+
let selected;
|
|
17841
|
+
if (limit !== undefined) {
|
|
17842
|
+
selected = allMatches.slice(0, limit);
|
|
17843
|
+
} else if (wantAll) {
|
|
17844
|
+
selected = allMatches;
|
|
17845
|
+
} else {
|
|
17846
|
+
selected = allMatches.slice(0, 1);
|
|
17847
|
+
}
|
|
17848
|
+
const matchesPayload = selected.map((match) => ({
|
|
17849
|
+
locator: `${match.blockId}:${match.start}-${match.end}`,
|
|
17850
|
+
blockId: match.blockId,
|
|
17851
|
+
start: match.start,
|
|
17852
|
+
end: match.end,
|
|
17853
|
+
text: match.text
|
|
17854
|
+
}));
|
|
17855
|
+
if (parsed.values["dry-run"]) {
|
|
17856
|
+
await respond({
|
|
17857
|
+
ok: true,
|
|
17858
|
+
operation: "replace",
|
|
17859
|
+
dryRun: true,
|
|
17860
|
+
path,
|
|
17861
|
+
pattern,
|
|
17862
|
+
replacement,
|
|
17863
|
+
regex: useRegex,
|
|
17864
|
+
ignoreCase,
|
|
17865
|
+
totalMatches: allMatches.length,
|
|
17866
|
+
replaced: selected.length,
|
|
17867
|
+
matches: matchesPayload
|
|
17868
|
+
});
|
|
17174
17869
|
return EXIT.OK;
|
|
17175
17870
|
}
|
|
17176
|
-
if (
|
|
17177
|
-
await
|
|
17871
|
+
if (selected.length === 0) {
|
|
17872
|
+
await respond({
|
|
17873
|
+
ok: true,
|
|
17874
|
+
operation: "replace",
|
|
17875
|
+
path,
|
|
17876
|
+
pattern,
|
|
17877
|
+
replacement,
|
|
17878
|
+
regex: useRegex,
|
|
17879
|
+
ignoreCase,
|
|
17880
|
+
totalMatches: 0,
|
|
17881
|
+
replaced: 0,
|
|
17882
|
+
matches: []
|
|
17883
|
+
});
|
|
17178
17884
|
return EXIT.OK;
|
|
17179
17885
|
}
|
|
17180
|
-
|
|
17886
|
+
const reversed = [...selected].sort((leftMatch, rightMatch) => {
|
|
17887
|
+
if (leftMatch.blockId !== rightMatch.blockId) {
|
|
17888
|
+
return rightMatch.blockId.localeCompare(leftMatch.blockId);
|
|
17889
|
+
}
|
|
17890
|
+
return rightMatch.start - leftMatch.start;
|
|
17891
|
+
});
|
|
17892
|
+
const regexFlags = ignoreCase ? "i" : "";
|
|
17893
|
+
try {
|
|
17894
|
+
for (const match of reversed) {
|
|
17895
|
+
const concreteReplacement = useRegex ? match.text.replace(new RegExp(pattern, regexFlags), replacement) : replacement;
|
|
17896
|
+
const blockRef = resolveBlock(view, match.blockId);
|
|
17897
|
+
replaceSpanInParagraph(blockRef.node, { start: match.start, end: match.end }, concreteReplacement);
|
|
17898
|
+
}
|
|
17899
|
+
} catch (error) {
|
|
17900
|
+
if (error instanceof TrackedChangeBoundaryError) {
|
|
17901
|
+
return fail("TRACKED_CHANGE_CONFLICT", error.message, "Use `docx track-changes off` (or accept/reject the change in Word) before replacing.");
|
|
17902
|
+
}
|
|
17903
|
+
throw error;
|
|
17904
|
+
}
|
|
17905
|
+
await saveDocView(view);
|
|
17906
|
+
await respond({
|
|
17907
|
+
ok: true,
|
|
17908
|
+
operation: "replace",
|
|
17909
|
+
path,
|
|
17910
|
+
pattern,
|
|
17911
|
+
replacement,
|
|
17912
|
+
regex: useRegex,
|
|
17913
|
+
ignoreCase,
|
|
17914
|
+
totalMatches: allMatches.length,
|
|
17915
|
+
replaced: selected.length,
|
|
17916
|
+
matches: matchesPayload
|
|
17917
|
+
});
|
|
17181
17918
|
return EXIT.OK;
|
|
17182
17919
|
}
|
|
17183
|
-
var
|
|
17920
|
+
var HELP21 = `docx replace \u2014 substitute text spans (sed for docx)
|
|
17184
17921
|
|
|
17185
17922
|
Usage:
|
|
17186
|
-
docx
|
|
17923
|
+
docx replace FILE PATTERN REPLACEMENT [options]
|
|
17187
17924
|
|
|
17188
17925
|
Options:
|
|
17189
|
-
--
|
|
17190
|
-
--
|
|
17191
|
-
|
|
17926
|
+
--regex treat PATTERN as a JavaScript regular expression
|
|
17927
|
+
--ignore-case case-insensitive match
|
|
17928
|
+
--all replace every match (default: just the first)
|
|
17929
|
+
--limit N replace at most N matches (in document order)
|
|
17930
|
+
--dry-run report what would change without writing the file
|
|
17931
|
+
-h, --help show this help
|
|
17932
|
+
|
|
17933
|
+
Within-paragraph matches only. Run formatting (rPr) on the surrounding text
|
|
17934
|
+
is preserved; the replacement run inherits the rPr of the first run that
|
|
17935
|
+
overlaps the matched span. When a single invocation produces multiple
|
|
17936
|
+
replacements in the same paragraph, they're applied in reverse offset order
|
|
17937
|
+
so earlier offsets don't shift before being applied.
|
|
17938
|
+
|
|
17939
|
+
With --regex, REPLACEMENT supports JS String.replace substitution syntax:
|
|
17940
|
+
$1, $2, ... numbered capture groups
|
|
17941
|
+
$& the matched substring
|
|
17942
|
+
$\` text before the match
|
|
17943
|
+
$' text after the match
|
|
17944
|
+
$$ a literal $
|
|
17192
17945
|
|
|
17193
17946
|
Examples:
|
|
17194
|
-
docx
|
|
17195
|
-
docx
|
|
17196
|
-
|
|
17197
|
-
|
|
17198
|
-
|
|
17947
|
+
docx replace doc.docx "fox" "cat"
|
|
17948
|
+
docx replace doc.docx "fox" "cat" --all
|
|
17949
|
+
docx replace doc.docx "TODO|FIXME" "DONE" --regex --all
|
|
17950
|
+
docx replace doc.docx "(\\w+) (\\w+)" "$2 $1" --regex --all
|
|
17951
|
+
docx replace doc.docx "wordy phrase" "tighter phrase" --all --dry-run
|
|
17952
|
+
`;
|
|
17953
|
+
var init_replace2 = __esm(() => {
|
|
17954
|
+
init_core();
|
|
17199
17955
|
init_respond();
|
|
17200
|
-
|
|
17201
|
-
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
17202
|
-
$id: "https://github.com/kklimuk/docx-cli/schema",
|
|
17203
|
-
title: "docx-cli AST",
|
|
17204
|
-
type: "object",
|
|
17205
|
-
required: ["schemaVersion", "path", "properties", "blocks", "comments"],
|
|
17206
|
-
properties: {
|
|
17207
|
-
schemaVersion: { const: 1 },
|
|
17208
|
-
path: { type: "string" },
|
|
17209
|
-
properties: {
|
|
17210
|
-
type: "object",
|
|
17211
|
-
properties: {
|
|
17212
|
-
title: { type: "string" },
|
|
17213
|
-
author: { type: "string" },
|
|
17214
|
-
created: { type: "string" },
|
|
17215
|
-
modified: { type: "string" }
|
|
17216
|
-
}
|
|
17217
|
-
},
|
|
17218
|
-
blocks: { type: "array", items: { $ref: "#/$defs/Block" } },
|
|
17219
|
-
comments: { type: "array", items: { $ref: "#/$defs/Comment" } }
|
|
17220
|
-
},
|
|
17221
|
-
$defs: {
|
|
17222
|
-
Block: {
|
|
17223
|
-
oneOf: [
|
|
17224
|
-
{ $ref: "#/$defs/Paragraph" },
|
|
17225
|
-
{ $ref: "#/$defs/Table" },
|
|
17226
|
-
{ $ref: "#/$defs/SectionBreak" }
|
|
17227
|
-
]
|
|
17228
|
-
},
|
|
17229
|
-
Paragraph: {
|
|
17230
|
-
type: "object",
|
|
17231
|
-
required: ["id", "type", "runs"],
|
|
17232
|
-
properties: {
|
|
17233
|
-
id: { type: "string" },
|
|
17234
|
-
type: { const: "paragraph" },
|
|
17235
|
-
style: { type: "string" },
|
|
17236
|
-
alignment: { enum: ["left", "center", "right", "justify"] },
|
|
17237
|
-
list: {
|
|
17238
|
-
type: "object",
|
|
17239
|
-
required: ["level", "numId"],
|
|
17240
|
-
properties: {
|
|
17241
|
-
level: { type: "number" },
|
|
17242
|
-
numId: { type: "string" }
|
|
17243
|
-
}
|
|
17244
|
-
},
|
|
17245
|
-
runs: { type: "array", items: { $ref: "#/$defs/Run" } }
|
|
17246
|
-
}
|
|
17247
|
-
},
|
|
17248
|
-
Run: {
|
|
17249
|
-
oneOf: [
|
|
17250
|
-
{ $ref: "#/$defs/TextRun" },
|
|
17251
|
-
{ $ref: "#/$defs/ImageRun" },
|
|
17252
|
-
{ $ref: "#/$defs/BreakRun" },
|
|
17253
|
-
{ $ref: "#/$defs/TabRun" }
|
|
17254
|
-
]
|
|
17255
|
-
},
|
|
17256
|
-
TextRun: {
|
|
17257
|
-
type: "object",
|
|
17258
|
-
required: ["type", "text"],
|
|
17259
|
-
properties: {
|
|
17260
|
-
type: { const: "text" },
|
|
17261
|
-
text: { type: "string" },
|
|
17262
|
-
color: { type: "string" },
|
|
17263
|
-
highlight: { type: "string" },
|
|
17264
|
-
bold: { type: "boolean" },
|
|
17265
|
-
italic: { type: "boolean" },
|
|
17266
|
-
underline: { type: "string" },
|
|
17267
|
-
strike: { type: "boolean" },
|
|
17268
|
-
font: { type: "string" },
|
|
17269
|
-
sizeHalfPoints: { type: "number" },
|
|
17270
|
-
comments: { type: "array", items: { type: "string" } },
|
|
17271
|
-
trackedChange: {
|
|
17272
|
-
type: "object",
|
|
17273
|
-
required: ["kind", "author", "date", "revisionId"],
|
|
17274
|
-
properties: {
|
|
17275
|
-
kind: { enum: ["ins", "del"] },
|
|
17276
|
-
author: { type: "string" },
|
|
17277
|
-
date: { type: "string" },
|
|
17278
|
-
revisionId: { type: "string" }
|
|
17279
|
-
}
|
|
17280
|
-
}
|
|
17281
|
-
}
|
|
17282
|
-
},
|
|
17283
|
-
ImageRun: {
|
|
17284
|
-
type: "object",
|
|
17285
|
-
required: ["type", "id", "contentType", "hash"],
|
|
17286
|
-
properties: {
|
|
17287
|
-
type: { const: "image" },
|
|
17288
|
-
id: { type: "string" },
|
|
17289
|
-
contentType: { type: "string" },
|
|
17290
|
-
hash: { type: "string" },
|
|
17291
|
-
widthEmu: { type: "number" },
|
|
17292
|
-
heightEmu: { type: "number" },
|
|
17293
|
-
alt: { type: "string" }
|
|
17294
|
-
}
|
|
17295
|
-
},
|
|
17296
|
-
BreakRun: {
|
|
17297
|
-
type: "object",
|
|
17298
|
-
required: ["type", "kind"],
|
|
17299
|
-
properties: {
|
|
17300
|
-
type: { const: "break" },
|
|
17301
|
-
kind: { enum: ["page", "line", "column"] }
|
|
17302
|
-
}
|
|
17303
|
-
},
|
|
17304
|
-
TabRun: {
|
|
17305
|
-
type: "object",
|
|
17306
|
-
required: ["type"],
|
|
17307
|
-
properties: { type: { const: "tab" } }
|
|
17308
|
-
},
|
|
17309
|
-
Table: {
|
|
17310
|
-
type: "object",
|
|
17311
|
-
required: ["id", "type", "rows"],
|
|
17312
|
-
properties: {
|
|
17313
|
-
id: { type: "string" },
|
|
17314
|
-
type: { const: "table" },
|
|
17315
|
-
rows: {
|
|
17316
|
-
type: "array",
|
|
17317
|
-
items: {
|
|
17318
|
-
type: "object",
|
|
17319
|
-
properties: {
|
|
17320
|
-
cells: {
|
|
17321
|
-
type: "array",
|
|
17322
|
-
items: {
|
|
17323
|
-
type: "object",
|
|
17324
|
-
properties: {
|
|
17325
|
-
blocks: {
|
|
17326
|
-
type: "array",
|
|
17327
|
-
items: { $ref: "#/$defs/Block" }
|
|
17328
|
-
}
|
|
17329
|
-
}
|
|
17330
|
-
}
|
|
17331
|
-
}
|
|
17332
|
-
}
|
|
17333
|
-
}
|
|
17334
|
-
}
|
|
17335
|
-
}
|
|
17336
|
-
},
|
|
17337
|
-
SectionBreak: {
|
|
17338
|
-
type: "object",
|
|
17339
|
-
required: ["id", "type"],
|
|
17340
|
-
properties: {
|
|
17341
|
-
id: { type: "string" },
|
|
17342
|
-
type: { const: "sectionBreak" }
|
|
17343
|
-
}
|
|
17344
|
-
},
|
|
17345
|
-
Comment: {
|
|
17346
|
-
type: "object",
|
|
17347
|
-
required: ["id", "author", "date", "text", "anchor"],
|
|
17348
|
-
properties: {
|
|
17349
|
-
id: { type: "string" },
|
|
17350
|
-
author: { type: "string" },
|
|
17351
|
-
initials: { type: "string" },
|
|
17352
|
-
date: { type: "string" },
|
|
17353
|
-
text: { type: "string" },
|
|
17354
|
-
parentId: { type: "string" },
|
|
17355
|
-
resolved: { type: "boolean" },
|
|
17356
|
-
anchor: {
|
|
17357
|
-
type: "object",
|
|
17358
|
-
required: ["startBlockId", "startOffset", "endBlockId", "endOffset"],
|
|
17359
|
-
properties: {
|
|
17360
|
-
startBlockId: { type: "string" },
|
|
17361
|
-
startOffset: { type: "number" },
|
|
17362
|
-
endBlockId: { type: "string" },
|
|
17363
|
-
endOffset: { type: "number" }
|
|
17364
|
-
}
|
|
17365
|
-
}
|
|
17366
|
-
}
|
|
17367
|
-
}
|
|
17368
|
-
}
|
|
17369
|
-
};
|
|
17956
|
+
init_replace_span();
|
|
17370
17957
|
});
|
|
17371
17958
|
|
|
17372
17959
|
// src/cli/track-changes/index.tsx
|
|
17373
17960
|
var exports_track_changes = {};
|
|
17374
17961
|
__export(exports_track_changes, {
|
|
17375
|
-
run: () =>
|
|
17962
|
+
run: () => run22
|
|
17376
17963
|
});
|
|
17377
|
-
import { parseArgs as
|
|
17378
|
-
async function
|
|
17964
|
+
import { parseArgs as parseArgs19 } from "util";
|
|
17965
|
+
async function run22(args) {
|
|
17379
17966
|
let parsed;
|
|
17380
17967
|
try {
|
|
17381
|
-
parsed =
|
|
17968
|
+
parsed = parseArgs19({
|
|
17382
17969
|
args,
|
|
17383
17970
|
allowPositionals: true,
|
|
17384
17971
|
options: {
|
|
@@ -17388,41 +17975,31 @@ async function run19(args) {
|
|
|
17388
17975
|
});
|
|
17389
17976
|
} catch (parseError) {
|
|
17390
17977
|
const message = parseError instanceof Error ? parseError.message : String(parseError);
|
|
17391
|
-
return fail("USAGE", message,
|
|
17978
|
+
return fail("USAGE", message, HELP22);
|
|
17392
17979
|
}
|
|
17393
17980
|
if (parsed.values.help) {
|
|
17394
|
-
await writeStdout(
|
|
17981
|
+
await writeStdout(HELP22);
|
|
17395
17982
|
return EXIT.OK;
|
|
17396
17983
|
}
|
|
17397
17984
|
const path = parsed.positionals[0];
|
|
17398
17985
|
if (!path)
|
|
17399
|
-
return fail("USAGE", "Missing FILE argument",
|
|
17986
|
+
return fail("USAGE", "Missing FILE argument", HELP22);
|
|
17400
17987
|
const mode = parsed.positionals[1];
|
|
17401
17988
|
if (mode !== "on" && mode !== "off") {
|
|
17402
|
-
return fail("USAGE", `Expected "on" or "off", got: ${mode ?? "<nothing>"}`,
|
|
17403
|
-
}
|
|
17404
|
-
|
|
17405
|
-
|
|
17406
|
-
view
|
|
17407
|
-
|
|
17408
|
-
|
|
17409
|
-
|
|
17410
|
-
|
|
17411
|
-
}
|
|
17412
|
-
if (openError.code === "NOT_A_ZIP") {
|
|
17413
|
-
return fail("NOT_A_ZIP", openError.message);
|
|
17414
|
-
}
|
|
17415
|
-
}
|
|
17416
|
-
throw openError;
|
|
17417
|
-
}
|
|
17418
|
-
const settingsXml = view.pkg.hasPart(SETTINGS_PART) ? await view.pkg.readText(SETTINGS_PART) : null;
|
|
17419
|
-
const settingsTree = settingsXml ? XmlNode2.parse(settingsXml) : [];
|
|
17420
|
-
let settingsRoot = XmlNode2.findRoot(settingsTree, "w:settings");
|
|
17989
|
+
return fail("USAGE", `Expected "on" or "off", got: ${mode ?? "<nothing>"}`, HELP22);
|
|
17990
|
+
}
|
|
17991
|
+
const view = await openOrFail(path);
|
|
17992
|
+
if (typeof view === "number")
|
|
17993
|
+
return view;
|
|
17994
|
+
const wasMissing = view.settingsTree === undefined;
|
|
17995
|
+
if (!view.settingsTree)
|
|
17996
|
+
view.settingsTree = [];
|
|
17997
|
+
let settingsRoot = XmlNode2.findRoot(view.settingsTree, "w:settings");
|
|
17421
17998
|
if (!settingsRoot) {
|
|
17422
17999
|
settingsRoot = /* @__PURE__ */ jsxDEV(w.settings, {
|
|
17423
18000
|
"xmlns:w": NS_W2
|
|
17424
18001
|
}, undefined, false, undefined, this);
|
|
17425
|
-
settingsTree.push(settingsRoot);
|
|
18002
|
+
view.settingsTree.push(settingsRoot);
|
|
17426
18003
|
}
|
|
17427
18004
|
const hasTrackChanges = settingsRoot.children.some((child) => child.tag === "w:trackChanges");
|
|
17428
18005
|
if (parsed.values["dry-run"]) {
|
|
@@ -17441,13 +18018,15 @@ async function run19(args) {
|
|
|
17441
18018
|
} else if (mode === "off" && hasTrackChanges) {
|
|
17442
18019
|
settingsRoot.children = settingsRoot.children.filter((child) => child.tag !== "w:trackChanges");
|
|
17443
18020
|
}
|
|
17444
|
-
|
|
17445
|
-
|
|
17446
|
-
|
|
18021
|
+
if (wasMissing) {
|
|
18022
|
+
registerPart(view.relationshipsTree, view.contentTypesTree, {
|
|
18023
|
+
partName: SETTINGS_PART,
|
|
18024
|
+
contentType: SETTINGS_CONTENT_TYPE,
|
|
18025
|
+
relationshipType: SETTINGS_REL_TYPE,
|
|
18026
|
+
target: "settings.xml"
|
|
18027
|
+
});
|
|
17447
18028
|
}
|
|
17448
|
-
|
|
17449
|
-
view.pkg.writeText("[Content_Types].xml", XmlNode2.serializeWithDeclaration(view.contentTypesTree));
|
|
17450
|
-
await view.pkg.save();
|
|
18029
|
+
await saveDocView(view);
|
|
17451
18030
|
await respond({
|
|
17452
18031
|
ok: true,
|
|
17453
18032
|
operation: "track-changes",
|
|
@@ -17457,47 +18036,7 @@ async function run19(args) {
|
|
|
17457
18036
|
});
|
|
17458
18037
|
return EXIT.OK;
|
|
17459
18038
|
}
|
|
17460
|
-
|
|
17461
|
-
const relationships = XmlNode2.findRoot(view.relationshipsTree, "Relationships");
|
|
17462
|
-
if (relationships) {
|
|
17463
|
-
const alreadyLinked = relationships.children.some((child) => child.tag === "Relationship" && child.getAttribute("Type") === SETTINGS_REL_TYPE);
|
|
17464
|
-
if (!alreadyLinked) {
|
|
17465
|
-
relationships.children.push(new XmlNode2("Relationship", {
|
|
17466
|
-
Id: nextRelationshipId2(relationships),
|
|
17467
|
-
Type: SETTINGS_REL_TYPE,
|
|
17468
|
-
Target: "settings.xml"
|
|
17469
|
-
}));
|
|
17470
|
-
}
|
|
17471
|
-
}
|
|
17472
|
-
const types = XmlNode2.findRoot(view.contentTypesTree, "Types");
|
|
17473
|
-
if (types) {
|
|
17474
|
-
const exists = types.children.some((child) => child.tag === "Override" && child.getAttribute("PartName") === `/${SETTINGS_PART}`);
|
|
17475
|
-
if (!exists) {
|
|
17476
|
-
types.children.push(new XmlNode2("Override", {
|
|
17477
|
-
PartName: `/${SETTINGS_PART}`,
|
|
17478
|
-
ContentType: SETTINGS_CONTENT_TYPE
|
|
17479
|
-
}));
|
|
17480
|
-
}
|
|
17481
|
-
}
|
|
17482
|
-
}
|
|
17483
|
-
function nextRelationshipId2(relationships) {
|
|
17484
|
-
let highest = 0;
|
|
17485
|
-
for (const child of relationships.children) {
|
|
17486
|
-
if (child.tag !== "Relationship")
|
|
17487
|
-
continue;
|
|
17488
|
-
const id = child.getAttribute("Id");
|
|
17489
|
-
if (!id)
|
|
17490
|
-
continue;
|
|
17491
|
-
const match = id.match(/^rId(\d+)$/);
|
|
17492
|
-
if (!match)
|
|
17493
|
-
continue;
|
|
17494
|
-
const numeric = Number(match[1]);
|
|
17495
|
-
if (Number.isFinite(numeric) && numeric > highest)
|
|
17496
|
-
highest = numeric;
|
|
17497
|
-
}
|
|
17498
|
-
return `rId${highest + 1}`;
|
|
17499
|
-
}
|
|
17500
|
-
var HELP19 = `docx track-changes \u2014 toggle the document's tracked-changes mode
|
|
18039
|
+
var HELP22 = `docx track-changes \u2014 toggle the document's tracked-changes mode
|
|
17501
18040
|
|
|
17502
18041
|
Usage:
|
|
17503
18042
|
docx track-changes FILE on|off [options]
|
|
@@ -17516,14 +18055,76 @@ Examples:
|
|
|
17516
18055
|
var init_track_changes = __esm(() => {
|
|
17517
18056
|
init_core();
|
|
17518
18057
|
init_jsx();
|
|
18058
|
+
init_package();
|
|
17519
18059
|
init_parser();
|
|
17520
18060
|
init_respond();
|
|
17521
18061
|
init_jsx_dev_runtime();
|
|
17522
18062
|
});
|
|
18063
|
+
// package.json
|
|
18064
|
+
var package_default = {
|
|
18065
|
+
name: "bun-docx",
|
|
18066
|
+
version: "0.2.0",
|
|
18067
|
+
description: "CLI for AI agents (Claude, Codex) to read, edit, and comment on .docx files with full format fidelity.",
|
|
18068
|
+
keywords: [
|
|
18069
|
+
"docx",
|
|
18070
|
+
"openxml",
|
|
18071
|
+
"ooxml",
|
|
18072
|
+
"word",
|
|
18073
|
+
"cli",
|
|
18074
|
+
"ai",
|
|
18075
|
+
"claude",
|
|
18076
|
+
"codex",
|
|
18077
|
+
"agentic"
|
|
18078
|
+
],
|
|
18079
|
+
license: "MIT",
|
|
18080
|
+
author: "Kirill Klimuk",
|
|
18081
|
+
repository: {
|
|
18082
|
+
type: "git",
|
|
18083
|
+
url: "git+https://github.com/kklimuk/docx-cli.git"
|
|
18084
|
+
},
|
|
18085
|
+
homepage: "https://github.com/kklimuk/docx-cli#readme",
|
|
18086
|
+
bugs: "https://github.com/kklimuk/docx-cli/issues",
|
|
18087
|
+
type: "module",
|
|
18088
|
+
packageManager: "bun@1.3.13",
|
|
18089
|
+
bin: {
|
|
18090
|
+
docx: "./dist/index.js"
|
|
18091
|
+
},
|
|
18092
|
+
files: [
|
|
18093
|
+
"dist/index.js",
|
|
18094
|
+
"README.md",
|
|
18095
|
+
"LICENSE"
|
|
18096
|
+
],
|
|
18097
|
+
engines: {
|
|
18098
|
+
bun: ">=1.3.0"
|
|
18099
|
+
},
|
|
18100
|
+
scripts: {
|
|
18101
|
+
dev: "bun src/index.ts",
|
|
18102
|
+
build: "bun build src/index.ts --outfile dist/index.js --target bun",
|
|
18103
|
+
"build:binary": "bun build --compile --outfile=dist/docx src/index.ts",
|
|
18104
|
+
check: "biome check . && knip-bun && bunx tsc --noEmit",
|
|
18105
|
+
test: "bun test",
|
|
18106
|
+
"test:unit": "bun test tests/core tests/cli",
|
|
18107
|
+
"test:integration": "bun test tests/integration",
|
|
18108
|
+
prepack: "bun run build",
|
|
18109
|
+
prepare: "husky"
|
|
18110
|
+
},
|
|
18111
|
+
devDependencies: {
|
|
18112
|
+
"@biomejs/biome": "^2.4.10",
|
|
18113
|
+
"@types/bun": "^1.3.13",
|
|
18114
|
+
husky: "^9.1.7",
|
|
18115
|
+
knip: "^6.3.0",
|
|
18116
|
+
typescript: "^6.0.2"
|
|
18117
|
+
},
|
|
18118
|
+
dependencies: {
|
|
18119
|
+
"fast-xml-builder": "^1.1.6",
|
|
18120
|
+
"fast-xml-parser": "^5.7.2",
|
|
18121
|
+
jszip: "^3.10.1"
|
|
18122
|
+
}
|
|
18123
|
+
};
|
|
17523
18124
|
|
|
17524
18125
|
// src/cli/help.ts
|
|
17525
18126
|
init_respond();
|
|
17526
|
-
var VERSION =
|
|
18127
|
+
var VERSION = package_default.version;
|
|
17527
18128
|
var TOP_HELP = `docx ${VERSION} \u2014 read, edit, and comment on .docx files
|
|
17528
18129
|
|
|
17529
18130
|
Usage:
|
|
@@ -17535,11 +18136,12 @@ Commands:
|
|
|
17535
18136
|
edit FILE Replace text/properties at a locator
|
|
17536
18137
|
insert FILE Insert a block or run
|
|
17537
18138
|
delete FILE Remove a block or run range
|
|
18139
|
+
find FILE QUERY Find text spans, return locators
|
|
18140
|
+
replace FILE PATTERN REPL Substitute text spans (sed for docx)
|
|
17538
18141
|
comments \u2026 Add, reply, resolve, delete, restore, list comments
|
|
17539
18142
|
images \u2026 Extract, replace, list images
|
|
17540
18143
|
track-changes FILE on|off Toggle tracked-changes mode
|
|
17541
|
-
|
|
17542
|
-
locators Dump locator grammar reference
|
|
18144
|
+
info \u2026 Reference material (schema, locators)
|
|
17543
18145
|
|
|
17544
18146
|
Run "docx <command> --help" for command-specific help.
|
|
17545
18147
|
|
|
@@ -17557,18 +18159,19 @@ var COMMANDS = {
|
|
|
17557
18159
|
create: () => Promise.resolve().then(() => (init_create(), exports_create)),
|
|
17558
18160
|
delete: () => Promise.resolve().then(() => (init_delete2(), exports_delete2)),
|
|
17559
18161
|
edit: () => Promise.resolve().then(() => (init_edit(), exports_edit)),
|
|
18162
|
+
find: () => Promise.resolve().then(() => (init_find(), exports_find)),
|
|
17560
18163
|
images: () => Promise.resolve().then(() => (init_images(), exports_images)),
|
|
18164
|
+
info: () => Promise.resolve().then(() => (init_info(), exports_info)),
|
|
17561
18165
|
insert: () => Promise.resolve().then(() => (init_insert(), exports_insert)),
|
|
17562
|
-
locators: () => Promise.resolve().then(() => (init_locators_cmd(), exports_locators_cmd)),
|
|
17563
18166
|
read: () => Promise.resolve().then(() => (init_read2(), exports_read)),
|
|
17564
|
-
|
|
18167
|
+
replace: () => Promise.resolve().then(() => (init_replace2(), exports_replace2)),
|
|
17565
18168
|
"track-changes": () => Promise.resolve().then(() => (init_track_changes(), exports_track_changes))
|
|
17566
18169
|
};
|
|
17567
18170
|
async function main(argv) {
|
|
17568
18171
|
const args = argv.slice(2);
|
|
17569
18172
|
const cmd = args[0];
|
|
17570
18173
|
if (!cmd) {
|
|
17571
|
-
|
|
18174
|
+
Bun.stderr.write(`Usage: docx <command> [options]
|
|
17572
18175
|
Run "docx --help" for available commands.
|
|
17573
18176
|
`);
|
|
17574
18177
|
return 2;
|