@ansonlai/docx-redline-js 0.5.2 → 0.5.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.
@@ -6,6 +6,26 @@ import {
6
6
  } from './types.js';
7
7
  import { isWordElement } from './word-xml.js';
8
8
 
9
+ const REVISION_HISTORY_ELEMENTS = new Set([
10
+ 'ins', 'del', 'moveFrom', 'moveTo', 'pPrChange', 'rPrChange',
11
+ 'tblPrChange', 'trPrChange', 'tcPrChange', 'sectPrChange'
12
+ ]);
13
+
14
+ /**
15
+ * Clones effective paragraph/run properties without copying tracked history
16
+ * into a newly created paragraph or run.
17
+ */
18
+ export function clonePropertiesWithoutRevisionHistory(root) {
19
+ if (!root) return null;
20
+ const clone = root.cloneNode(true);
21
+ const candidates = [clone, ...Array.from(clone.getElementsByTagName?.('*') || [])];
22
+ for (const node of candidates.reverse()) {
23
+ if (!REVISION_HISTORY_ELEMENTS.has(String(node.localName || node.nodeName || '').replace(/^.*:/, ''))) continue;
24
+ node.parentNode?.removeChild(node);
25
+ }
26
+ return clone;
27
+ }
28
+
9
29
  /**
10
30
  * Assigns fresh document-scoped IDs to w:rPrChange elements in a cloned
11
31
  * run-properties subtree. This preserves formatting-revision metadata while
@@ -32,6 +52,7 @@ export function refreshRunPropertyChangeIds(root, allocator = null) {
32
52
  } else {
33
53
  node.setAttribute('w:id', nextId);
34
54
  }
55
+ resolvedAllocator._receiptCollector?.recordRevision(Number(nextId), 'rPrChange');
35
56
  }
36
57
 
37
58
  return root;
@@ -0,0 +1,23 @@
1
+ function issueKey(issue) {
2
+ return `${issue?.source || ''}\u001f${issue?.severity || ''}\u001f${issue?.code || ''}\u001f${issue?.message || ''}`;
3
+ }
4
+
5
+ /** Subtracts baseline validation issues as a multiset, preserving duplicates. */
6
+ export function subtractValidationIssueMultiset(outputIssues = [], baselineIssues = []) {
7
+ const remaining = new Map();
8
+ for (const issue of baselineIssues || []) {
9
+ const key = issueKey(issue);
10
+ remaining.set(key, (remaining.get(key) || 0) + 1);
11
+ }
12
+ return (outputIssues || []).filter(issue => {
13
+ const key = issueKey(issue);
14
+ const count = remaining.get(key) || 0;
15
+ if (count === 0) return true;
16
+ remaining.set(key, count - 1);
17
+ return false;
18
+ });
19
+ }
20
+
21
+ export function validationErrors(issues = []) {
22
+ return (issues || []).filter(issue => issue?.severity === 'error');
23
+ }