@eigenpal/docx-editor-agents 0.0.30 → 0.0.32
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/dist/bridge.js +1 -10
- package/dist/bridge.mjs +1 -8
- package/dist/chunk-2AF2FRMM.js +1 -0
- package/dist/chunk-4QRVKNI4.js +1 -0
- package/dist/chunk-QU2KZVKE.mjs +71 -0
- package/dist/chunk-T3PAPI4X.js +71 -0
- package/dist/chunk-UILTIEBD.mjs +1 -0
- package/dist/chunk-X57U3ESM.mjs +1 -0
- package/dist/executor-O3426NM3.mjs +1 -0
- package/dist/executor-WY7D4C5O.js +1 -0
- package/dist/headless-BWFR2RRX.mjs +1 -0
- package/dist/headless-SJ66VOJQ.js +1 -0
- package/dist/index.js +5 -903
- package/dist/index.mjs +5 -898
- package/dist/processTemplate-3P7VLW5K.js +1 -0
- package/dist/processTemplate-DEFHEMLN.mjs +1 -0
- package/package.json +1 -1
- package/dist/bridge.js.map +0 -1
- package/dist/bridge.mjs.map +0 -1
- package/dist/chunk-5D2V7VK3.js +0 -976
- package/dist/chunk-5D2V7VK3.js.map +0 -1
- package/dist/chunk-5E3CFYZ4.mjs +0 -249
- package/dist/chunk-5E3CFYZ4.mjs.map +0 -1
- package/dist/chunk-GACRQVPW.js +0 -11680
- package/dist/chunk-GACRQVPW.js.map +0 -1
- package/dist/chunk-OFUT6WUQ.mjs +0 -969
- package/dist/chunk-OFUT6WUQ.mjs.map +0 -1
- package/dist/chunk-Q2HHIVUL.js +0 -266
- package/dist/chunk-Q2HHIVUL.js.map +0 -1
- package/dist/chunk-R4MIGZEJ.mjs +0 -11587
- package/dist/chunk-R4MIGZEJ.mjs.map +0 -1
- package/dist/executor-6ZG2VUZS.mjs +0 -3
- package/dist/executor-6ZG2VUZS.mjs.map +0 -1
- package/dist/executor-ZRVQSXRT.js +0 -16
- package/dist/executor-ZRVQSXRT.js.map +0 -1
- package/dist/headless-O2RRWYCB.js +0 -422
- package/dist/headless-O2RRWYCB.js.map +0 -1
- package/dist/headless-UKRSG32U.mjs +0 -5
- package/dist/headless-UKRSG32U.mjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/processTemplate-7M6KZ6GR.mjs +0 -3
- package/dist/processTemplate-7M6KZ6GR.mjs.map +0 -1
- package/dist/processTemplate-H4X2MH5R.js +0 -54
- package/dist/processTemplate-H4X2MH5R.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,903 +1,5 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
// src/utils.ts
|
|
8
|
-
function isTrackedChange(item) {
|
|
9
|
-
return item.type === "insertion" || item.type === "deletion" || item.type === "moveFrom" || item.type === "moveTo";
|
|
10
|
-
}
|
|
11
|
-
function getTrackedChangeText(content) {
|
|
12
|
-
const parts = [];
|
|
13
|
-
for (const item of content) {
|
|
14
|
-
if (item.type === "run") {
|
|
15
|
-
parts.push(chunkGACRQVPW_js.getRunText(item));
|
|
16
|
-
} else if (item.type === "hyperlink") {
|
|
17
|
-
parts.push(chunkGACRQVPW_js.getHyperlinkText(item));
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
return parts.join("");
|
|
21
|
-
}
|
|
22
|
-
function getParagraphAtIndex(body, paragraphIndex) {
|
|
23
|
-
let index = 0;
|
|
24
|
-
for (const block of body.content) {
|
|
25
|
-
if (block.type === "paragraph") {
|
|
26
|
-
if (index === paragraphIndex) return block;
|
|
27
|
-
index++;
|
|
28
|
-
} else if (block.type === "table") {
|
|
29
|
-
for (const row of block.rows) {
|
|
30
|
-
for (const cell of row.cells) {
|
|
31
|
-
for (const cellBlock of cell.content) {
|
|
32
|
-
if (cellBlock.type === "paragraph") {
|
|
33
|
-
if (index === paragraphIndex) return cellBlock;
|
|
34
|
-
index++;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
} else {
|
|
40
|
-
index++;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
throw new Error(`Paragraph index ${paragraphIndex} out of bounds (max: ${index - 1})`);
|
|
44
|
-
}
|
|
45
|
-
function forEachParagraph(body, fn) {
|
|
46
|
-
let index = 0;
|
|
47
|
-
for (const block of body.content) {
|
|
48
|
-
if (block.type === "paragraph") {
|
|
49
|
-
if (fn(block, index) === false) return;
|
|
50
|
-
index++;
|
|
51
|
-
} else if (block.type === "table") {
|
|
52
|
-
for (const row of block.rows) {
|
|
53
|
-
for (const cell of row.cells) {
|
|
54
|
-
for (const cellBlock of cell.content) {
|
|
55
|
-
if (cellBlock.type === "paragraph") {
|
|
56
|
-
if (fn(cellBlock, index) === false) return;
|
|
57
|
-
index++;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
} else {
|
|
63
|
-
index++;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// src/content.ts
|
|
69
|
-
function getContent(body, options = {}) {
|
|
70
|
-
const {
|
|
71
|
-
fromIndex,
|
|
72
|
-
toIndex,
|
|
73
|
-
includeTrackedChanges = true,
|
|
74
|
-
includeCommentAnchors = true
|
|
75
|
-
} = options;
|
|
76
|
-
const blocks = [];
|
|
77
|
-
let index = 0;
|
|
78
|
-
for (const block of body.content) {
|
|
79
|
-
if (block.type === "paragraph") {
|
|
80
|
-
if (isInRange(index, fromIndex, toIndex)) {
|
|
81
|
-
blocks.push(
|
|
82
|
-
buildParagraphBlock(block, index, includeTrackedChanges, includeCommentAnchors)
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
index++;
|
|
86
|
-
} else if (block.type === "table") {
|
|
87
|
-
if (isInRange(index, fromIndex, toIndex)) {
|
|
88
|
-
blocks.push(buildTableBlock(block, index, includeTrackedChanges, includeCommentAnchors));
|
|
89
|
-
}
|
|
90
|
-
for (const row of block.rows) {
|
|
91
|
-
for (const cell of row.cells) {
|
|
92
|
-
for (const cellBlock of cell.content) {
|
|
93
|
-
if (cellBlock.type === "paragraph") {
|
|
94
|
-
index++;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
} else {
|
|
100
|
-
index++;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
return blocks;
|
|
104
|
-
}
|
|
105
|
-
function isInRange(index, from, to) {
|
|
106
|
-
return (from === void 0 || index >= from) && (to === void 0 || index <= to);
|
|
107
|
-
}
|
|
108
|
-
function buildParagraphBlock(para, index, includeTrackedChanges, includeCommentAnchors) {
|
|
109
|
-
const text = buildParagraphText(para, includeTrackedChanges, includeCommentAnchors);
|
|
110
|
-
const styleId = para.formatting?.styleId;
|
|
111
|
-
if (chunkGACRQVPW_js.isHeadingStyle(styleId)) {
|
|
112
|
-
return {
|
|
113
|
-
type: "heading",
|
|
114
|
-
index,
|
|
115
|
-
level: chunkGACRQVPW_js.parseHeadingLevel(styleId) ?? 1,
|
|
116
|
-
text
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
if (para.listRendering) {
|
|
120
|
-
return {
|
|
121
|
-
type: "list-item",
|
|
122
|
-
index,
|
|
123
|
-
text,
|
|
124
|
-
listLevel: para.listRendering.level ?? 0,
|
|
125
|
-
listType: para.listRendering.isBullet ? "bullet" : "number"
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
return { type: "paragraph", index, text };
|
|
129
|
-
}
|
|
130
|
-
function buildTableBlock(table, index, includeTrackedChanges, includeCommentAnchors) {
|
|
131
|
-
const rows = [];
|
|
132
|
-
for (const row of table.rows) {
|
|
133
|
-
const cells = [];
|
|
134
|
-
for (const cell of row.cells) {
|
|
135
|
-
const cellTexts = [];
|
|
136
|
-
for (const block of cell.content) {
|
|
137
|
-
if (block.type === "paragraph") {
|
|
138
|
-
cellTexts.push(buildParagraphText(block, includeTrackedChanges, includeCommentAnchors));
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
cells.push(cellTexts.join("\n"));
|
|
142
|
-
}
|
|
143
|
-
rows.push(cells);
|
|
144
|
-
}
|
|
145
|
-
return { type: "table", index, rows };
|
|
146
|
-
}
|
|
147
|
-
function formatContentForLLM(blocks) {
|
|
148
|
-
const lines = [];
|
|
149
|
-
for (const block of blocks) {
|
|
150
|
-
switch (block.type) {
|
|
151
|
-
case "heading":
|
|
152
|
-
lines.push(`[${block.index}] (h${block.level}) ${block.text}`);
|
|
153
|
-
break;
|
|
154
|
-
case "paragraph":
|
|
155
|
-
lines.push(`[${block.index}] ${block.text}`);
|
|
156
|
-
break;
|
|
157
|
-
case "list-item": {
|
|
158
|
-
const indent = " ".repeat(block.listLevel);
|
|
159
|
-
const bullet = block.listType === "bullet" ? "\u2022" : "-";
|
|
160
|
-
lines.push(`[${block.index}] ${indent}${bullet} ${block.text}`);
|
|
161
|
-
break;
|
|
162
|
-
}
|
|
163
|
-
case "table": {
|
|
164
|
-
let idx = block.index;
|
|
165
|
-
for (let r = 0; r < block.rows.length; r++) {
|
|
166
|
-
for (let c = 0; c < block.rows[r].length; c++) {
|
|
167
|
-
const cellText = block.rows[r][c];
|
|
168
|
-
const paras = cellText.split("\n");
|
|
169
|
-
for (const para of paras) {
|
|
170
|
-
lines.push(`[${idx}] (table, row ${r + 1}, col ${c + 1}) ${para}`);
|
|
171
|
-
idx++;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
break;
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
return lines.join("\n");
|
|
180
|
-
}
|
|
181
|
-
function buildParagraphText(para, includeTrackedChanges, includeCommentAnchors) {
|
|
182
|
-
const parts = [];
|
|
183
|
-
const activeCommentIds = /* @__PURE__ */ new Set();
|
|
184
|
-
for (const item of para.content) {
|
|
185
|
-
if (item.type === "commentRangeStart" && includeCommentAnchors) {
|
|
186
|
-
activeCommentIds.add(item.id);
|
|
187
|
-
parts.push(`[comment:${item.id}]`);
|
|
188
|
-
continue;
|
|
189
|
-
}
|
|
190
|
-
if (item.type === "commentRangeEnd" && includeCommentAnchors) {
|
|
191
|
-
if (activeCommentIds.has(item.id)) {
|
|
192
|
-
activeCommentIds.delete(item.id);
|
|
193
|
-
parts.push("[/comment]");
|
|
194
|
-
}
|
|
195
|
-
continue;
|
|
196
|
-
}
|
|
197
|
-
if (item.type === "run") {
|
|
198
|
-
parts.push(chunkGACRQVPW_js.getRunText(item));
|
|
199
|
-
} else if (item.type === "hyperlink") {
|
|
200
|
-
parts.push(chunkGACRQVPW_js.getHyperlinkText(item));
|
|
201
|
-
} else if (isTrackedChange(item)) {
|
|
202
|
-
const text = getTrackedChangeText(item.content);
|
|
203
|
-
if (item.type === "insertion" || item.type === "moveTo") {
|
|
204
|
-
if (includeTrackedChanges) {
|
|
205
|
-
parts.push(`[+${text}+]{by:${item.info.author}}`);
|
|
206
|
-
} else {
|
|
207
|
-
parts.push(text);
|
|
208
|
-
}
|
|
209
|
-
} else {
|
|
210
|
-
if (includeTrackedChanges) {
|
|
211
|
-
parts.push(`[-${text}-]{by:${item.info.author}}`);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
return parts.join("");
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// src/errors.ts
|
|
220
|
-
var TextNotFoundError = class extends Error {
|
|
221
|
-
constructor(search, paragraphIndex) {
|
|
222
|
-
const location = paragraphIndex !== void 0 ? ` in paragraph ${paragraphIndex}` : " in document";
|
|
223
|
-
super(`Text not found${location}: "${search}"`);
|
|
224
|
-
this.name = "TextNotFoundError";
|
|
225
|
-
}
|
|
226
|
-
};
|
|
227
|
-
var ChangeNotFoundError = class extends Error {
|
|
228
|
-
constructor(id) {
|
|
229
|
-
super(`Tracked change not found: id=${id}`);
|
|
230
|
-
this.name = "ChangeNotFoundError";
|
|
231
|
-
}
|
|
232
|
-
};
|
|
233
|
-
var CommentNotFoundError = class extends Error {
|
|
234
|
-
constructor(id) {
|
|
235
|
-
super(`Comment not found: id=${id}`);
|
|
236
|
-
this.name = "CommentNotFoundError";
|
|
237
|
-
}
|
|
238
|
-
};
|
|
239
|
-
|
|
240
|
-
// src/textSearch.ts
|
|
241
|
-
function flattenRuns(paragraph) {
|
|
242
|
-
const result = [];
|
|
243
|
-
let pos = 0;
|
|
244
|
-
for (let ci = 0; ci < paragraph.content.length; ci++) {
|
|
245
|
-
const item = paragraph.content[ci];
|
|
246
|
-
if (item.type === "run") {
|
|
247
|
-
const text = chunkGACRQVPW_js.getRunText(item);
|
|
248
|
-
result.push({ contentIndex: ci, run: item, text, startPos: pos });
|
|
249
|
-
pos += text.length;
|
|
250
|
-
} else if (item.type === "hyperlink") {
|
|
251
|
-
for (let hi = 0; hi < item.children.length; hi++) {
|
|
252
|
-
const child = item.children[hi];
|
|
253
|
-
if (child.type === "run") {
|
|
254
|
-
const text = chunkGACRQVPW_js.getRunText(child);
|
|
255
|
-
result.push({ contentIndex: ci, run: child, text, startPos: pos });
|
|
256
|
-
pos += text.length;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
} else if (isTrackedChange(item)) {
|
|
260
|
-
for (let ri = 0; ri < item.content.length; ri++) {
|
|
261
|
-
const child = item.content[ri];
|
|
262
|
-
if (child.type === "run") {
|
|
263
|
-
const text = chunkGACRQVPW_js.getRunText(child);
|
|
264
|
-
result.push({ contentIndex: ci, run: child, text, startPos: pos });
|
|
265
|
-
pos += text.length;
|
|
266
|
-
} else if (child.type === "hyperlink") {
|
|
267
|
-
for (const hc of child.children) {
|
|
268
|
-
if (hc.type === "run") {
|
|
269
|
-
const text = chunkGACRQVPW_js.getRunText(hc);
|
|
270
|
-
result.push({ contentIndex: ci, run: hc, text, startPos: pos });
|
|
271
|
-
pos += text.length;
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
return result;
|
|
279
|
-
}
|
|
280
|
-
function getParagraphPlainText(paragraph) {
|
|
281
|
-
return flattenRuns(paragraph).map((r) => r.text).join("");
|
|
282
|
-
}
|
|
283
|
-
function findTextInParagraph(paragraph, search, paragraphIndex) {
|
|
284
|
-
const runs = flattenRuns(paragraph);
|
|
285
|
-
const fullText = runs.map((r) => r.text).join("");
|
|
286
|
-
const match = findMatch(fullText, search);
|
|
287
|
-
if (!match) throw new TextNotFoundError(search, paragraphIndex);
|
|
288
|
-
let startRunIdx = -1;
|
|
289
|
-
let startOffset = 0;
|
|
290
|
-
for (let i = 0; i < runs.length; i++) {
|
|
291
|
-
if (match.start < runs[i].startPos + runs[i].text.length) {
|
|
292
|
-
startRunIdx = i;
|
|
293
|
-
startOffset = match.start - runs[i].startPos;
|
|
294
|
-
break;
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
let endRunIdx = -1;
|
|
298
|
-
let endOffset = 0;
|
|
299
|
-
for (let i = runs.length - 1; i >= 0; i--) {
|
|
300
|
-
if (match.end > runs[i].startPos) {
|
|
301
|
-
endRunIdx = i;
|
|
302
|
-
endOffset = match.end - runs[i].startPos;
|
|
303
|
-
break;
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
if (startRunIdx === -1 || endRunIdx === -1) {
|
|
307
|
-
throw new TextNotFoundError(search, paragraphIndex);
|
|
308
|
-
}
|
|
309
|
-
return {
|
|
310
|
-
startRunIndex: runs[startRunIdx].contentIndex,
|
|
311
|
-
startOffset,
|
|
312
|
-
endRunIndex: runs[endRunIdx].contentIndex,
|
|
313
|
-
endOffset
|
|
314
|
-
};
|
|
315
|
-
}
|
|
316
|
-
function isolateMatchedText(paragraph, search, paragraphIndex) {
|
|
317
|
-
const result = findTextInParagraph(paragraph, search, paragraphIndex);
|
|
318
|
-
let { startRunIndex, endRunIndex } = result;
|
|
319
|
-
const { startOffset, endOffset } = result;
|
|
320
|
-
const endItem = paragraph.content[endRunIndex];
|
|
321
|
-
if (endItem.type === "run") {
|
|
322
|
-
const endText = chunkGACRQVPW_js.getRunText(endItem);
|
|
323
|
-
if (endOffset < endText.length) {
|
|
324
|
-
const afterRun = makeRunWithText(endText.slice(endOffset), endItem);
|
|
325
|
-
setRunText(endItem, endText.slice(0, endOffset));
|
|
326
|
-
paragraph.content.splice(endRunIndex + 1, 0, afterRun);
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
const startItem = paragraph.content[startRunIndex];
|
|
330
|
-
if (startItem.type === "run" && startOffset > 0) {
|
|
331
|
-
const startText = chunkGACRQVPW_js.getRunText(startItem);
|
|
332
|
-
const beforeRun = makeRunWithText(startText.slice(0, startOffset), startItem);
|
|
333
|
-
setRunText(startItem, startText.slice(startOffset));
|
|
334
|
-
paragraph.content.splice(startRunIndex, 0, beforeRun);
|
|
335
|
-
startRunIndex++;
|
|
336
|
-
endRunIndex++;
|
|
337
|
-
}
|
|
338
|
-
return { startIndex: startRunIndex, endIndex: endRunIndex };
|
|
339
|
-
}
|
|
340
|
-
function makeRunWithText(text, template) {
|
|
341
|
-
return {
|
|
342
|
-
type: "run",
|
|
343
|
-
content: [{ type: "text", text }],
|
|
344
|
-
formatting: template.formatting ? { ...template.formatting } : void 0
|
|
345
|
-
};
|
|
346
|
-
}
|
|
347
|
-
function setRunText(run, text) {
|
|
348
|
-
const textContent = run.content.find((c) => c.type === "text");
|
|
349
|
-
if (textContent) {
|
|
350
|
-
textContent.text = text;
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
function normalize(original) {
|
|
354
|
-
const chars = [];
|
|
355
|
-
const posMap = [];
|
|
356
|
-
let prevSpace = true;
|
|
357
|
-
for (let i = 0; i < original.length; i++) {
|
|
358
|
-
let ch = original[i];
|
|
359
|
-
if ("\u200B\u200C\u200D\uFEFF\xAD".includes(ch)) continue;
|
|
360
|
-
if ("\u201C\u201D\u201E\u201F".includes(ch)) ch = '"';
|
|
361
|
-
if ("\u2018\u2019\u201A\u201B".includes(ch)) ch = "'";
|
|
362
|
-
if ("\u2013\u2014\u2012\u2015".includes(ch)) ch = "-";
|
|
363
|
-
if (ch === "\u2026") {
|
|
364
|
-
chars.push(".", ".", ".");
|
|
365
|
-
posMap.push(i, i, i);
|
|
366
|
-
prevSpace = false;
|
|
367
|
-
continue;
|
|
368
|
-
}
|
|
369
|
-
if (/\s/.test(ch) || ch === "\xA0") {
|
|
370
|
-
if (!prevSpace) {
|
|
371
|
-
chars.push(" ");
|
|
372
|
-
posMap.push(i);
|
|
373
|
-
prevSpace = true;
|
|
374
|
-
}
|
|
375
|
-
continue;
|
|
376
|
-
}
|
|
377
|
-
chars.push(ch.toLowerCase());
|
|
378
|
-
posMap.push(i);
|
|
379
|
-
prevSpace = false;
|
|
380
|
-
}
|
|
381
|
-
if (chars.length > 0 && chars[chars.length - 1] === " ") {
|
|
382
|
-
chars.pop();
|
|
383
|
-
posMap.pop();
|
|
384
|
-
}
|
|
385
|
-
return { text: chars.join(""), posMap };
|
|
386
|
-
}
|
|
387
|
-
function mapBack(norm, idx, len, original) {
|
|
388
|
-
const start = norm.posMap[idx];
|
|
389
|
-
let end = norm.posMap[idx + len - 1] + 1;
|
|
390
|
-
while (end < original.length && "\u200B\u200C\u200D\uFEFF\xAD".includes(original[end])) end++;
|
|
391
|
-
return { start, end };
|
|
392
|
-
}
|
|
393
|
-
function findMatch(text, search) {
|
|
394
|
-
if (!search || !text) return null;
|
|
395
|
-
const exact = text.indexOf(search);
|
|
396
|
-
if (exact !== -1) return { start: exact, end: exact + search.length };
|
|
397
|
-
const normText = normalize(text);
|
|
398
|
-
const normSearch = normalize(search);
|
|
399
|
-
if (!normSearch.text) return null;
|
|
400
|
-
const idx = normText.text.indexOf(normSearch.text);
|
|
401
|
-
if (idx !== -1) return mapBack(normText, idx, normSearch.text.length, text);
|
|
402
|
-
const words = normSearch.text.split(" ");
|
|
403
|
-
if (words.length >= 3) {
|
|
404
|
-
for (let drop = 1; drop <= Math.min(2, words.length - 2); drop++) {
|
|
405
|
-
const trimmed = words.slice(0, -drop).join(" ");
|
|
406
|
-
const trimIdx = normText.text.indexOf(trimmed);
|
|
407
|
-
if (trimIdx !== -1) return mapBack(normText, trimIdx, trimmed.length, text);
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
return null;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
// src/discovery.ts
|
|
414
|
-
function getChanges(body, filter) {
|
|
415
|
-
const grouped = /* @__PURE__ */ new Map();
|
|
416
|
-
forEachParagraph(body, (para, paragraphIndex) => {
|
|
417
|
-
let context = null;
|
|
418
|
-
for (const item of para.content) {
|
|
419
|
-
if (isTrackedChange(item)) {
|
|
420
|
-
if (context === null) context = getParagraphPlainText(para);
|
|
421
|
-
const text = getTrackedChangeText(item.content);
|
|
422
|
-
const id = item.info.id;
|
|
423
|
-
const existing = grouped.get(id);
|
|
424
|
-
if (existing && existing.paragraphIndex === paragraphIndex) {
|
|
425
|
-
existing.text += text;
|
|
426
|
-
} else {
|
|
427
|
-
grouped.set(id, {
|
|
428
|
-
id,
|
|
429
|
-
type: item.type,
|
|
430
|
-
author: item.info.author,
|
|
431
|
-
date: item.info.date ?? null,
|
|
432
|
-
text,
|
|
433
|
-
context,
|
|
434
|
-
paragraphIndex
|
|
435
|
-
});
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
});
|
|
440
|
-
const changes = Array.from(grouped.values());
|
|
441
|
-
return changes.filter((c) => {
|
|
442
|
-
if (filter?.author && c.author !== filter.author) return false;
|
|
443
|
-
if (filter?.type && c.type !== filter.type) return false;
|
|
444
|
-
return true;
|
|
445
|
-
});
|
|
446
|
-
}
|
|
447
|
-
function getComments(body, filter) {
|
|
448
|
-
const comments = body.comments ?? [];
|
|
449
|
-
if (comments.length === 0) return [];
|
|
450
|
-
const anchoredTextMap = buildAnchoredTextMap(body);
|
|
451
|
-
const topLevel = [];
|
|
452
|
-
const repliesByParent = /* @__PURE__ */ new Map();
|
|
453
|
-
for (const c of comments) {
|
|
454
|
-
if (c.parentId !== void 0) {
|
|
455
|
-
const existing = repliesByParent.get(c.parentId) ?? [];
|
|
456
|
-
existing.push(c);
|
|
457
|
-
repliesByParent.set(c.parentId, existing);
|
|
458
|
-
} else {
|
|
459
|
-
topLevel.push(c);
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
const result = topLevel.map((c) => {
|
|
463
|
-
const anchor = anchoredTextMap.get(c.id);
|
|
464
|
-
const replies = (repliesByParent.get(c.id) ?? []).map((r) => ({
|
|
465
|
-
id: r.id,
|
|
466
|
-
author: r.author,
|
|
467
|
-
date: r.date ?? null,
|
|
468
|
-
text: getCommentText(r)
|
|
469
|
-
}));
|
|
470
|
-
return {
|
|
471
|
-
id: c.id,
|
|
472
|
-
author: c.author,
|
|
473
|
-
date: c.date ?? null,
|
|
474
|
-
text: getCommentText(c),
|
|
475
|
-
anchoredText: anchor?.text ?? "",
|
|
476
|
-
paragraphIndex: anchor?.paragraphIndex ?? -1,
|
|
477
|
-
replies,
|
|
478
|
-
done: c.done ?? false
|
|
479
|
-
};
|
|
480
|
-
});
|
|
481
|
-
return result.filter((c) => {
|
|
482
|
-
if (filter?.author && c.author !== filter.author) return false;
|
|
483
|
-
if (filter?.done !== void 0 && c.done !== filter.done) return false;
|
|
484
|
-
return true;
|
|
485
|
-
});
|
|
486
|
-
}
|
|
487
|
-
function getCommentText(comment) {
|
|
488
|
-
return comment.content.map((para) => getParagraphPlainText(para)).join("\n");
|
|
489
|
-
}
|
|
490
|
-
function buildAnchoredTextMap(body) {
|
|
491
|
-
const result = /* @__PURE__ */ new Map();
|
|
492
|
-
const openRanges = /* @__PURE__ */ new Map();
|
|
493
|
-
forEachParagraph(body, (para, paragraphIndex) => {
|
|
494
|
-
for (const item of para.content) {
|
|
495
|
-
if (item.type === "commentRangeStart") {
|
|
496
|
-
openRanges.set(item.id, { paragraphIndex, parts: [] });
|
|
497
|
-
} else if (item.type === "commentRangeEnd") {
|
|
498
|
-
const open = openRanges.get(item.id);
|
|
499
|
-
if (open) {
|
|
500
|
-
result.set(item.id, { text: open.parts.join(""), paragraphIndex: open.paragraphIndex });
|
|
501
|
-
openRanges.delete(item.id);
|
|
502
|
-
}
|
|
503
|
-
} else if (item.type === "run") {
|
|
504
|
-
const text = chunkGACRQVPW_js.getRunText(item);
|
|
505
|
-
for (const open of openRanges.values()) {
|
|
506
|
-
open.parts.push(text);
|
|
507
|
-
}
|
|
508
|
-
} else if (item.type === "hyperlink") {
|
|
509
|
-
const text = item.children.filter((c) => c.type === "run").map(chunkGACRQVPW_js.getRunText).join("");
|
|
510
|
-
for (const open of openRanges.values()) {
|
|
511
|
-
open.parts.push(text);
|
|
512
|
-
}
|
|
513
|
-
} else if (isTrackedChange(item)) {
|
|
514
|
-
const text = getTrackedChangeText(item.content);
|
|
515
|
-
for (const open of openRanges.values()) {
|
|
516
|
-
open.parts.push(text);
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
});
|
|
521
|
-
return result;
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
// src/comments.ts
|
|
525
|
-
function addComment(body, options) {
|
|
526
|
-
const { paragraphIndex, author = "AI", text, search } = options;
|
|
527
|
-
const para = getParagraphAtIndex(body, paragraphIndex);
|
|
528
|
-
const existingIds = (body.comments ?? []).map((c) => c.id);
|
|
529
|
-
const newId = existingIds.length > 0 ? Math.max(...existingIds) + 1 : 1;
|
|
530
|
-
const comment = {
|
|
531
|
-
id: newId,
|
|
532
|
-
author,
|
|
533
|
-
date: (/* @__PURE__ */ new Date()).toISOString(),
|
|
534
|
-
content: [
|
|
535
|
-
{
|
|
536
|
-
type: "paragraph",
|
|
537
|
-
content: [{ type: "run", content: [{ type: "text", text }] }],
|
|
538
|
-
formatting: {}
|
|
539
|
-
}
|
|
540
|
-
]
|
|
541
|
-
};
|
|
542
|
-
if (!body.comments) {
|
|
543
|
-
body.comments = [];
|
|
544
|
-
}
|
|
545
|
-
body.comments.push(comment);
|
|
546
|
-
if (search) {
|
|
547
|
-
const result = findTextInParagraph(para, search, paragraphIndex);
|
|
548
|
-
para.content.splice(result.endRunIndex + 1, 0, { type: "commentRangeEnd", id: newId });
|
|
549
|
-
para.content.splice(result.startRunIndex, 0, { type: "commentRangeStart", id: newId });
|
|
550
|
-
} else {
|
|
551
|
-
para.content.unshift({ type: "commentRangeStart", id: newId });
|
|
552
|
-
para.content.push({ type: "commentRangeEnd", id: newId });
|
|
553
|
-
}
|
|
554
|
-
return newId;
|
|
555
|
-
}
|
|
556
|
-
function replyTo(body, commentId, options) {
|
|
557
|
-
const comments = body.comments ?? [];
|
|
558
|
-
const parent = comments.find((c) => c.id === commentId);
|
|
559
|
-
if (!parent) {
|
|
560
|
-
throw new CommentNotFoundError(commentId);
|
|
561
|
-
}
|
|
562
|
-
const existingIds = comments.map((c) => c.id);
|
|
563
|
-
const newId = Math.max(...existingIds) + 1;
|
|
564
|
-
const reply = {
|
|
565
|
-
id: newId,
|
|
566
|
-
author: options.author ?? "AI",
|
|
567
|
-
date: (/* @__PURE__ */ new Date()).toISOString(),
|
|
568
|
-
parentId: commentId,
|
|
569
|
-
content: [
|
|
570
|
-
{
|
|
571
|
-
type: "paragraph",
|
|
572
|
-
content: [{ type: "run", content: [{ type: "text", text: options.text }] }],
|
|
573
|
-
formatting: {}
|
|
574
|
-
}
|
|
575
|
-
]
|
|
576
|
-
};
|
|
577
|
-
comments.push(reply);
|
|
578
|
-
return newId;
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
// src/changes.ts
|
|
582
|
-
function acceptChange(body, id) {
|
|
583
|
-
if (!processChangeById(body, id, "accept")) {
|
|
584
|
-
throw new ChangeNotFoundError(id);
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
function rejectChange(body, id) {
|
|
588
|
-
if (!processChangeById(body, id, "reject")) {
|
|
589
|
-
throw new ChangeNotFoundError(id);
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
function acceptAll(body) {
|
|
593
|
-
return processAllChanges(body, "accept");
|
|
594
|
-
}
|
|
595
|
-
function rejectAll(body) {
|
|
596
|
-
return processAllChanges(body, "reject");
|
|
597
|
-
}
|
|
598
|
-
function processAllChanges(body, mode) {
|
|
599
|
-
let count = 0;
|
|
600
|
-
forEachParagraph(body, (para) => {
|
|
601
|
-
for (let i = para.content.length - 1; i >= 0; i--) {
|
|
602
|
-
const item = para.content[i];
|
|
603
|
-
if (isTrackedChange(item)) {
|
|
604
|
-
applyChangeAtIndex(para, i, item, mode);
|
|
605
|
-
count++;
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
});
|
|
609
|
-
return count;
|
|
610
|
-
}
|
|
611
|
-
function processChangeById(body, id, mode) {
|
|
612
|
-
let found = false;
|
|
613
|
-
forEachParagraph(body, (para) => {
|
|
614
|
-
for (let i = para.content.length - 1; i >= 0; i--) {
|
|
615
|
-
const item = para.content[i];
|
|
616
|
-
if (isTrackedChange(item) && item.info.id === id) {
|
|
617
|
-
applyChangeAtIndex(para, i, item, mode);
|
|
618
|
-
found = true;
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
if (found) return false;
|
|
622
|
-
});
|
|
623
|
-
return found;
|
|
624
|
-
}
|
|
625
|
-
function applyChangeAtIndex(para, index, item, mode) {
|
|
626
|
-
const keepContent = item.type === "insertion" && mode === "accept" || item.type === "deletion" && mode === "reject" || item.type === "moveTo" && mode === "accept" || item.type === "moveFrom" && mode === "reject";
|
|
627
|
-
if (keepContent) {
|
|
628
|
-
const runs = item.content;
|
|
629
|
-
para.content.splice(index, 1, ...runs);
|
|
630
|
-
} else {
|
|
631
|
-
para.content.splice(index, 1);
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
function proposeReplacement(body, options) {
|
|
635
|
-
const { paragraphIndex, search, author = "AI", replaceWith } = options;
|
|
636
|
-
const para = getParagraphAtIndex(body, paragraphIndex);
|
|
637
|
-
const { startIndex, endIndex } = isolateMatchedText(para, search, paragraphIndex);
|
|
638
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
639
|
-
const baseId = nextRevisionId(body);
|
|
640
|
-
const matchedContent = para.content.slice(startIndex, endIndex + 1);
|
|
641
|
-
const deletion = {
|
|
642
|
-
type: "deletion",
|
|
643
|
-
info: { id: baseId, author, date: now },
|
|
644
|
-
content: matchedContent
|
|
645
|
-
};
|
|
646
|
-
const insertion = {
|
|
647
|
-
type: "insertion",
|
|
648
|
-
info: { id: baseId + 1, author, date: now },
|
|
649
|
-
content: [{ type: "run", content: [{ type: "text", text: replaceWith }] }]
|
|
650
|
-
};
|
|
651
|
-
para.content.splice(startIndex, endIndex - startIndex + 1, deletion, insertion);
|
|
652
|
-
}
|
|
653
|
-
function proposeInsertion(body, options) {
|
|
654
|
-
const { paragraphIndex, author = "AI", insertText, position = "after", search } = options;
|
|
655
|
-
const para = getParagraphAtIndex(body, paragraphIndex);
|
|
656
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
657
|
-
const id = nextRevisionId(body);
|
|
658
|
-
const insertion = {
|
|
659
|
-
type: "insertion",
|
|
660
|
-
info: { id, author, date: now },
|
|
661
|
-
content: [{ type: "run", content: [{ type: "text", text: insertText }] }]
|
|
662
|
-
};
|
|
663
|
-
if (search) {
|
|
664
|
-
const { startIndex, endIndex } = isolateMatchedText(para, search, paragraphIndex);
|
|
665
|
-
const insertAt = position === "after" ? endIndex + 1 : startIndex;
|
|
666
|
-
para.content.splice(insertAt, 0, insertion);
|
|
667
|
-
} else {
|
|
668
|
-
if (position === "before") {
|
|
669
|
-
para.content.unshift(insertion);
|
|
670
|
-
} else {
|
|
671
|
-
para.content.push(insertion);
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
function proposeDeletion(body, options) {
|
|
676
|
-
const { paragraphIndex, search, author = "AI" } = options;
|
|
677
|
-
const para = getParagraphAtIndex(body, paragraphIndex);
|
|
678
|
-
const { startIndex, endIndex } = isolateMatchedText(para, search, paragraphIndex);
|
|
679
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
680
|
-
const id = nextRevisionId(body);
|
|
681
|
-
const matchedContent = para.content.slice(startIndex, endIndex + 1);
|
|
682
|
-
const deletion = {
|
|
683
|
-
type: "deletion",
|
|
684
|
-
info: { id, author, date: now },
|
|
685
|
-
content: matchedContent
|
|
686
|
-
};
|
|
687
|
-
para.content.splice(startIndex, endIndex - startIndex + 1, deletion);
|
|
688
|
-
}
|
|
689
|
-
var revisionIdCache = /* @__PURE__ */ new WeakMap();
|
|
690
|
-
function nextRevisionId(body) {
|
|
691
|
-
let maxId = revisionIdCache.get(body);
|
|
692
|
-
if (maxId === void 0) {
|
|
693
|
-
maxId = 0;
|
|
694
|
-
forEachParagraph(body, (para) => {
|
|
695
|
-
for (const item of para.content) {
|
|
696
|
-
if (isTrackedChange(item)) {
|
|
697
|
-
maxId = Math.max(maxId, item.info.id);
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
});
|
|
701
|
-
}
|
|
702
|
-
const next = maxId + 1;
|
|
703
|
-
revisionIdCache.set(body, next + 1);
|
|
704
|
-
return next;
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
// src/batch.ts
|
|
708
|
-
function applyReview(body, ops, defaultAuthor = "AI") {
|
|
709
|
-
const errors = [];
|
|
710
|
-
let accepted = 0;
|
|
711
|
-
let rejected = 0;
|
|
712
|
-
let commentsAdded = 0;
|
|
713
|
-
let repliesAdded = 0;
|
|
714
|
-
let proposalsAdded = 0;
|
|
715
|
-
for (const id of ops.accept ?? []) {
|
|
716
|
-
try {
|
|
717
|
-
acceptChange(body, id);
|
|
718
|
-
accepted++;
|
|
719
|
-
} catch (e) {
|
|
720
|
-
errors.push({ operation: "accept", id, error: e.message });
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
for (const id of ops.reject ?? []) {
|
|
724
|
-
try {
|
|
725
|
-
rejectChange(body, id);
|
|
726
|
-
rejected++;
|
|
727
|
-
} catch (e) {
|
|
728
|
-
errors.push({ operation: "reject", id, error: e.message });
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
|
-
for (const opts of ops.comments ?? []) {
|
|
732
|
-
try {
|
|
733
|
-
addComment(body, { ...opts, author: opts.author ?? defaultAuthor });
|
|
734
|
-
commentsAdded++;
|
|
735
|
-
} catch (e) {
|
|
736
|
-
errors.push({ operation: "comment", search: opts.search, error: e.message });
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
for (const opts of ops.replies ?? []) {
|
|
740
|
-
try {
|
|
741
|
-
replyTo(body, opts.commentId, { author: opts.author ?? defaultAuthor, text: opts.text });
|
|
742
|
-
repliesAdded++;
|
|
743
|
-
} catch (e) {
|
|
744
|
-
errors.push({ operation: "reply", id: opts.commentId, error: e.message });
|
|
745
|
-
}
|
|
746
|
-
}
|
|
747
|
-
for (const opts of ops.proposals ?? []) {
|
|
748
|
-
try {
|
|
749
|
-
proposeReplacement(body, { ...opts, author: opts.author ?? defaultAuthor });
|
|
750
|
-
proposalsAdded++;
|
|
751
|
-
} catch (e) {
|
|
752
|
-
errors.push({ operation: "proposal", search: opts.search, error: e.message });
|
|
753
|
-
}
|
|
754
|
-
}
|
|
755
|
-
return { accepted, rejected, commentsAdded, repliesAdded, proposalsAdded, errors };
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
// src/DocxReviewer.ts
|
|
759
|
-
var DocxReviewer = class _DocxReviewer {
|
|
760
|
-
/**
|
|
761
|
-
* Create a reviewer from a parsed Document.
|
|
762
|
-
* @param document - Parsed Document from @eigenpal/docx-core
|
|
763
|
-
* @param author - Default author name for comments and changes. (default: 'AI')
|
|
764
|
-
* @param originalBuffer - Original DOCX buffer, needed for toBuffer()
|
|
765
|
-
*/
|
|
766
|
-
constructor(document, author = "AI", originalBuffer) {
|
|
767
|
-
const savedBuffer = originalBuffer ?? document.originalBuffer;
|
|
768
|
-
const { originalBuffer: _discard, ...rest } = document;
|
|
769
|
-
this.doc = structuredClone(rest);
|
|
770
|
-
if (savedBuffer) this.doc.originalBuffer = savedBuffer;
|
|
771
|
-
this.author = author;
|
|
772
|
-
}
|
|
773
|
-
/**
|
|
774
|
-
* Create a reviewer from a DOCX file buffer.
|
|
775
|
-
* @param buffer - ArrayBuffer of the DOCX file
|
|
776
|
-
* @param author - Default author name for comments and changes. (default: 'AI')
|
|
777
|
-
*/
|
|
778
|
-
static async fromBuffer(buffer, author = "AI") {
|
|
779
|
-
const doc = await chunkGACRQVPW_js.parseDocx(buffer, { preloadFonts: false });
|
|
780
|
-
return new _DocxReviewer(doc, author, buffer);
|
|
781
|
-
}
|
|
782
|
-
get body() {
|
|
783
|
-
return this.doc.package.document;
|
|
784
|
-
}
|
|
785
|
-
resolveAuthor(author) {
|
|
786
|
-
return author ?? this.author;
|
|
787
|
-
}
|
|
788
|
-
// ==========================================================================
|
|
789
|
-
// READ
|
|
790
|
-
// ==========================================================================
|
|
791
|
-
/** Get document content as structured blocks (headings, paragraphs, tables, lists). */
|
|
792
|
-
getContent(options) {
|
|
793
|
-
return getContent(this.body, options);
|
|
794
|
-
}
|
|
795
|
-
/**
|
|
796
|
-
* Get document content as plain text for LLM prompts.
|
|
797
|
-
* Each paragraph is prefixed with its index: `[0] text`, `[1] text`, etc.
|
|
798
|
-
* Table cells include position: `[5] (table, row 1, col 2) cell text`.
|
|
799
|
-
* Avoids JSON quote-escaping issues — LLMs can copy text verbatim.
|
|
800
|
-
*/
|
|
801
|
-
getContentAsText(options) {
|
|
802
|
-
return formatContentForLLM(getContent(this.body, options));
|
|
803
|
-
}
|
|
804
|
-
// ==========================================================================
|
|
805
|
-
// DISCOVER
|
|
806
|
-
// ==========================================================================
|
|
807
|
-
/** Get all tracked changes in the document. */
|
|
808
|
-
getChanges(filter) {
|
|
809
|
-
return getChanges(this.body, filter);
|
|
810
|
-
}
|
|
811
|
-
/** Get all comments with their replies. */
|
|
812
|
-
getComments(filter) {
|
|
813
|
-
return getComments(this.body, filter);
|
|
814
|
-
}
|
|
815
|
-
addComment(indexOrOptions, text) {
|
|
816
|
-
const opts = typeof indexOrOptions === "number" ? { paragraphIndex: indexOrOptions, text, author: this.author } : { ...indexOrOptions, author: this.resolveAuthor(indexOrOptions.author) };
|
|
817
|
-
return addComment(this.body, opts);
|
|
818
|
-
}
|
|
819
|
-
replyTo(commentId, textOrOptions) {
|
|
820
|
-
const opts = typeof textOrOptions === "string" ? { text: textOrOptions, author: this.author } : { ...textOrOptions, author: this.resolveAuthor(textOrOptions.author) };
|
|
821
|
-
return replyTo(this.body, commentId, opts);
|
|
822
|
-
}
|
|
823
|
-
replace(indexOrOptions, search, replaceWith) {
|
|
824
|
-
const opts = typeof indexOrOptions === "number" ? {
|
|
825
|
-
paragraphIndex: indexOrOptions,
|
|
826
|
-
search,
|
|
827
|
-
replaceWith,
|
|
828
|
-
author: this.author
|
|
829
|
-
} : { ...indexOrOptions, author: this.resolveAuthor(indexOrOptions.author) };
|
|
830
|
-
proposeReplacement(this.body, opts);
|
|
831
|
-
}
|
|
832
|
-
/** @deprecated Use replace() instead. */
|
|
833
|
-
proposeReplacement(options) {
|
|
834
|
-
this.replace(options);
|
|
835
|
-
}
|
|
836
|
-
/** Insert text as a tracked change. */
|
|
837
|
-
proposeInsertion(options) {
|
|
838
|
-
proposeInsertion(this.body, {
|
|
839
|
-
...options,
|
|
840
|
-
author: this.resolveAuthor(options.author)
|
|
841
|
-
});
|
|
842
|
-
}
|
|
843
|
-
/** Delete text as a tracked change. */
|
|
844
|
-
proposeDeletion(options) {
|
|
845
|
-
proposeDeletion(this.body, {
|
|
846
|
-
...options,
|
|
847
|
-
author: this.resolveAuthor(options.author)
|
|
848
|
-
});
|
|
849
|
-
}
|
|
850
|
-
// ==========================================================================
|
|
851
|
-
// RESOLVE
|
|
852
|
-
// ==========================================================================
|
|
853
|
-
/** Accept a tracked change by its revision ID. */
|
|
854
|
-
acceptChange(id) {
|
|
855
|
-
acceptChange(this.body, id);
|
|
856
|
-
}
|
|
857
|
-
/** Reject a tracked change by its revision ID. */
|
|
858
|
-
rejectChange(id) {
|
|
859
|
-
rejectChange(this.body, id);
|
|
860
|
-
}
|
|
861
|
-
/** Accept all tracked changes. Returns count accepted. */
|
|
862
|
-
acceptAll() {
|
|
863
|
-
return acceptAll(this.body);
|
|
864
|
-
}
|
|
865
|
-
/** Reject all tracked changes. Returns count rejected. */
|
|
866
|
-
rejectAll() {
|
|
867
|
-
return rejectAll(this.body);
|
|
868
|
-
}
|
|
869
|
-
// ==========================================================================
|
|
870
|
-
// BATCH
|
|
871
|
-
// ==========================================================================
|
|
872
|
-
/**
|
|
873
|
-
* Apply multiple review operations in one call.
|
|
874
|
-
* Uses the reviewer's default author. Individual failures are collected, not thrown.
|
|
875
|
-
*/
|
|
876
|
-
applyReview(ops) {
|
|
877
|
-
return applyReview(this.body, ops, this.author);
|
|
878
|
-
}
|
|
879
|
-
// ==========================================================================
|
|
880
|
-
// EXPORT
|
|
881
|
-
// ==========================================================================
|
|
882
|
-
/** Get the modified Document model. */
|
|
883
|
-
toDocument() {
|
|
884
|
-
return this.doc;
|
|
885
|
-
}
|
|
886
|
-
/** Serialize back to a DOCX buffer. Requires the original buffer. */
|
|
887
|
-
async toBuffer() {
|
|
888
|
-
if (!this.doc.originalBuffer) {
|
|
889
|
-
throw new Error(
|
|
890
|
-
"Cannot create buffer: no original DOCX buffer was provided. Use DocxReviewer.fromBuffer() or pass originalBuffer to the constructor."
|
|
891
|
-
);
|
|
892
|
-
}
|
|
893
|
-
const { repackDocx } = await import('./headless-O2RRWYCB.js');
|
|
894
|
-
return repackDocx(this.doc);
|
|
895
|
-
}
|
|
896
|
-
};
|
|
897
|
-
|
|
898
|
-
exports.ChangeNotFoundError = ChangeNotFoundError;
|
|
899
|
-
exports.CommentNotFoundError = CommentNotFoundError;
|
|
900
|
-
exports.DocxReviewer = DocxReviewer;
|
|
901
|
-
exports.TextNotFoundError = TextNotFoundError;
|
|
902
|
-
//# sourceMappingURL=index.js.map
|
|
903
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
'use strict';var chunkT3PAPI4X_js=require('./chunk-T3PAPI4X.js');function d(r){return r.type==="insertion"||r.type==="deletion"||r.type==="moveFrom"||r.type==="moveTo"}function y(r){let e=[];for(let t of r)t.type==="run"?e.push(chunkT3PAPI4X_js.Q(t)):t.type==="hyperlink"&&e.push(chunkT3PAPI4X_js.R(t));return e.join("")}function h(r,e){let t=0;for(let o of r.content)if(o.type==="paragraph"){if(t===e)return o;t++;}else if(o.type==="table"){for(let s of o.rows)for(let n of s.cells)for(let i of n.content)if(i.type==="paragraph"){if(t===e)return i;t++;}}else t++;throw new Error(`Paragraph index ${e} out of bounds (max: ${t-1})`)}function f(r,e){let t=0;for(let o of r.content)if(o.type==="paragraph"){if(e(o,t)===false)return;t++;}else if(o.type==="table"){for(let s of o.rows)for(let n of s.cells)for(let i of n.content)if(i.type==="paragraph"){if(e(i,t)===false)return;t++;}}else t++;}function O(r,e={}){let{fromIndex:t,toIndex:o,includeTrackedChanges:s=true,includeCommentAnchors:n=true}=e,i=[],a=0;for(let p of r.content)if(p.type==="paragraph")S(a,t,o)&&i.push(oe(p,a,s,n)),a++;else if(p.type==="table"){S(a,t,o)&&i.push(re(p,a,s,n));for(let u of p.rows)for(let c of u.cells)for(let m of c.content)m.type==="paragraph"&&a++;}else a++;return i}function S(r,e,t){return (e===void 0||r>=e)&&(t===void 0||r<=t)}function oe(r,e,t,o){let s=L(r,t,o),n=r.formatting?.styleId;return chunkT3PAPI4X_js.ba(n)?{type:"heading",index:e,level:chunkT3PAPI4X_js.ca(n)??1,text:s}:r.listRendering?{type:"list-item",index:e,text:s,listLevel:r.listRendering.level??0,listType:r.listRendering.isBullet?"bullet":"number"}:{type:"paragraph",index:e,text:s}}function re(r,e,t,o){let s=[];for(let n of r.rows){let i=[];for(let a of n.cells){let p=[];for(let u of a.content)u.type==="paragraph"&&p.push(L(u,t,o));i.push(p.join(`
|
|
2
|
+
`));}s.push(i);}return {type:"table",index:e,rows:s}}function H(r){let e=[];for(let t of r)switch(t.type){case "heading":e.push(`[${t.index}] (h${t.level}) ${t.text}`);break;case "paragraph":e.push(`[${t.index}] ${t.text}`);break;case "list-item":{let o=" ".repeat(t.listLevel),s=t.listType==="bullet"?"\u2022":"-";e.push(`[${t.index}] ${o}${s} ${t.text}`);break}case "table":{let o=t.index;for(let s=0;s<t.rows.length;s++)for(let n=0;n<t.rows[s].length;n++){let a=t.rows[s][n].split(`
|
|
3
|
+
`);for(let p of a)e.push(`[${o}] (table, row ${s+1}, col ${n+1}) ${p}`),o++;}break}}return e.join(`
|
|
4
|
+
`)}function L(r,e,t){let o=[],s=new Set;for(let n of r.content){if(n.type==="commentRangeStart"&&t){s.add(n.id),o.push(`[comment:${n.id}]`);continue}if(n.type==="commentRangeEnd"&&t){s.has(n.id)&&(s.delete(n.id),o.push("[/comment]"));continue}if(n.type==="run")o.push(chunkT3PAPI4X_js.Q(n));else if(n.type==="hyperlink")o.push(chunkT3PAPI4X_js.R(n));else if(d(n)){let i=y(n.content);n.type==="insertion"||n.type==="moveTo"?e?o.push(`[+${i}+]{by:${n.info.author}}`):o.push(i):e&&o.push(`[-${i}-]{by:${n.info.author}}`);}}return o.join("")}var g=class extends Error{constructor(e,t){let o=t!==void 0?` in paragraph ${t}`:" in document";super(`Text not found${o}: "${e}"`),this.name="TextNotFoundError";}},x=class extends Error{constructor(e){super(`Tracked change not found: id=${e}`),this.name="ChangeNotFoundError";}},C=class extends Error{constructor(e){super(`Comment not found: id=${e}`),this.name="CommentNotFoundError";}};function U(r){let e=[],t=0;for(let o=0;o<r.content.length;o++){let s=r.content[o];if(s.type==="run"){let n=chunkT3PAPI4X_js.Q(s);e.push({contentIndex:o,run:s,text:n,startPos:t}),t+=n.length;}else if(s.type==="hyperlink")for(let n=0;n<s.children.length;n++){let i=s.children[n];if(i.type==="run"){let a=chunkT3PAPI4X_js.Q(i);e.push({contentIndex:o,run:i,text:a,startPos:t}),t+=a.length;}}else if(d(s))for(let n=0;n<s.content.length;n++){let i=s.content[n];if(i.type==="run"){let a=chunkT3PAPI4X_js.Q(i);e.push({contentIndex:o,run:i,text:a,startPos:t}),t+=a.length;}else if(i.type==="hyperlink"){for(let a of i.children)if(a.type==="run"){let p=chunkT3PAPI4X_js.Q(a);e.push({contentIndex:o,run:a,text:p,startPos:t}),t+=p.length;}}}}return e}function F(r){return U(r).map(e=>e.text).join("")}function j(r,e,t){let o=U(r),s=o.map(c=>c.text).join(""),n=se(s,e);if(!n)throw new g(e,t);let i=-1,a=0;for(let c=0;c<o.length;c++)if(n.start<o[c].startPos+o[c].text.length){i=c,a=n.start-o[c].startPos;break}let p=-1,u=0;for(let c=o.length-1;c>=0;c--)if(n.end>o[c].startPos){p=c,u=n.end-o[c].startPos;break}if(i===-1||p===-1)throw new g(e,t);return {startRunIndex:o[i].contentIndex,startOffset:a,endRunIndex:o[p].contentIndex,endOffset:u}}function I(r,e,t){let o=j(r,e,t),{startRunIndex:s,endRunIndex:n}=o,{startOffset:i,endOffset:a}=o,p=r.content[n];if(p.type==="run"){let c=chunkT3PAPI4X_js.Q(p);if(a<c.length){let m=G(c.slice(a),p);N(p,c.slice(0,a)),r.content.splice(n+1,0,m);}}let u=r.content[s];if(u.type==="run"&&i>0){let c=chunkT3PAPI4X_js.Q(u),m=G(c.slice(0,i),u);N(u,c.slice(i)),r.content.splice(s,0,m),s++,n++;}return {startIndex:s,endIndex:n}}function G(r,e){return {type:"run",content:[{type:"text",text:r}],formatting:e.formatting?{...e.formatting}:void 0}}function N(r,e){let t=r.content.find(o=>o.type==="text");t&&(t.text=e);}function W(r){let e=[],t=[],o=true;for(let s=0;s<r.length;s++){let n=r[s];if(!"\u200B\u200C\u200D\uFEFF\xAD".includes(n)){if("\u201C\u201D\u201E\u201F".includes(n)&&(n='"'),"\u2018\u2019\u201A\u201B".includes(n)&&(n="'"),"\u2013\u2014\u2012\u2015".includes(n)&&(n="-"),n==="\u2026"){e.push(".",".","."),t.push(s,s,s),o=false;continue}if(/\s/.test(n)||n==="\xA0"){o||(e.push(" "),t.push(s),o=true);continue}e.push(n.toLowerCase()),t.push(s),o=false;}}return e.length>0&&e[e.length-1]===" "&&(e.pop(),t.pop()),{text:e.join(""),posMap:t}}function z(r,e,t,o){let s=r.posMap[e],n=r.posMap[e+t-1]+1;for(;n<o.length&&"\u200B\u200C\u200D\uFEFF\xAD".includes(o[n]);)n++;return {start:s,end:n}}function se(r,e){if(!e||!r)return null;let t=r.indexOf(e);if(t!==-1)return {start:t,end:t+e.length};let o=W(r),s=W(e);if(!s.text)return null;let n=o.text.indexOf(s.text);if(n!==-1)return z(o,n,s.text.length,r);let i=s.text.split(" ");if(i.length>=3)for(let a=1;a<=Math.min(2,i.length-2);a++){let p=i.slice(0,-a).join(" "),u=o.text.indexOf(p);if(u!==-1)return z(o,u,p.length,r)}return null}function q(r,e){let t=new Map;return f(r,(s,n)=>{let i=null;for(let a of s.content)if(d(a)){i===null&&(i=F(s));let p=y(a.content),u=a.info.id,c=t.get(u);c&&c.paragraphIndex===n?c.text+=p:t.set(u,{id:u,type:a.type,author:a.info.author,date:a.info.date??null,text:p,context:i,paragraphIndex:n});}}),Array.from(t.values()).filter(s=>!(e?.author&&s.author!==e.author||e?.type&&s.type!==e.type))}function J(r,e){let t=r.comments??[];if(t.length===0)return [];let o=ae(r),s=[],n=new Map;for(let a of t)if(a.parentId!==void 0){let p=n.get(a.parentId)??[];p.push(a),n.set(a.parentId,p);}else s.push(a);return s.map(a=>{let p=o.get(a.id),u=(n.get(a.id)??[]).map(c=>({id:c.id,author:c.author,date:c.date??null,text:X(c)}));return {id:a.id,author:a.author,date:a.date??null,text:X(a),anchoredText:p?.text??"",paragraphIndex:p?.paragraphIndex??-1,replies:u,done:a.done??false}}).filter(a=>!(e?.author&&a.author!==e.author||e?.done!==void 0&&a.done!==e.done))}function X(r){return r.content.map(e=>F(e)).join(`
|
|
5
|
+
`)}function ae(r){let e=new Map,t=new Map;return f(r,(o,s)=>{for(let n of o.content)if(n.type==="commentRangeStart")t.set(n.id,{paragraphIndex:s,parts:[]});else if(n.type==="commentRangeEnd"){let i=t.get(n.id);i&&(e.set(n.id,{text:i.parts.join(""),paragraphIndex:i.paragraphIndex}),t.delete(n.id));}else if(n.type==="run"){let i=chunkT3PAPI4X_js.Q(n);for(let a of t.values())a.parts.push(i);}else if(n.type==="hyperlink"){let i=n.children.filter(a=>a.type==="run").map(chunkT3PAPI4X_js.Q).join("");for(let a of t.values())a.parts.push(i);}else if(d(n)){let i=y(n.content);for(let a of t.values())a.parts.push(i);}}),e}function R(r,e){let{paragraphIndex:t,author:o="AI",text:s,search:n}=e,i=h(r,t),a=(r.comments??[]).map(c=>c.id),p=a.length>0?Math.max(...a)+1:1,u={id:p,author:o,date:new Date().toISOString(),content:[{type:"paragraph",content:[{type:"run",content:[{type:"text",text:s}]}],formatting:{}}]};if(r.comments||(r.comments=[]),r.comments.push(u),n){let c=j(i,n,t);i.content.splice(c.endRunIndex+1,0,{type:"commentRangeEnd",id:p}),i.content.splice(c.startRunIndex,0,{type:"commentRangeStart",id:p});}else i.content.unshift({type:"commentRangeStart",id:p}),i.content.push({type:"commentRangeEnd",id:p});return p}function v(r,e,t){let o=r.comments??[];if(!o.find(p=>p.id===e))throw new C(e);let n=o.map(p=>p.id),i=Math.max(...n)+1,a={id:i,author:t.author??"AI",date:new Date().toISOString(),parentId:e,content:[{type:"paragraph",content:[{type:"run",content:[{type:"text",text:t.text}]}],formatting:{}}]};return o.push(a),i}function w(r,e){if(!Z(r,e,"accept"))throw new x(e)}function B(r,e){if(!Z(r,e,"reject"))throw new x(e)}function Q(r){return Y(r,"accept")}function V(r){return Y(r,"reject")}function Y(r,e){let t=0;return f(r,o=>{for(let s=o.content.length-1;s>=0;s--){let n=o.content[s];d(n)&&(_(o,s,n,e),t++);}}),t}function Z(r,e,t){let o=false;return f(r,s=>{for(let n=s.content.length-1;n>=0;n--){let i=s.content[n];d(i)&&i.info.id===e&&(_(s,n,i,t),o=true);}if(o)return false}),o}function _(r,e,t,o){if(t.type==="insertion"&&o==="accept"||t.type==="deletion"&&o==="reject"||t.type==="moveTo"&&o==="accept"||t.type==="moveFrom"&&o==="reject"){let n=t.content;r.content.splice(e,1,...n);}else r.content.splice(e,1);}function T(r,e){let{paragraphIndex:t,search:o,author:s="AI",replaceWith:n}=e,i=h(r,t),{startIndex:a,endIndex:p}=I(i,o,t),u=new Date().toISOString(),c=E(r),m=i.content.slice(a,p+1),D={type:"deletion",info:{id:c,author:s,date:u},content:m},P={type:"insertion",info:{id:c+1,author:s,date:u},content:[{type:"run",content:[{type:"text",text:n}]}]};i.content.splice(a,p-a+1,D,P);}function ee(r,e){let{paragraphIndex:t,author:o="AI",insertText:s,position:n="after",search:i}=e,a=h(r,t),p=new Date().toISOString(),c={type:"insertion",info:{id:E(r),author:o,date:p},content:[{type:"run",content:[{type:"text",text:s}]}]};if(i){let{startIndex:m,endIndex:D}=I(a,i,t),P=n==="after"?D+1:m;a.content.splice(P,0,c);}else n==="before"?a.content.unshift(c):a.content.push(c);}function te(r,e){let{paragraphIndex:t,search:o,author:s="AI"}=e,n=h(r,t),{startIndex:i,endIndex:a}=I(n,o,t),p=new Date().toISOString(),u=E(r),c=n.content.slice(i,a+1),m={type:"deletion",info:{id:u,author:s,date:p},content:c};n.content.splice(i,a-i+1,m);}var K=new WeakMap;function E(r){let e=K.get(r);e===void 0&&(e=0,f(r,o=>{for(let s of o.content)d(s)&&(e=Math.max(e,s.info.id));}));let t=e+1;return K.set(r,t+1),t}function ne(r,e,t="AI"){let o=[],s=0,n=0,i=0,a=0,p=0;for(let u of e.accept??[])try{w(r,u),s++;}catch(c){o.push({operation:"accept",id:u,error:c.message});}for(let u of e.reject??[])try{B(r,u),n++;}catch(c){o.push({operation:"reject",id:u,error:c.message});}for(let u of e.comments??[])try{R(r,{...u,author:u.author??t}),i++;}catch(c){o.push({operation:"comment",search:u.search,error:c.message});}for(let u of e.replies??[])try{v(r,u.commentId,{author:u.author??t,text:u.text}),a++;}catch(c){o.push({operation:"reply",id:u.commentId,error:c.message});}for(let u of e.proposals??[])try{T(r,{...u,author:u.author??t}),p++;}catch(c){o.push({operation:"proposal",search:u.search,error:c.message});}return {accepted:s,rejected:n,commentsAdded:i,repliesAdded:a,proposalsAdded:p,errors:o}}var M=class r{constructor(e,t="AI",o){let s=o??e.originalBuffer,{originalBuffer:n,...i}=e;this.doc=structuredClone(i),s&&(this.doc.originalBuffer=s),this.author=t;}static async fromBuffer(e,t="AI"){let o=await chunkT3PAPI4X_js.F(e,{preloadFonts:false});return new r(o,t,e)}get body(){return this.doc.package.document}resolveAuthor(e){return e??this.author}getContent(e){return O(this.body,e)}getContentAsText(e){return H(O(this.body,e))}getChanges(e){return q(this.body,e)}getComments(e){return J(this.body,e)}addComment(e,t){let o=typeof e=="number"?{paragraphIndex:e,text:t,author:this.author}:{...e,author:this.resolveAuthor(e.author)};return R(this.body,o)}replyTo(e,t){let o=typeof t=="string"?{text:t,author:this.author}:{...t,author:this.resolveAuthor(t.author)};return v(this.body,e,o)}replace(e,t,o){let s=typeof e=="number"?{paragraphIndex:e,search:t,replaceWith:o,author:this.author}:{...e,author:this.resolveAuthor(e.author)};T(this.body,s);}proposeReplacement(e){this.replace(e);}proposeInsertion(e){ee(this.body,{...e,author:this.resolveAuthor(e.author)});}proposeDeletion(e){te(this.body,{...e,author:this.resolveAuthor(e.author)});}acceptChange(e){w(this.body,e);}rejectChange(e){B(this.body,e);}acceptAll(){return Q(this.body)}rejectAll(){return V(this.body)}applyReview(e){return ne(this.body,e,this.author)}toDocument(){return this.doc}async toBuffer(){if(!this.doc.originalBuffer)throw new Error("Cannot create buffer: no original DOCX buffer was provided. Use DocxReviewer.fromBuffer() or pass originalBuffer to the constructor.");let{repackDocx:e}=await import('./headless-SJ66VOJQ.js');return e(this.doc)}};exports.ChangeNotFoundError=x;exports.CommentNotFoundError=C;exports.DocxReviewer=M;exports.TextNotFoundError=g;
|