@ansonlai/docx-redline-js 0.8.2 → 0.8.4
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/CHANGELOG.md +75 -1
- package/README.md +28 -13
- package/core/list-targeting.js +12 -10
- package/dist/docx-redline-js.esm.js +837 -549
- package/dist/docx-redline-js.esm.js.map +4 -4
- package/dist/docx-redline-js.esm.min.js +93 -90
- package/dist/docx-redline-js.esm.min.js.map +4 -4
- package/dist/docx-redline.bundle.cjs +837 -549
- package/dist/docx-redline.bundle.cjs.map +4 -4
- package/dist/docx-redline.bundle.js +837 -549
- package/dist/docx-redline.bundle.js.map +4 -4
- package/docs/AGENT_KNOWLEDGE_BASE.md +4 -1
- package/docs/schemas/document-operations.schema.json +168 -168
- package/engine/oxml-engine.js +215 -195
- package/engine/reconstruction-mode.js +183 -183
- package/index.d.ts +4 -0
- package/index.js +36 -1
- package/node/cli.js +2 -1
- package/orchestration/list-structural-fallback.js +530 -518
- package/package.json +1 -1
- package/pipeline/list-generation.js +203 -168
- package/pipeline/serialization.js +111 -94
- package/services/batch-operation-orchestrator.js +6 -0
- package/services/document-inspection.js +10 -7
- package/services/document-operation-applier.js +2 -0
- package/services/document-operation-contract.js +553 -537
- package/services/document-operation-mutations.js +1140 -1011
- package/services/numbering-helpers.js +108 -0
- package/services/operation-batch-compiler.js +440 -436
- package/services/operation-heuristics.js +197 -173
- package/services/revision-comment-management.js +601 -594
- package/services/standalone-operation-runner.d.ts +429 -427
- package/services/table-reconciliation.js +48 -46
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import { computeWordLevelDiffOps } from '../pipeline/diff-engine.js';
|
|
8
8
|
import { splitRunsAtDiffBoundaries, applyPatches } from '../pipeline/patching.js';
|
|
9
9
|
import { serializeToOoxml } from '../pipeline/serialization.js';
|
|
10
|
-
import { createRevisionMetadata, escapeXml, RunKind } from '../core/types.js';
|
|
10
|
+
import { createRevisionMetadata, escapeXml, RunKind } from '../core/types.js';
|
|
11
11
|
import { preprocessMarkdown } from '../pipeline/markdown-processor.js';
|
|
12
12
|
|
|
13
13
|
/**
|
|
@@ -18,14 +18,16 @@ import { preprocessMarkdown } from '../pipeline/markdown-processor.js';
|
|
|
18
18
|
* @param {Object} options - { generateRedlines, author }
|
|
19
19
|
* @returns {string} Complete w:tbl OOXML
|
|
20
20
|
*/
|
|
21
|
-
export function generateTableOoxml(tableData, options = {}) {
|
|
22
|
-
const {
|
|
23
|
-
generateRedlines = false,
|
|
24
|
-
author = 'AI',
|
|
25
|
-
revisionIdAllocator = null,
|
|
26
|
-
trackAsBlock = false
|
|
27
|
-
} = options;
|
|
28
|
-
|
|
21
|
+
export function generateTableOoxml(tableData, options = {}) {
|
|
22
|
+
const {
|
|
23
|
+
generateRedlines = false,
|
|
24
|
+
author = 'AI',
|
|
25
|
+
revisionIdAllocator = null,
|
|
26
|
+
trackAsBlock = false
|
|
27
|
+
} = options;
|
|
28
|
+
// trackAsBlock: Word-native inserted table = tracked-inserted rows (trPr/ins), inserted cell runs and
|
|
29
|
+
// tracked-inserted cell paragraph marks. (w:ins around w:tbl is not a table insertion to Word.)
|
|
30
|
+
const trackRows = generateRedlines && trackAsBlock;
|
|
29
31
|
|
|
30
32
|
// Determine number of columns
|
|
31
33
|
const numCols = tableData.headers?.length || (tableData.rows?.[0]?.length || 1);
|
|
@@ -65,7 +67,7 @@ export function generateTableOoxml(tableData, options = {}) {
|
|
|
65
67
|
|
|
66
68
|
// Build run model for the cell
|
|
67
69
|
const runModel = [{
|
|
68
|
-
kind: generateRedlines
|
|
70
|
+
kind: generateRedlines ? RunKind.INSERTION : RunKind.TEXT,
|
|
69
71
|
text: cleanText,
|
|
70
72
|
rPrXml: isHeaderRow ? '<w:rPr><w:b/></w:rPr>' : '',
|
|
71
73
|
author,
|
|
@@ -73,11 +75,15 @@ export function generateTableOoxml(tableData, options = {}) {
|
|
|
73
75
|
endOffset: cleanText.length
|
|
74
76
|
}];
|
|
75
77
|
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
const cellMarkMeta = trackRows ? createRevisionMetadata(author, revisionIdAllocator) : null;
|
|
79
|
+
const cellPPr = cellMarkMeta
|
|
80
|
+
? `<w:pPr><w:rPr><w:ins w:id="${cellMarkMeta.id}" w:author="${escapeXml(cellMarkMeta.author)}" w:date="${cellMarkMeta.date}"/></w:rPr></w:pPr>`
|
|
81
|
+
: null;
|
|
82
|
+
const runsOoxml = serializeToOoxml(runModel, cellPPr, formatHints, {
|
|
83
|
+
author,
|
|
84
|
+
generateRedlines,
|
|
85
|
+
revisionIdAllocator
|
|
86
|
+
});
|
|
81
87
|
|
|
82
88
|
// Cell properties
|
|
83
89
|
const tcPr = '<w:tcPr><w:tcW w:w="0" w:type="auto"/></w:tcPr>';
|
|
@@ -85,24 +91,20 @@ export function generateTableOoxml(tableData, options = {}) {
|
|
|
85
91
|
cellsXml += `<w:tc>${tcPr}${runsOoxml}</w:tc>`;
|
|
86
92
|
}
|
|
87
93
|
|
|
88
|
-
// Keep each logical record intact across page boundaries. When a
|
|
89
|
-
// Markdown header is present, also mark it as a repeating Word table
|
|
90
|
-
// header so continuation pages retain their column labels.
|
|
91
|
-
const trPr = isHeaderRow
|
|
92
|
-
? '<w:trPr><w:tblHeader/><w:cantSplit/></w:trPr>'
|
|
93
|
-
: '<w:trPr><w:cantSplit/></w:trPr>';
|
|
94
|
-
|
|
94
|
+
// Keep each logical record intact across page boundaries. When a
|
|
95
|
+
// Markdown header is present, also mark it as a repeating Word table
|
|
96
|
+
// header so continuation pages retain their column labels.
|
|
97
|
+
const trPr = isHeaderRow
|
|
98
|
+
? '<w:trPr><w:tblHeader/><w:cantSplit/></w:trPr>'
|
|
99
|
+
: '<w:trPr><w:cantSplit/></w:trPr>';
|
|
100
|
+
const rowMeta = trackRows ? createRevisionMetadata(author, revisionIdAllocator) : null;
|
|
101
|
+
const trackedTrPr = rowMeta
|
|
102
|
+
? trPr.replace('</w:trPr>', `<w:ins w:id="${rowMeta.id}" w:author="${escapeXml(rowMeta.author)}" w:date="${rowMeta.date}"/></w:trPr>`)
|
|
103
|
+
: trPr;
|
|
104
|
+
rowsXml += `<w:tr>${trackedTrPr}${cellsXml}</w:tr>`;
|
|
95
105
|
}
|
|
96
106
|
|
|
97
|
-
|
|
98
|
-
let tableXml = `<w:tbl>${tblPr}${tblGrid}${rowsXml}</w:tbl>`;
|
|
99
|
-
|
|
100
|
-
// Wrap entire table in w:ins if generating redlines
|
|
101
|
-
if (tableInsertMeta) {
|
|
102
|
-
tableXml = `<w:ins w:id="${tableInsertMeta.id}" w:author="${escapeXml(tableInsertMeta.author)}" w:date="${tableInsertMeta.date}">${tableXml}</w:ins>`;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return tableXml;
|
|
107
|
+
return `<w:tbl>${tblPr}${tblGrid}${rowsXml}</w:tbl>`;
|
|
106
108
|
}
|
|
107
109
|
|
|
108
110
|
/**
|
|
@@ -177,7 +179,7 @@ export function diffTablesWithVirtualGrid(oldGrid, newTableData) {
|
|
|
177
179
|
* @returns {string} Reconciled w:tbl OOXML
|
|
178
180
|
*/
|
|
179
181
|
export function serializeVirtualGridToOoxml(grid, operations, options) {
|
|
180
|
-
const { generateRedlines, author, revisionIdAllocator = null } = options;
|
|
182
|
+
const { generateRedlines, author, revisionIdAllocator = null } = options;
|
|
181
183
|
const opIndex = buildTableOperationIndex(operations);
|
|
182
184
|
|
|
183
185
|
let rowsXml = '';
|
|
@@ -219,7 +221,7 @@ export function serializeVirtualGridToOoxml(grid, operations, options) {
|
|
|
219
221
|
let trPr = grid.trPrList[row] || '<w:trPr/>';
|
|
220
222
|
|
|
221
223
|
if (rowDeleteOp && generateRedlines) {
|
|
222
|
-
const metadata = createRevisionMetadata(author, revisionIdAllocator);
|
|
224
|
+
const metadata = createRevisionMetadata(author, revisionIdAllocator);
|
|
223
225
|
const delMark = `<w:del w:id="${metadata.id}" w:author="${escapeXml(metadata.author)}" w:date="${metadata.date}"/>`;
|
|
224
226
|
if (trPr.includes('</w:trPr>')) {
|
|
225
227
|
trPr = trPr.replace('</w:trPr>', `${delMark}</w:trPr>`);
|
|
@@ -235,7 +237,7 @@ export function serializeVirtualGridToOoxml(grid, operations, options) {
|
|
|
235
237
|
const insertOps = opIndex.rowInsertOperations;
|
|
236
238
|
for (const op of insertOps) {
|
|
237
239
|
let cellsXml = '';
|
|
238
|
-
const rowInsertMeta = generateRedlines ? createRevisionMetadata(author, revisionIdAllocator) : null;
|
|
240
|
+
const rowInsertMeta = generateRedlines ? createRevisionMetadata(author, revisionIdAllocator) : null;
|
|
239
241
|
|
|
240
242
|
for (const cellText of op.cells) {
|
|
241
243
|
const { cleanText, formatHints } = preprocessMarkdown(cellText);
|
|
@@ -249,11 +251,11 @@ export function serializeVirtualGridToOoxml(grid, operations, options) {
|
|
|
249
251
|
endOffset: cleanText.length
|
|
250
252
|
}];
|
|
251
253
|
|
|
252
|
-
const runsOoxml = serializeToOoxml(runModel, null, formatHints, {
|
|
253
|
-
author,
|
|
254
|
-
generateRedlines,
|
|
255
|
-
revisionIdAllocator
|
|
256
|
-
});
|
|
254
|
+
const runsOoxml = serializeToOoxml(runModel, null, formatHints, {
|
|
255
|
+
author,
|
|
256
|
+
generateRedlines,
|
|
257
|
+
revisionIdAllocator
|
|
258
|
+
});
|
|
257
259
|
// serializeToOoxml already returns one or more w:p blocks.
|
|
258
260
|
cellsXml += `<w:tc><w:tcPr><w:tcW w:w="0" w:type="auto"/></w:tcPr>${runsOoxml}</w:tc>`;
|
|
259
261
|
}
|
|
@@ -310,7 +312,7 @@ function buildTableOperationIndex(operations) {
|
|
|
310
312
|
}
|
|
311
313
|
|
|
312
314
|
function reconcileCellContent(cell, newText, options) {
|
|
313
|
-
const { generateRedlines, author, revisionIdAllocator = null } = options;
|
|
315
|
+
const { generateRedlines, author, revisionIdAllocator = null } = options;
|
|
314
316
|
const { cleanText, formatHints } = preprocessMarkdown(newText);
|
|
315
317
|
|
|
316
318
|
// For now, satisfy with single block or join blocks
|
|
@@ -327,11 +329,11 @@ function reconcileCellContent(cell, newText, options) {
|
|
|
327
329
|
formatHints
|
|
328
330
|
});
|
|
329
331
|
|
|
330
|
-
const runsOoxml = serializeToOoxml(patchedModel, baseBlock.pPr, formatHints, {
|
|
331
|
-
author,
|
|
332
|
-
generateRedlines,
|
|
333
|
-
revisionIdAllocator
|
|
334
|
-
});
|
|
332
|
+
const runsOoxml = serializeToOoxml(patchedModel, baseBlock.pPr, formatHints, {
|
|
333
|
+
author,
|
|
334
|
+
generateRedlines,
|
|
335
|
+
revisionIdAllocator
|
|
336
|
+
});
|
|
335
337
|
return runsOoxml;
|
|
336
338
|
}
|
|
337
339
|
|
|
@@ -343,7 +345,7 @@ function serializeCellBlocks(blocks) {
|
|
|
343
345
|
}).join('');
|
|
344
346
|
}
|
|
345
347
|
|
|
346
|
-
function buildTcXml(cell, content, _options) {
|
|
348
|
+
function buildTcXml(cell, content, _options) {
|
|
347
349
|
let tcPr = cell.tcPrXml;
|
|
348
350
|
|
|
349
351
|
// Ensure gridSpan is preserved
|