@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.d.cts CHANGED
@@ -308,7 +308,12 @@ declare class RedlineEngine {
308
308
  private _build_edit_context_previews;
309
309
  private _scan_existing_ids;
310
310
  private _get_heading_path_and_page;
311
- accept_all_revisions(): void;
311
+ accept_all_revisions(): {
312
+ accepted_insertions: number;
313
+ accepted_deletions: number;
314
+ accepted_formatting: number;
315
+ removed_comments: number;
316
+ };
312
317
  /**
313
318
  * Revert every tracked change, returning the document to the state it had
314
319
  * before any revision was proposed. The exact inverse of
@@ -449,7 +454,10 @@ declare class RedlineEngine {
449
454
  * actions, so it can be stale mid-batch. Returns null if not found.
450
455
  */
451
456
  private _get_comment_author;
457
+ /** Returns how many comment BODIES were actually deleted (see below: only
458
+ * our own are; foreign ones keep their body and lose only the anchor). */
452
459
  private _clean_wrapping_comments;
460
+ /** Returns how many comment bodies were deleted. */
453
461
  private _delete_comments_in_element;
454
462
  validate_edits(edits: any[], index_offset?: number): string[];
455
463
  /**
package/dist/index.d.ts CHANGED
@@ -308,7 +308,12 @@ declare class RedlineEngine {
308
308
  private _build_edit_context_previews;
309
309
  private _scan_existing_ids;
310
310
  private _get_heading_path_and_page;
311
- accept_all_revisions(): void;
311
+ accept_all_revisions(): {
312
+ accepted_insertions: number;
313
+ accepted_deletions: number;
314
+ accepted_formatting: number;
315
+ removed_comments: number;
316
+ };
312
317
  /**
313
318
  * Revert every tracked change, returning the document to the state it had
314
319
  * before any revision was proposed. The exact inverse of
@@ -449,7 +454,10 @@ declare class RedlineEngine {
449
454
  * actions, so it can be stale mid-batch. Returns null if not found.
450
455
  */
451
456
  private _get_comment_author;
457
+ /** Returns how many comment BODIES were actually deleted (see below: only
458
+ * our own are; foreign ones keep their body and lose only the anchor). */
452
459
  private _clean_wrapping_comments;
460
+ /** Returns how many comment bodies were deleted. */
453
461
  private _delete_comments_in_element;
454
462
  validate_edits(edits: any[], index_offset?: number): string[];
455
463
  /**
package/dist/index.js CHANGED
@@ -1696,8 +1696,26 @@ ${header}`;
1696
1696
  const cell_start = current;
1697
1697
  current = this._map_blocks(cell, current);
1698
1698
  if (!this.clean_view && !this.original_view) {
1699
- const firstP = cell._element.getElementsByTagName("w:p")[0];
1700
- const paraId = firstP ? firstP.getAttribute("w14:paraId") : null;
1699
+ let firstP = cell._element.getElementsByTagName("w:p")[0];
1700
+ let paraId = firstP ? firstP.getAttribute("w14:paraId") : null;
1701
+ const is_empty = current === cell_start;
1702
+ if (!paraId && is_empty) {
1703
+ if (!firstP) {
1704
+ const xmlDoc = cell._element.ownerDocument;
1705
+ firstP = xmlDoc.createElement("w:p");
1706
+ cell._element.appendChild(firstP);
1707
+ }
1708
+ const allPs = Array.from(cell._element.ownerDocument.getElementsByTagName("w:p"));
1709
+ const index = allPs.indexOf(firstP);
1710
+ let hash = 2166136261;
1711
+ const str = `fallback-paraId-${index}`;
1712
+ for (let i = 0; i < str.length; i++) {
1713
+ hash ^= str.charCodeAt(i);
1714
+ hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
1715
+ }
1716
+ paraId = (hash >>> 0).toString(16).toUpperCase().padStart(8, "0");
1717
+ firstP.setAttribute("w14:paraId", paraId);
1718
+ }
1701
1719
  if (paraId && firstP) {
1702
1720
  const cellPara = new Paragraph(firstP, cell);
1703
1721
  this._add_virtual_text("", current, cellPara);
@@ -2870,6 +2888,10 @@ function _split_cross_paragraph_hunks(edits) {
2870
2888
  return out;
2871
2889
  }
2872
2890
  function generate_edits_via_paragraph_alignment(original_text, modified_text) {
2891
+ const orig_stripped = original_text.trimEnd();
2892
+ const orig_ws = original_text.slice(orig_stripped.length);
2893
+ const mod_stripped = modified_text.trimEnd();
2894
+ modified_text = mod_stripped + orig_ws;
2873
2895
  const orig_paragraphs = original_text.split("\n\n");
2874
2896
  const mod_paragraphs = modified_text.split("\n\n");
2875
2897
  const orig_offsets = [];
@@ -4655,10 +4677,21 @@ var RedlineEngine = class _RedlineEngine {
4655
4677
  parts_to_process.push(part._element);
4656
4678
  }
4657
4679
  }
4680
+ let accepted_insertions = 0;
4681
+ let accepted_deletions = 0;
4682
+ let accepted_formatting = 0;
4683
+ for (const root_element of parts_to_process) {
4684
+ accepted_insertions += findAllDescendants(root_element, "w:ins").length;
4685
+ accepted_deletions += findAllDescendants(root_element, "w:del").length;
4686
+ for (const tag of ["w:rPrChange", "w:pPrChange", "w:sectPrChange"]) {
4687
+ accepted_formatting += findAllDescendants(root_element, tag).length;
4688
+ }
4689
+ }
4690
+ let removed_comments = 0;
4658
4691
  for (const root_element of parts_to_process) {
4659
4692
  const insNodes = findAllDescendants(root_element, "w:ins");
4660
4693
  for (const ins of insNodes) {
4661
- this._clean_wrapping_comments(ins);
4694
+ removed_comments += this._clean_wrapping_comments(ins);
4662
4695
  const parent = ins.parentNode;
4663
4696
  if (!parent) continue;
4664
4697
  if (parent.tagName === "w:trPr") {
@@ -4702,8 +4735,8 @@ var RedlineEngine = class _RedlineEngine {
4702
4735
  if (has_content) {
4703
4736
  rPr.removeChild(delMark);
4704
4737
  } else {
4705
- this._clean_wrapping_comments(p);
4706
- this._delete_comments_in_element(p);
4738
+ removed_comments += this._clean_wrapping_comments(p);
4739
+ removed_comments += this._delete_comments_in_element(p);
4707
4740
  if (p.parentNode) {
4708
4741
  p.parentNode.removeChild(p);
4709
4742
  }
@@ -4713,8 +4746,8 @@ var RedlineEngine = class _RedlineEngine {
4713
4746
  }
4714
4747
  const delNodes = findAllDescendants(root_element, "w:del");
4715
4748
  for (const d of delNodes) {
4716
- this._clean_wrapping_comments(d);
4717
- this._delete_comments_in_element(d);
4749
+ removed_comments += this._clean_wrapping_comments(d);
4750
+ removed_comments += this._delete_comments_in_element(d);
4718
4751
  const parent = d.parentNode;
4719
4752
  if (parent) {
4720
4753
  if (parent.tagName === "w:trPr") {
@@ -4809,6 +4842,12 @@ var RedlineEngine = class _RedlineEngine {
4809
4842
  }
4810
4843
  }
4811
4844
  }
4845
+ return {
4846
+ accepted_insertions,
4847
+ accepted_deletions,
4848
+ accepted_formatting,
4849
+ removed_comments
4850
+ };
4812
4851
  }
4813
4852
  /**
4814
4853
  * Revert every tracked change, returning the document to the state it had
@@ -5465,7 +5504,10 @@ var RedlineEngine = class _RedlineEngine {
5465
5504
  }
5466
5505
  return null;
5467
5506
  }
5507
+ /** Returns how many comment BODIES were actually deleted (see below: only
5508
+ * our own are; foreign ones keep their body and lose only the anchor). */
5468
5509
  _clean_wrapping_comments(element) {
5510
+ let deleted = 0;
5469
5511
  let first_node = element;
5470
5512
  while (true) {
5471
5513
  const prev2 = getPreviousElement(first_node);
@@ -5533,6 +5575,7 @@ var RedlineEngine = class _RedlineEngine {
5533
5575
  const is_own = author !== null && author === this.author;
5534
5576
  if (is_own) {
5535
5577
  this.comments_manager.deleteComment(c_id);
5578
+ deleted++;
5536
5579
  }
5537
5580
  if (s.parentNode) s.parentNode.removeChild(s);
5538
5581
  for (const e of ends_to_remove) {
@@ -5550,13 +5593,17 @@ var RedlineEngine = class _RedlineEngine {
5550
5593
  }
5551
5594
  }
5552
5595
  }
5596
+ return deleted;
5553
5597
  }
5598
+ /** Returns how many comment bodies were deleted. */
5554
5599
  _delete_comments_in_element(element) {
5600
+ let deleted = 0;
5555
5601
  const refs = findAllDescendants(element, "w:commentReference");
5556
5602
  for (const ref of refs) {
5557
5603
  const c_id = ref.getAttribute("w:id");
5558
5604
  if (c_id) {
5559
5605
  this.comments_manager.deleteComment(c_id);
5606
+ deleted++;
5560
5607
  for (const tag of ["w:commentRangeStart", "w:commentRangeEnd"]) {
5561
5608
  const nodes = findAllDescendants(this.doc.element, tag);
5562
5609
  for (const node of nodes) {
@@ -5567,6 +5614,7 @@ var RedlineEngine = class _RedlineEngine {
5567
5614
  }
5568
5615
  }
5569
5616
  }
5617
+ return deleted;
5570
5618
  }
5571
5619
  validate_edits(edits, index_offset = 0) {
5572
5620
  const errors = [];
@@ -6083,6 +6131,7 @@ var RedlineEngine = class _RedlineEngine {
6083
6131
  );
6084
6132
  reports_by_input[i] = {
6085
6133
  status: "failed",
6134
+ type: edit.type || "modify",
6086
6135
  target_text: truncate_middle(edit.target_text || "", REPORT_ECHO_CAP),
6087
6136
  new_text: truncate_middle(_RedlineEngine._report_new_text(edit), REPORT_ECHO_CAP),
6088
6137
  warning,
@@ -6098,6 +6147,7 @@ var RedlineEngine = class _RedlineEngine {
6098
6147
  const previews = this._build_edit_context_previews(edit);
6099
6148
  reports_by_input[i] = {
6100
6149
  status: "applied",
6150
+ type: edit.type || "modify",
6101
6151
  target_text: truncate_middle(edit.target_text || "", REPORT_ECHO_CAP),
6102
6152
  new_text: truncate_middle(_RedlineEngine._report_new_text(edit), REPORT_ECHO_CAP),
6103
6153
  warning: null,
@@ -6119,6 +6169,7 @@ var RedlineEngine = class _RedlineEngine {
6119
6169
  );
6120
6170
  reports_by_input[i] = {
6121
6171
  status: "failed",
6172
+ type: edit.type || "modify",
6122
6173
  target_text: truncate_middle(edit.target_text || "", REPORT_ECHO_CAP),
6123
6174
  new_text: truncate_middle(_RedlineEngine._report_new_text(edit), REPORT_ECHO_CAP),
6124
6175
  warning,
@@ -6137,6 +6188,7 @@ var RedlineEngine = class _RedlineEngine {
6137
6188
  if (report.status === "applied") {
6138
6189
  reports_by_input[i] = {
6139
6190
  status: "failed",
6191
+ type: report.type || "modify",
6140
6192
  target_text: report.target_text,
6141
6193
  new_text: report.new_text,
6142
6194
  warning: null,
@@ -6207,6 +6259,7 @@ var RedlineEngine = class _RedlineEngine {
6207
6259
  }
6208
6260
  edits_reports.push({
6209
6261
  status: success ? "applied" : "failed",
6262
+ type: edit.type || "modify",
6210
6263
  target_text: truncate_middle(edit.target_text || "", REPORT_ECHO_CAP),
6211
6264
  new_text: truncate_middle(_RedlineEngine._report_new_text(edit), REPORT_ECHO_CAP),
6212
6265
  warning,
@@ -6284,9 +6337,52 @@ var RedlineEngine = class _RedlineEngine {
6284
6337
  resolved_mapper = this.clean_mapper;
6285
6338
  }
6286
6339
  if (matches.length > 0) {
6287
- edit._resolved_start_idx = matches[0][0];
6288
- edit._active_mapper_ref = resolved_mapper;
6289
- resolved_edits.push([edit, null]);
6340
+ const match_mode = edit.match_mode || "strict";
6341
+ const unique_matches = [];
6342
+ const seen_trs = /* @__PURE__ */ new Set();
6343
+ for (const match of matches) {
6344
+ const start_idx = match[0];
6345
+ const [anchor_run, anchor_para] = resolved_mapper.get_insertion_anchor(start_idx, false);
6346
+ let target_element = null;
6347
+ if (anchor_run) target_element = anchor_run._element;
6348
+ else if (anchor_para) target_element = anchor_para._element;
6349
+ let tr = target_element;
6350
+ while (tr && tr.tagName !== "w:tr") tr = tr.parentNode;
6351
+ if (tr) {
6352
+ if (!seen_trs.has(tr)) {
6353
+ seen_trs.add(tr);
6354
+ unique_matches.push(match);
6355
+ }
6356
+ }
6357
+ }
6358
+ if (unique_matches.length > 0) {
6359
+ let matches_to_apply = unique_matches;
6360
+ if (match_mode === "strict" || match_mode === "first") {
6361
+ matches_to_apply = unique_matches.slice(0, 1);
6362
+ }
6363
+ if (match_mode === "all" || matches_to_apply.length > 1) {
6364
+ for (const m of matches_to_apply) {
6365
+ const sub_edit = {
6366
+ ...edit,
6367
+ _resolved_start_idx: m[0],
6368
+ _active_mapper_ref: resolved_mapper,
6369
+ _parent_edit_ref: edit
6370
+ };
6371
+ resolved_edits.push([sub_edit, null]);
6372
+ }
6373
+ } else {
6374
+ edit._resolved_start_idx = matches_to_apply[0][0];
6375
+ edit._active_mapper_ref = resolved_mapper;
6376
+ resolved_edits.push([edit, null]);
6377
+ }
6378
+ } else {
6379
+ skipped++;
6380
+ edit._applied_status = false;
6381
+ const target_snippet = (edit.target_text || "").trim().substring(0, 40);
6382
+ const msg = `- Failed to locate row target: '${target_snippet}...'`;
6383
+ this.skipped_details.push(msg);
6384
+ edit._error_msg = msg;
6385
+ }
6290
6386
  } else {
6291
6387
  skipped++;
6292
6388
  edit._applied_status = false;
@@ -6592,8 +6688,15 @@ var RedlineEngine = class _RedlineEngine {
6592
6688
  let skipped = 0;
6593
6689
  let already_resolved = 0;
6594
6690
  const resolved_history = /* @__PURE__ */ new Map();
6595
- for (let pos = 0; pos < actions.length; pos++) {
6596
- const action = actions[pos];
6691
+ const sortedActions = actions.map((action, pos) => ({ action, pos })).sort((a, b) => {
6692
+ const aPri = a.action.type === "reply" ? 0 : 1;
6693
+ const bPri = b.action.type === "reply" ? 0 : 1;
6694
+ if (aPri !== bPri) {
6695
+ return aPri - bPri;
6696
+ }
6697
+ return a.pos - b.pos;
6698
+ });
6699
+ for (const { action, pos } of sortedActions) {
6597
6700
  const type = action.type;
6598
6701
  if (type === "reply") {
6599
6702
  const cid = action.target_id.replace("Com:", "");
@@ -8741,8 +8844,25 @@ function extract_table(table, comments_map, cleanView, cursor, paragraph_offsets
8741
8844
  paragraph_offsets
8742
8845
  );
8743
8846
  if (!cleanView) {
8744
- const firstP = cell._element.getElementsByTagName("w:p")[0];
8745
- const paraId = firstP ? firstP.getAttribute("w14:paraId") : null;
8847
+ let firstP = cell._element.getElementsByTagName("w:p")[0];
8848
+ let paraId = firstP ? firstP.getAttribute("w14:paraId") : null;
8849
+ if (!paraId && (!cell_content || cell_content.trim() === "")) {
8850
+ if (!firstP) {
8851
+ const xmlDoc = cell._element.ownerDocument;
8852
+ firstP = xmlDoc.createElement("w:p");
8853
+ cell._element.appendChild(firstP);
8854
+ }
8855
+ const allPs = Array.from(cell._element.ownerDocument.getElementsByTagName("w:p"));
8856
+ const index = allPs.indexOf(firstP);
8857
+ let hash = 2166136261;
8858
+ const str = `fallback-paraId-${index}`;
8859
+ for (let i = 0; i < str.length; i++) {
8860
+ hash ^= str.charCodeAt(i);
8861
+ hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
8862
+ }
8863
+ paraId = (hash >>> 0).toString(16).toUpperCase().padStart(8, "0");
8864
+ firstP.setAttribute("w14:paraId", paraId);
8865
+ }
8746
8866
  if (paraId) {
8747
8867
  const space_pad = cell_content ? " " : "";
8748
8868
  const anchor = `${space_pad}{#cell:${paraId}}`;
@@ -9701,7 +9821,7 @@ async function finalize_document(doc, options) {
9701
9821
  report.tracked_changes_found = total;
9702
9822
  if (total > 0 && !options.accept_all) {
9703
9823
  report.status = "blocked";
9704
- 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.`;
9824
+ 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'.`;
9705
9825
  return { reportText: report.render() };
9706
9826
  }
9707
9827
  if (total > 0) {