@adeu/core 1.6.2 → 1.6.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/dist/index.cjs.map +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +38 -38
- package/src/comments.test.ts +37 -37
- package/src/comments.ts +450 -450
- package/src/diff.test.ts +61 -61
- package/src/diff.ts +250 -250
- package/src/docx/bridge.ts +188 -188
- package/src/docx/dom.ts +53 -53
- package/src/docx/primitives.ts +64 -64
- package/src/domain.ts +10 -10
- package/src/engine.atomic.test.ts +57 -57
- package/src/engine.batch.test.ts +92 -92
- package/src/engine.safety.test.ts +41 -41
- package/src/engine.tables.test.ts +165 -165
- package/src/engine.ts +734 -734
- package/src/index.test.ts +7 -7
- package/src/index.ts +13 -13
- package/src/ingest.test.ts +43 -43
- package/src/ingest.ts +399 -399
- package/src/mapper.test.ts +65 -65
- package/src/mapper.ts +834 -834
- package/src/markup.test.ts +149 -149
- package/src/markup.ts +322 -322
- package/src/models.ts +50 -50
- package/src/outline.ts +376 -376
- package/src/pagination.ts +238 -238
- package/src/test-utils.ts +141 -141
- package/src/utils/docx.ts +477 -477
- package/tsconfig.json +21 -21
- package/tsup.config.ts +9 -9
- package/vitest.config.ts +11 -11
|
@@ -1,58 +1,58 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { createTestDocument, addParagraph } from './test-utils.js';
|
|
3
|
-
import { DocumentObject } from './docx/bridge.js';
|
|
4
|
-
import { extractTextFromBuffer } from './ingest.js';
|
|
5
|
-
import { RedlineEngine } from './engine.js';
|
|
6
|
-
import { ModifyText, AcceptChange } from './models.js';
|
|
7
|
-
|
|
8
|
-
describe('Atomic Batch Pipeline (Node.js Port)', () => {
|
|
9
|
-
it('prevents cascading misanchor when accepting changes shifts indices', async () => {
|
|
10
|
-
// 1. Setup initial doc
|
|
11
|
-
const doc = await createTestDocument();
|
|
12
|
-
addParagraph(doc, "First paragraph.");
|
|
13
|
-
addParagraph(doc, "Second paragraph.");
|
|
14
|
-
addParagraph(doc, "Third paragraph.");
|
|
15
|
-
|
|
16
|
-
// 2. Make an initial tracked change (Simulating Round 1)
|
|
17
|
-
const engine = new RedlineEngine(doc, "Round1");
|
|
18
|
-
engine.apply_edits([{ type: 'modify', target_text: "First", new_text: "1st" } as ModifyText]);
|
|
19
|
-
|
|
20
|
-
const midBuf = await doc.save();
|
|
21
|
-
|
|
22
|
-
// Verify intermediate state (Round 1)
|
|
23
|
-
const midText = await extractTextFromBuffer(midBuf);
|
|
24
|
-
expect(midText).toContain("{--First--}");
|
|
25
|
-
expect(midText).toContain("{++1st++}");
|
|
26
|
-
|
|
27
|
-
// Extract dynamically generated Change IDs for the Accept action
|
|
28
|
-
const matches = Array.from(midText.matchAll(/\[Chg:(\d+)(?:\s+\w+)?\]/g));
|
|
29
|
-
const chgIds = new Set(matches.map(m => m[1]));
|
|
30
|
-
expect(chgIds.size).toBeGreaterThan(0);
|
|
31
|
-
|
|
32
|
-
// 3. Execute the Atomic Batch (Simulating Round 2)
|
|
33
|
-
const midDoc = await DocumentObject.load(midBuf);
|
|
34
|
-
const engine2 = new RedlineEngine(midDoc, "Round2");
|
|
35
|
-
|
|
36
|
-
const actions = Array.from(chgIds).map(id => ({ type: 'accept', target_id: `Chg:${id}` } as AcceptChange));
|
|
37
|
-
const edits = [{ type: 'modify', target_text: "Third", new_text: "3rd" } as ModifyText];
|
|
38
|
-
|
|
39
|
-
const changes = [...actions, ...edits];
|
|
40
|
-
const stats = engine2.process_batch(changes);
|
|
41
|
-
|
|
42
|
-
// 4. Assertions on the Tool Execution
|
|
43
|
-
expect(stats.actions_applied).toBe(actions.length);
|
|
44
|
-
expect(stats.edits_applied).toBe(1);
|
|
45
|
-
|
|
46
|
-
// 5. Assertions on the Final Document State
|
|
47
|
-
const finalBuf = await midDoc.save();
|
|
48
|
-
const final_text = await extractTextFromBuffer(finalBuf);
|
|
49
|
-
|
|
50
|
-
// The first paragraph should be cleanly accepted
|
|
51
|
-
expect(final_text).toContain("1st paragraph.");
|
|
52
|
-
expect(final_text).not.toContain("{--First--}");
|
|
53
|
-
|
|
54
|
-
// The third paragraph should have the new tracked change anchored perfectly
|
|
55
|
-
expect(final_text).toContain("{--Third--}");
|
|
56
|
-
expect(final_text).toContain("{++3rd++}");
|
|
57
|
-
});
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { createTestDocument, addParagraph } from './test-utils.js';
|
|
3
|
+
import { DocumentObject } from './docx/bridge.js';
|
|
4
|
+
import { extractTextFromBuffer } from './ingest.js';
|
|
5
|
+
import { RedlineEngine } from './engine.js';
|
|
6
|
+
import { ModifyText, AcceptChange } from './models.js';
|
|
7
|
+
|
|
8
|
+
describe('Atomic Batch Pipeline (Node.js Port)', () => {
|
|
9
|
+
it('prevents cascading misanchor when accepting changes shifts indices', async () => {
|
|
10
|
+
// 1. Setup initial doc
|
|
11
|
+
const doc = await createTestDocument();
|
|
12
|
+
addParagraph(doc, "First paragraph.");
|
|
13
|
+
addParagraph(doc, "Second paragraph.");
|
|
14
|
+
addParagraph(doc, "Third paragraph.");
|
|
15
|
+
|
|
16
|
+
// 2. Make an initial tracked change (Simulating Round 1)
|
|
17
|
+
const engine = new RedlineEngine(doc, "Round1");
|
|
18
|
+
engine.apply_edits([{ type: 'modify', target_text: "First", new_text: "1st" } as ModifyText]);
|
|
19
|
+
|
|
20
|
+
const midBuf = await doc.save();
|
|
21
|
+
|
|
22
|
+
// Verify intermediate state (Round 1)
|
|
23
|
+
const midText = await extractTextFromBuffer(midBuf);
|
|
24
|
+
expect(midText).toContain("{--First--}");
|
|
25
|
+
expect(midText).toContain("{++1st++}");
|
|
26
|
+
|
|
27
|
+
// Extract dynamically generated Change IDs for the Accept action
|
|
28
|
+
const matches = Array.from(midText.matchAll(/\[Chg:(\d+)(?:\s+\w+)?\]/g));
|
|
29
|
+
const chgIds = new Set(matches.map(m => m[1]));
|
|
30
|
+
expect(chgIds.size).toBeGreaterThan(0);
|
|
31
|
+
|
|
32
|
+
// 3. Execute the Atomic Batch (Simulating Round 2)
|
|
33
|
+
const midDoc = await DocumentObject.load(midBuf);
|
|
34
|
+
const engine2 = new RedlineEngine(midDoc, "Round2");
|
|
35
|
+
|
|
36
|
+
const actions = Array.from(chgIds).map(id => ({ type: 'accept', target_id: `Chg:${id}` } as AcceptChange));
|
|
37
|
+
const edits = [{ type: 'modify', target_text: "Third", new_text: "3rd" } as ModifyText];
|
|
38
|
+
|
|
39
|
+
const changes = [...actions, ...edits];
|
|
40
|
+
const stats = engine2.process_batch(changes);
|
|
41
|
+
|
|
42
|
+
// 4. Assertions on the Tool Execution
|
|
43
|
+
expect(stats.actions_applied).toBe(actions.length);
|
|
44
|
+
expect(stats.edits_applied).toBe(1);
|
|
45
|
+
|
|
46
|
+
// 5. Assertions on the Final Document State
|
|
47
|
+
const finalBuf = await midDoc.save();
|
|
48
|
+
const final_text = await extractTextFromBuffer(finalBuf);
|
|
49
|
+
|
|
50
|
+
// The first paragraph should be cleanly accepted
|
|
51
|
+
expect(final_text).toContain("1st paragraph.");
|
|
52
|
+
expect(final_text).not.toContain("{--First--}");
|
|
53
|
+
|
|
54
|
+
// The third paragraph should have the new tracked change anchored perfectly
|
|
55
|
+
expect(final_text).toContain("{--Third--}");
|
|
56
|
+
expect(final_text).toContain("{++3rd++}");
|
|
57
|
+
});
|
|
58
58
|
});
|
package/src/engine.batch.test.ts
CHANGED
|
@@ -1,93 +1,93 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { createTestDocument, addParagraph } from './test-utils.js';
|
|
3
|
-
import { DocumentObject } from './docx/bridge.js';
|
|
4
|
-
import { extractTextFromBuffer } from './ingest.js';
|
|
5
|
-
import { RedlineEngine } from './engine.js';
|
|
6
|
-
import { ModifyText, AcceptChange, RejectChange } from './models.js';
|
|
7
|
-
|
|
8
|
-
describe('Batch Reliability (Node.js Port)', () => {
|
|
9
|
-
it('batch accept does not corrupt the document', async () => {
|
|
10
|
-
const doc = await createTestDocument();
|
|
11
|
-
addParagraph(doc, "Para 1");
|
|
12
|
-
addParagraph(doc, "Para 2");
|
|
13
|
-
addParagraph(doc, "Para 3");
|
|
14
|
-
|
|
15
|
-
const engine = new RedlineEngine(doc);
|
|
16
|
-
const edits: ModifyText[] = [
|
|
17
|
-
{ type: 'modify', target_text: "Para 1", new_text: "Para One" },
|
|
18
|
-
{ type: 'modify', target_text: "Para 2", new_text: "Para Two" },
|
|
19
|
-
{ type: 'modify', target_text: "Para 3", new_text: "Para Three" },
|
|
20
|
-
];
|
|
21
|
-
|
|
22
|
-
engine.apply_edits(edits);
|
|
23
|
-
const redlinedBuf = await doc.save();
|
|
24
|
-
|
|
25
|
-
const text = await extractTextFromBuffer(redlinedBuf);
|
|
26
|
-
expect(text).toContain("[Chg:1 ");
|
|
27
|
-
expect(text).toContain("[Chg:6 ");
|
|
28
|
-
|
|
29
|
-
// BATCH ACCEPT ALL
|
|
30
|
-
const midDoc = await DocumentObject.load(redlinedBuf);
|
|
31
|
-
const engine2 = new RedlineEngine(midDoc);
|
|
32
|
-
|
|
33
|
-
const actions: AcceptChange[] = [1, 2, 3, 4, 5, 6].map(id => ({ type: 'accept', target_id: `Chg:${id}` }));
|
|
34
|
-
|
|
35
|
-
// Test direct apply_review_actions (Note: method missing in raw TS port right now, needs implementing)
|
|
36
|
-
const [applied, skipped] = (engine2 as any).apply_review_actions(actions);
|
|
37
|
-
|
|
38
|
-
expect(applied).toBe(6);
|
|
39
|
-
expect(skipped).toBe(0);
|
|
40
|
-
|
|
41
|
-
const finalBuf = await midDoc.save();
|
|
42
|
-
const final_text = await extractTextFromBuffer(finalBuf);
|
|
43
|
-
|
|
44
|
-
expect(final_text).toContain("Para One");
|
|
45
|
-
expect(final_text).toContain("Para Two");
|
|
46
|
-
expect(final_text).toContain("Para Three");
|
|
47
|
-
|
|
48
|
-
expect(final_text).not.toContain("Para 1");
|
|
49
|
-
expect(final_text).not.toContain("Para 2");
|
|
50
|
-
expect(final_text).not.toContain("Para 3");
|
|
51
|
-
|
|
52
|
-
expect(final_text).not.toContain("[Chg:");
|
|
53
|
-
expect(final_text).not.toContain("{++");
|
|
54
|
-
expect(final_text).not.toContain("{--");
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it('batch mixed accept and reject maintains integrity', async () => {
|
|
58
|
-
const doc = await createTestDocument();
|
|
59
|
-
addParagraph(doc, "Para 1");
|
|
60
|
-
addParagraph(doc, "Para 2");
|
|
61
|
-
|
|
62
|
-
const engine = new RedlineEngine(doc);
|
|
63
|
-
const edits: ModifyText[] = [
|
|
64
|
-
{ type: 'modify', target_text: "Para 1", new_text: "Para One" },
|
|
65
|
-
{ type: 'modify', target_text: "Para 2", new_text: "Para Two" },
|
|
66
|
-
];
|
|
67
|
-
|
|
68
|
-
engine.apply_edits(edits);
|
|
69
|
-
const redlinedBuf = await doc.save();
|
|
70
|
-
|
|
71
|
-
const midDoc = await DocumentObject.load(redlinedBuf);
|
|
72
|
-
const engine2 = new RedlineEngine(midDoc);
|
|
73
|
-
|
|
74
|
-
const actions = [
|
|
75
|
-
{ type: 'accept', target_id: "Chg:3" } as AcceptChange,
|
|
76
|
-
{ type: 'accept', target_id: "Chg:4" } as AcceptChange,
|
|
77
|
-
{ type: 'reject', target_id: "Chg:1" } as RejectChange,
|
|
78
|
-
{ type: 'reject', target_id: "Chg:2" } as RejectChange,
|
|
79
|
-
];
|
|
80
|
-
|
|
81
|
-
const [applied] = (engine2 as any).apply_review_actions(actions);
|
|
82
|
-
expect(applied).toBe(4);
|
|
83
|
-
|
|
84
|
-
const finalBuf = await midDoc.save();
|
|
85
|
-
const text_final = await extractTextFromBuffer(finalBuf);
|
|
86
|
-
|
|
87
|
-
expect(text_final).toContain("Para One");
|
|
88
|
-
expect(text_final).not.toContain("Para 1");
|
|
89
|
-
|
|
90
|
-
expect(text_final).toContain("Para 2");
|
|
91
|
-
expect(text_final).not.toContain("Para Two");
|
|
92
|
-
});
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { createTestDocument, addParagraph } from './test-utils.js';
|
|
3
|
+
import { DocumentObject } from './docx/bridge.js';
|
|
4
|
+
import { extractTextFromBuffer } from './ingest.js';
|
|
5
|
+
import { RedlineEngine } from './engine.js';
|
|
6
|
+
import { ModifyText, AcceptChange, RejectChange } from './models.js';
|
|
7
|
+
|
|
8
|
+
describe('Batch Reliability (Node.js Port)', () => {
|
|
9
|
+
it('batch accept does not corrupt the document', async () => {
|
|
10
|
+
const doc = await createTestDocument();
|
|
11
|
+
addParagraph(doc, "Para 1");
|
|
12
|
+
addParagraph(doc, "Para 2");
|
|
13
|
+
addParagraph(doc, "Para 3");
|
|
14
|
+
|
|
15
|
+
const engine = new RedlineEngine(doc);
|
|
16
|
+
const edits: ModifyText[] = [
|
|
17
|
+
{ type: 'modify', target_text: "Para 1", new_text: "Para One" },
|
|
18
|
+
{ type: 'modify', target_text: "Para 2", new_text: "Para Two" },
|
|
19
|
+
{ type: 'modify', target_text: "Para 3", new_text: "Para Three" },
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
engine.apply_edits(edits);
|
|
23
|
+
const redlinedBuf = await doc.save();
|
|
24
|
+
|
|
25
|
+
const text = await extractTextFromBuffer(redlinedBuf);
|
|
26
|
+
expect(text).toContain("[Chg:1 ");
|
|
27
|
+
expect(text).toContain("[Chg:6 ");
|
|
28
|
+
|
|
29
|
+
// BATCH ACCEPT ALL
|
|
30
|
+
const midDoc = await DocumentObject.load(redlinedBuf);
|
|
31
|
+
const engine2 = new RedlineEngine(midDoc);
|
|
32
|
+
|
|
33
|
+
const actions: AcceptChange[] = [1, 2, 3, 4, 5, 6].map(id => ({ type: 'accept', target_id: `Chg:${id}` }));
|
|
34
|
+
|
|
35
|
+
// Test direct apply_review_actions (Note: method missing in raw TS port right now, needs implementing)
|
|
36
|
+
const [applied, skipped] = (engine2 as any).apply_review_actions(actions);
|
|
37
|
+
|
|
38
|
+
expect(applied).toBe(6);
|
|
39
|
+
expect(skipped).toBe(0);
|
|
40
|
+
|
|
41
|
+
const finalBuf = await midDoc.save();
|
|
42
|
+
const final_text = await extractTextFromBuffer(finalBuf);
|
|
43
|
+
|
|
44
|
+
expect(final_text).toContain("Para One");
|
|
45
|
+
expect(final_text).toContain("Para Two");
|
|
46
|
+
expect(final_text).toContain("Para Three");
|
|
47
|
+
|
|
48
|
+
expect(final_text).not.toContain("Para 1");
|
|
49
|
+
expect(final_text).not.toContain("Para 2");
|
|
50
|
+
expect(final_text).not.toContain("Para 3");
|
|
51
|
+
|
|
52
|
+
expect(final_text).not.toContain("[Chg:");
|
|
53
|
+
expect(final_text).not.toContain("{++");
|
|
54
|
+
expect(final_text).not.toContain("{--");
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('batch mixed accept and reject maintains integrity', async () => {
|
|
58
|
+
const doc = await createTestDocument();
|
|
59
|
+
addParagraph(doc, "Para 1");
|
|
60
|
+
addParagraph(doc, "Para 2");
|
|
61
|
+
|
|
62
|
+
const engine = new RedlineEngine(doc);
|
|
63
|
+
const edits: ModifyText[] = [
|
|
64
|
+
{ type: 'modify', target_text: "Para 1", new_text: "Para One" },
|
|
65
|
+
{ type: 'modify', target_text: "Para 2", new_text: "Para Two" },
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
engine.apply_edits(edits);
|
|
69
|
+
const redlinedBuf = await doc.save();
|
|
70
|
+
|
|
71
|
+
const midDoc = await DocumentObject.load(redlinedBuf);
|
|
72
|
+
const engine2 = new RedlineEngine(midDoc);
|
|
73
|
+
|
|
74
|
+
const actions = [
|
|
75
|
+
{ type: 'accept', target_id: "Chg:3" } as AcceptChange,
|
|
76
|
+
{ type: 'accept', target_id: "Chg:4" } as AcceptChange,
|
|
77
|
+
{ type: 'reject', target_id: "Chg:1" } as RejectChange,
|
|
78
|
+
{ type: 'reject', target_id: "Chg:2" } as RejectChange,
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
const [applied] = (engine2 as any).apply_review_actions(actions);
|
|
82
|
+
expect(applied).toBe(4);
|
|
83
|
+
|
|
84
|
+
const finalBuf = await midDoc.save();
|
|
85
|
+
const text_final = await extractTextFromBuffer(finalBuf);
|
|
86
|
+
|
|
87
|
+
expect(text_final).toContain("Para One");
|
|
88
|
+
expect(text_final).not.toContain("Para 1");
|
|
89
|
+
|
|
90
|
+
expect(text_final).toContain("Para 2");
|
|
91
|
+
expect(text_final).not.toContain("Para Two");
|
|
92
|
+
});
|
|
93
93
|
});
|
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { createTestDocument, addParagraph } from './test-utils.js';
|
|
3
|
-
import { RedlineEngine } from './engine.js';
|
|
4
|
-
import { ModifyText } from './models.js';
|
|
5
|
-
|
|
6
|
-
describe('Safety Engine Constraints (Node.js Port)', () => {
|
|
7
|
-
it('rejects empty target heuristic to prevent accidental insertions', async () => {
|
|
8
|
-
const doc = await createTestDocument();
|
|
9
|
-
addParagraph(doc, "Content");
|
|
10
|
-
|
|
11
|
-
const engine = new RedlineEngine(doc);
|
|
12
|
-
const edit: ModifyText = { type: 'modify', target_text: "", new_text: "Unexpected Header" };
|
|
13
|
-
|
|
14
|
-
const [applied, skipped] = engine.apply_edits([edit]);
|
|
15
|
-
|
|
16
|
-
expect(applied).toBe(0);
|
|
17
|
-
expect(skipped).toBe(1);
|
|
18
|
-
|
|
19
|
-
const xml = (doc.element as Element).ownerDocument?.documentElement.toString();
|
|
20
|
-
expect(xml).not.toContain("Unexpected Header");
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('applies heuristic edits strictly once for multiple occurrences', async () => {
|
|
24
|
-
const doc = await createTestDocument();
|
|
25
|
-
addParagraph(doc, "Repeat");
|
|
26
|
-
addParagraph(doc, "Repeat");
|
|
27
|
-
|
|
28
|
-
const engine = new RedlineEngine(doc);
|
|
29
|
-
const edit: ModifyText = { type: 'modify', target_text: "Repeat", new_text: "Changed" };
|
|
30
|
-
|
|
31
|
-
const [applied, skipped] = engine.apply_edits([edit]);
|
|
32
|
-
|
|
33
|
-
expect(applied).toBe(1);
|
|
34
|
-
expect(skipped).toBe(0);
|
|
35
|
-
|
|
36
|
-
const xml = (doc.element as Element).ownerDocument?.documentElement.toString();
|
|
37
|
-
|
|
38
|
-
// We expect one deletion of Repeat and one insertion of Changed
|
|
39
|
-
expect((xml?.match(/<w:delText[^>]*>Repeat<\/w:delText>/g) || []).length).toBe(1);
|
|
40
|
-
expect((xml?.match(/<w:t[^>]*>Changed<\/w:t>/g) || []).length).toBe(1);
|
|
41
|
-
});
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { createTestDocument, addParagraph } from './test-utils.js';
|
|
3
|
+
import { RedlineEngine } from './engine.js';
|
|
4
|
+
import { ModifyText } from './models.js';
|
|
5
|
+
|
|
6
|
+
describe('Safety Engine Constraints (Node.js Port)', () => {
|
|
7
|
+
it('rejects empty target heuristic to prevent accidental insertions', async () => {
|
|
8
|
+
const doc = await createTestDocument();
|
|
9
|
+
addParagraph(doc, "Content");
|
|
10
|
+
|
|
11
|
+
const engine = new RedlineEngine(doc);
|
|
12
|
+
const edit: ModifyText = { type: 'modify', target_text: "", new_text: "Unexpected Header" };
|
|
13
|
+
|
|
14
|
+
const [applied, skipped] = engine.apply_edits([edit]);
|
|
15
|
+
|
|
16
|
+
expect(applied).toBe(0);
|
|
17
|
+
expect(skipped).toBe(1);
|
|
18
|
+
|
|
19
|
+
const xml = (doc.element as Element).ownerDocument?.documentElement.toString();
|
|
20
|
+
expect(xml).not.toContain("Unexpected Header");
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('applies heuristic edits strictly once for multiple occurrences', async () => {
|
|
24
|
+
const doc = await createTestDocument();
|
|
25
|
+
addParagraph(doc, "Repeat");
|
|
26
|
+
addParagraph(doc, "Repeat");
|
|
27
|
+
|
|
28
|
+
const engine = new RedlineEngine(doc);
|
|
29
|
+
const edit: ModifyText = { type: 'modify', target_text: "Repeat", new_text: "Changed" };
|
|
30
|
+
|
|
31
|
+
const [applied, skipped] = engine.apply_edits([edit]);
|
|
32
|
+
|
|
33
|
+
expect(applied).toBe(1);
|
|
34
|
+
expect(skipped).toBe(0);
|
|
35
|
+
|
|
36
|
+
const xml = (doc.element as Element).ownerDocument?.documentElement.toString();
|
|
37
|
+
|
|
38
|
+
// We expect one deletion of Repeat and one insertion of Changed
|
|
39
|
+
expect((xml?.match(/<w:delText[^>]*>Repeat<\/w:delText>/g) || []).length).toBe(1);
|
|
40
|
+
expect((xml?.match(/<w:t[^>]*>Changed<\/w:t>/g) || []).length).toBe(1);
|
|
41
|
+
});
|
|
42
42
|
});
|