@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.
Files changed (33) hide show
  1. package/CHANGELOG.md +75 -1
  2. package/README.md +28 -13
  3. package/core/list-targeting.js +12 -10
  4. package/dist/docx-redline-js.esm.js +837 -549
  5. package/dist/docx-redline-js.esm.js.map +4 -4
  6. package/dist/docx-redline-js.esm.min.js +93 -90
  7. package/dist/docx-redline-js.esm.min.js.map +4 -4
  8. package/dist/docx-redline.bundle.cjs +837 -549
  9. package/dist/docx-redline.bundle.cjs.map +4 -4
  10. package/dist/docx-redline.bundle.js +837 -549
  11. package/dist/docx-redline.bundle.js.map +4 -4
  12. package/docs/AGENT_KNOWLEDGE_BASE.md +4 -1
  13. package/docs/schemas/document-operations.schema.json +168 -168
  14. package/engine/oxml-engine.js +215 -195
  15. package/engine/reconstruction-mode.js +183 -183
  16. package/index.d.ts +4 -0
  17. package/index.js +36 -1
  18. package/node/cli.js +2 -1
  19. package/orchestration/list-structural-fallback.js +530 -518
  20. package/package.json +1 -1
  21. package/pipeline/list-generation.js +203 -168
  22. package/pipeline/serialization.js +111 -94
  23. package/services/batch-operation-orchestrator.js +6 -0
  24. package/services/document-inspection.js +10 -7
  25. package/services/document-operation-applier.js +2 -0
  26. package/services/document-operation-contract.js +553 -537
  27. package/services/document-operation-mutations.js +1140 -1011
  28. package/services/numbering-helpers.js +108 -0
  29. package/services/operation-batch-compiler.js +440 -436
  30. package/services/operation-heuristics.js +197 -173
  31. package/services/revision-comment-management.js +601 -594
  32. package/services/standalone-operation-runner.d.ts +429 -427
  33. 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
- const tableInsertMeta = generateRedlines && trackAsBlock ? createRevisionMetadata(author, revisionIdAllocator) : null;
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 && !trackAsBlock ? RunKind.INSERTION : RunKind.TEXT,
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 runsOoxml = serializeToOoxml(runModel, null, formatHints, {
77
- author,
78
- generateRedlines,
79
- revisionIdAllocator
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
- rowsXml += `<w:tr>${trPr}${cellsXml}</w:tr>`;
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
- // Build the table
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