@adeu/core 1.28.0 → 1.29.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/dist/index.cjs CHANGED
@@ -1755,8 +1755,26 @@ ${header}`;
1755
1755
  const cell_start = current;
1756
1756
  current = this._map_blocks(cell, current);
1757
1757
  if (!this.clean_view && !this.original_view) {
1758
- const firstP = cell._element.getElementsByTagName("w:p")[0];
1759
- const paraId = firstP ? firstP.getAttribute("w14:paraId") : null;
1758
+ let firstP = cell._element.getElementsByTagName("w:p")[0];
1759
+ let paraId = firstP ? firstP.getAttribute("w14:paraId") : null;
1760
+ const is_empty = current === cell_start;
1761
+ if (!paraId && is_empty) {
1762
+ if (!firstP) {
1763
+ const xmlDoc = cell._element.ownerDocument;
1764
+ firstP = xmlDoc.createElement("w:p");
1765
+ cell._element.appendChild(firstP);
1766
+ }
1767
+ const allPs = Array.from(cell._element.ownerDocument.getElementsByTagName("w:p"));
1768
+ const index = allPs.indexOf(firstP);
1769
+ let hash = 2166136261;
1770
+ const str = `fallback-paraId-${index}`;
1771
+ for (let i = 0; i < str.length; i++) {
1772
+ hash ^= str.charCodeAt(i);
1773
+ hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
1774
+ }
1775
+ paraId = (hash >>> 0).toString(16).toUpperCase().padStart(8, "0");
1776
+ firstP.setAttribute("w14:paraId", paraId);
1777
+ }
1760
1778
  if (paraId && firstP) {
1761
1779
  const cellPara = new Paragraph(firstP, cell);
1762
1780
  this._add_virtual_text("", current, cellPara);
@@ -2929,6 +2947,10 @@ function _split_cross_paragraph_hunks(edits) {
2929
2947
  return out;
2930
2948
  }
2931
2949
  function generate_edits_via_paragraph_alignment(original_text, modified_text) {
2950
+ const orig_stripped = original_text.trimEnd();
2951
+ const orig_ws = original_text.slice(orig_stripped.length);
2952
+ const mod_stripped = modified_text.trimEnd();
2953
+ modified_text = mod_stripped + orig_ws;
2932
2954
  const orig_paragraphs = original_text.split("\n\n");
2933
2955
  const mod_paragraphs = modified_text.split("\n\n");
2934
2956
  const orig_offsets = [];
@@ -4714,10 +4736,21 @@ var RedlineEngine = class _RedlineEngine {
4714
4736
  parts_to_process.push(part._element);
4715
4737
  }
4716
4738
  }
4739
+ let accepted_insertions = 0;
4740
+ let accepted_deletions = 0;
4741
+ let accepted_formatting = 0;
4742
+ for (const root_element of parts_to_process) {
4743
+ accepted_insertions += findAllDescendants(root_element, "w:ins").length;
4744
+ accepted_deletions += findAllDescendants(root_element, "w:del").length;
4745
+ for (const tag of ["w:rPrChange", "w:pPrChange", "w:sectPrChange"]) {
4746
+ accepted_formatting += findAllDescendants(root_element, tag).length;
4747
+ }
4748
+ }
4749
+ let removed_comments = 0;
4717
4750
  for (const root_element of parts_to_process) {
4718
4751
  const insNodes = findAllDescendants(root_element, "w:ins");
4719
4752
  for (const ins of insNodes) {
4720
- this._clean_wrapping_comments(ins);
4753
+ removed_comments += this._clean_wrapping_comments(ins);
4721
4754
  const parent = ins.parentNode;
4722
4755
  if (!parent) continue;
4723
4756
  if (parent.tagName === "w:trPr") {
@@ -4761,8 +4794,8 @@ var RedlineEngine = class _RedlineEngine {
4761
4794
  if (has_content) {
4762
4795
  rPr.removeChild(delMark);
4763
4796
  } else {
4764
- this._clean_wrapping_comments(p);
4765
- this._delete_comments_in_element(p);
4797
+ removed_comments += this._clean_wrapping_comments(p);
4798
+ removed_comments += this._delete_comments_in_element(p);
4766
4799
  if (p.parentNode) {
4767
4800
  p.parentNode.removeChild(p);
4768
4801
  }
@@ -4772,8 +4805,8 @@ var RedlineEngine = class _RedlineEngine {
4772
4805
  }
4773
4806
  const delNodes = findAllDescendants(root_element, "w:del");
4774
4807
  for (const d of delNodes) {
4775
- this._clean_wrapping_comments(d);
4776
- this._delete_comments_in_element(d);
4808
+ removed_comments += this._clean_wrapping_comments(d);
4809
+ removed_comments += this._delete_comments_in_element(d);
4777
4810
  const parent = d.parentNode;
4778
4811
  if (parent) {
4779
4812
  if (parent.tagName === "w:trPr") {
@@ -4868,6 +4901,12 @@ var RedlineEngine = class _RedlineEngine {
4868
4901
  }
4869
4902
  }
4870
4903
  }
4904
+ return {
4905
+ accepted_insertions,
4906
+ accepted_deletions,
4907
+ accepted_formatting,
4908
+ removed_comments
4909
+ };
4871
4910
  }
4872
4911
  /**
4873
4912
  * Revert every tracked change, returning the document to the state it had
@@ -5524,7 +5563,10 @@ var RedlineEngine = class _RedlineEngine {
5524
5563
  }
5525
5564
  return null;
5526
5565
  }
5566
+ /** Returns how many comment BODIES were actually deleted (see below: only
5567
+ * our own are; foreign ones keep their body and lose only the anchor). */
5527
5568
  _clean_wrapping_comments(element) {
5569
+ let deleted = 0;
5528
5570
  let first_node = element;
5529
5571
  while (true) {
5530
5572
  const prev2 = getPreviousElement(first_node);
@@ -5592,6 +5634,7 @@ var RedlineEngine = class _RedlineEngine {
5592
5634
  const is_own = author !== null && author === this.author;
5593
5635
  if (is_own) {
5594
5636
  this.comments_manager.deleteComment(c_id);
5637
+ deleted++;
5595
5638
  }
5596
5639
  if (s.parentNode) s.parentNode.removeChild(s);
5597
5640
  for (const e of ends_to_remove) {
@@ -5609,13 +5652,17 @@ var RedlineEngine = class _RedlineEngine {
5609
5652
  }
5610
5653
  }
5611
5654
  }
5655
+ return deleted;
5612
5656
  }
5657
+ /** Returns how many comment bodies were deleted. */
5613
5658
  _delete_comments_in_element(element) {
5659
+ let deleted = 0;
5614
5660
  const refs = findAllDescendants(element, "w:commentReference");
5615
5661
  for (const ref of refs) {
5616
5662
  const c_id = ref.getAttribute("w:id");
5617
5663
  if (c_id) {
5618
5664
  this.comments_manager.deleteComment(c_id);
5665
+ deleted++;
5619
5666
  for (const tag of ["w:commentRangeStart", "w:commentRangeEnd"]) {
5620
5667
  const nodes = findAllDescendants(this.doc.element, tag);
5621
5668
  for (const node of nodes) {
@@ -5626,6 +5673,7 @@ var RedlineEngine = class _RedlineEngine {
5626
5673
  }
5627
5674
  }
5628
5675
  }
5676
+ return deleted;
5629
5677
  }
5630
5678
  validate_edits(edits, index_offset = 0) {
5631
5679
  const errors = [];
@@ -6142,6 +6190,7 @@ var RedlineEngine = class _RedlineEngine {
6142
6190
  );
6143
6191
  reports_by_input[i] = {
6144
6192
  status: "failed",
6193
+ type: edit.type || "modify",
6145
6194
  target_text: truncate_middle(edit.target_text || "", REPORT_ECHO_CAP),
6146
6195
  new_text: truncate_middle(_RedlineEngine._report_new_text(edit), REPORT_ECHO_CAP),
6147
6196
  warning,
@@ -6157,6 +6206,7 @@ var RedlineEngine = class _RedlineEngine {
6157
6206
  const previews = this._build_edit_context_previews(edit);
6158
6207
  reports_by_input[i] = {
6159
6208
  status: "applied",
6209
+ type: edit.type || "modify",
6160
6210
  target_text: truncate_middle(edit.target_text || "", REPORT_ECHO_CAP),
6161
6211
  new_text: truncate_middle(_RedlineEngine._report_new_text(edit), REPORT_ECHO_CAP),
6162
6212
  warning: null,
@@ -6178,6 +6228,7 @@ var RedlineEngine = class _RedlineEngine {
6178
6228
  );
6179
6229
  reports_by_input[i] = {
6180
6230
  status: "failed",
6231
+ type: edit.type || "modify",
6181
6232
  target_text: truncate_middle(edit.target_text || "", REPORT_ECHO_CAP),
6182
6233
  new_text: truncate_middle(_RedlineEngine._report_new_text(edit), REPORT_ECHO_CAP),
6183
6234
  warning,
@@ -6196,6 +6247,7 @@ var RedlineEngine = class _RedlineEngine {
6196
6247
  if (report.status === "applied") {
6197
6248
  reports_by_input[i] = {
6198
6249
  status: "failed",
6250
+ type: report.type || "modify",
6199
6251
  target_text: report.target_text,
6200
6252
  new_text: report.new_text,
6201
6253
  warning: null,
@@ -6266,6 +6318,7 @@ var RedlineEngine = class _RedlineEngine {
6266
6318
  }
6267
6319
  edits_reports.push({
6268
6320
  status: success ? "applied" : "failed",
6321
+ type: edit.type || "modify",
6269
6322
  target_text: truncate_middle(edit.target_text || "", REPORT_ECHO_CAP),
6270
6323
  new_text: truncate_middle(_RedlineEngine._report_new_text(edit), REPORT_ECHO_CAP),
6271
6324
  warning,
@@ -6343,9 +6396,52 @@ var RedlineEngine = class _RedlineEngine {
6343
6396
  resolved_mapper = this.clean_mapper;
6344
6397
  }
6345
6398
  if (matches.length > 0) {
6346
- edit._resolved_start_idx = matches[0][0];
6347
- edit._active_mapper_ref = resolved_mapper;
6348
- resolved_edits.push([edit, null]);
6399
+ const match_mode = edit.match_mode || "strict";
6400
+ const unique_matches = [];
6401
+ const seen_trs = /* @__PURE__ */ new Set();
6402
+ for (const match of matches) {
6403
+ const start_idx = match[0];
6404
+ const [anchor_run, anchor_para] = resolved_mapper.get_insertion_anchor(start_idx, false);
6405
+ let target_element = null;
6406
+ if (anchor_run) target_element = anchor_run._element;
6407
+ else if (anchor_para) target_element = anchor_para._element;
6408
+ let tr = target_element;
6409
+ while (tr && tr.tagName !== "w:tr") tr = tr.parentNode;
6410
+ if (tr) {
6411
+ if (!seen_trs.has(tr)) {
6412
+ seen_trs.add(tr);
6413
+ unique_matches.push(match);
6414
+ }
6415
+ }
6416
+ }
6417
+ if (unique_matches.length > 0) {
6418
+ let matches_to_apply = unique_matches;
6419
+ if (match_mode === "strict" || match_mode === "first") {
6420
+ matches_to_apply = unique_matches.slice(0, 1);
6421
+ }
6422
+ if (match_mode === "all" || matches_to_apply.length > 1) {
6423
+ for (const m of matches_to_apply) {
6424
+ const sub_edit = {
6425
+ ...edit,
6426
+ _resolved_start_idx: m[0],
6427
+ _active_mapper_ref: resolved_mapper,
6428
+ _parent_edit_ref: edit
6429
+ };
6430
+ resolved_edits.push([sub_edit, null]);
6431
+ }
6432
+ } else {
6433
+ edit._resolved_start_idx = matches_to_apply[0][0];
6434
+ edit._active_mapper_ref = resolved_mapper;
6435
+ resolved_edits.push([edit, null]);
6436
+ }
6437
+ } else {
6438
+ skipped++;
6439
+ edit._applied_status = false;
6440
+ const target_snippet = (edit.target_text || "").trim().substring(0, 40);
6441
+ const msg = `- Failed to locate row target: '${target_snippet}...'`;
6442
+ this.skipped_details.push(msg);
6443
+ edit._error_msg = msg;
6444
+ }
6349
6445
  } else {
6350
6446
  skipped++;
6351
6447
  edit._applied_status = false;
@@ -6651,8 +6747,15 @@ var RedlineEngine = class _RedlineEngine {
6651
6747
  let skipped = 0;
6652
6748
  let already_resolved = 0;
6653
6749
  const resolved_history = /* @__PURE__ */ new Map();
6654
- for (let pos = 0; pos < actions.length; pos++) {
6655
- const action = actions[pos];
6750
+ const sortedActions = actions.map((action, pos) => ({ action, pos })).sort((a, b) => {
6751
+ const aPri = a.action.type === "reply" ? 0 : 1;
6752
+ const bPri = b.action.type === "reply" ? 0 : 1;
6753
+ if (aPri !== bPri) {
6754
+ return aPri - bPri;
6755
+ }
6756
+ return a.pos - b.pos;
6757
+ });
6758
+ for (const { action, pos } of sortedActions) {
6656
6759
  const type = action.type;
6657
6760
  if (type === "reply") {
6658
6761
  const cid = action.target_id.replace("Com:", "");
@@ -8800,8 +8903,25 @@ function extract_table(table, comments_map, cleanView, cursor, paragraph_offsets
8800
8903
  paragraph_offsets
8801
8904
  );
8802
8905
  if (!cleanView) {
8803
- const firstP = cell._element.getElementsByTagName("w:p")[0];
8804
- const paraId = firstP ? firstP.getAttribute("w14:paraId") : null;
8906
+ let firstP = cell._element.getElementsByTagName("w:p")[0];
8907
+ let paraId = firstP ? firstP.getAttribute("w14:paraId") : null;
8908
+ if (!paraId && (!cell_content || cell_content.trim() === "")) {
8909
+ if (!firstP) {
8910
+ const xmlDoc = cell._element.ownerDocument;
8911
+ firstP = xmlDoc.createElement("w:p");
8912
+ cell._element.appendChild(firstP);
8913
+ }
8914
+ const allPs = Array.from(cell._element.ownerDocument.getElementsByTagName("w:p"));
8915
+ const index = allPs.indexOf(firstP);
8916
+ let hash = 2166136261;
8917
+ const str = `fallback-paraId-${index}`;
8918
+ for (let i = 0; i < str.length; i++) {
8919
+ hash ^= str.charCodeAt(i);
8920
+ hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
8921
+ }
8922
+ paraId = (hash >>> 0).toString(16).toUpperCase().padStart(8, "0");
8923
+ firstP.setAttribute("w14:paraId", paraId);
8924
+ }
8805
8925
  if (paraId) {
8806
8926
  const space_pad = cell_content ? " " : "";
8807
8927
  const anchor = `${space_pad}{#cell:${paraId}}`;
@@ -9760,7 +9880,7 @@ async function finalize_document(doc, options) {
9760
9880
  report.tracked_changes_found = total;
9761
9881
  if (total > 0 && !options.accept_all) {
9762
9882
  report.status = "blocked";
9763
- report.blocked_reason = `Document contains ${total} unresolved tracked changes (${counts[0]} insertions, ${counts[1]} deletions, ${counts[2]} formatting). Review in Word first, or set accept_all=true.`;
9883
+ report.blocked_reason = `Document contains ${total} unresolved tracked changes (${counts[0]} insertions, ${counts[1]} deletions, ${counts[2]} formatting). Review in Word first, set accept_all=true, or set sanitize_mode='keep-markup'.`;
9764
9884
  return { reportText: report.render() };
9765
9885
  }
9766
9886
  if (total > 0) {