@ansonlai/docx-redline-js 0.5.4 → 0.6.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/AGENTS.md +78 -697
- package/ARCHITECTURE.md +13 -1
- package/CHANGELOG.md +5 -0
- package/README.md +140 -30
- package/core/paragraph-targeting.js +14 -2
- package/dist/docx-redline-js.esm.js +113 -33
- package/dist/docx-redline-js.esm.js.map +3 -3
- package/dist/docx-redline-js.esm.min.js +75 -75
- package/dist/docx-redline-js.esm.min.js.map +4 -4
- package/docs/AGENT_FAST_START.md +59 -0
- package/docs/AGENT_KNOWLEDGE_BASE.md +868 -0
- package/docs/TESTING.md +20 -1
- package/docs/schemas/document-operations.schema.json +5 -1
- package/docs/validation-reports/2026-09-12-agent-protocol-rollout.md +82 -0
- package/engine/oxml-engine.js +80 -13
- package/engine/run-builders.js +5 -15
- package/index.d.ts +17 -1
- package/node/cli.js +111 -27
- package/node/docx-document.js +120 -69
- package/node/index.d.ts +6 -2
- package/package.json +10 -3
- package/scripts/generate-cross-author-slicing-fixtures.ps1 +25 -25
- package/services/batch-operation-orchestrator.js +215 -120
- package/services/document-inspection.js +5 -3
- package/services/document-operation-applier.js +52 -34
- package/services/document-operation-contract.js +10 -6
- package/services/document-operation-mutations.js +51 -5
- package/services/document-operation-session.js +4 -0
- package/services/error-recovery.js +174 -0
- package/services/operation-batch-compiler.js +394 -0
- package/services/operation-preflight.js +91 -72
- package/services/standalone-operation-runner.d.ts +17 -1
- package/docs/plans/2026-09-05-structural-revisions-and-fidelity-oracles.md +0 -1669
- package/docs/plans/2026-09-08-cross-author-revision-slicing.md +0 -1399
- package/docs/plans/completed/2026-03-01-release-0.1.4-design.md +0 -33
- package/docs/plans/completed/2026-03-01-release-0.1.4.md +0 -110
- package/docs/plans/completed/2026-05-31-architectural changes.md +0 -593
- package/docs/plans/completed/2026-08-02-reliability-improvements.md +0 -1155
- package/docs/plans/completed/2026-08-30-reliability-testing-improvements.md +0 -488
- package/docs/plans/completed/2026-09-01-performance-and-complexity-reduction.md +0 -669
- package/docs/plans/completed/2026-09-03-agent-friendly-document-workflows.md +0 -427
- package/docs/plans/completed/2026-09-04-comment-anchor-and-cli-reliability.md +0 -519
- package/docs/plans/completed/PERFORMANCE-CONSOLIDATION.md +0 -69
- package/docs/plans/completed/structural-revision-capability-matrix.md +0 -115
- package/docs/test-comparison-dashboard.html +0 -4338
- package/docs/validation-reports/2026-08-30-phase-1-word-visual-preflight.md +0 -22
- package/docs/validation-reports/2026-08-30-phase-2-word-visual-preflight.md +0 -24
- package/docs/validation-reports/2026-08-30-phase-3-coverage.md +0 -73
- package/docs/validation-reports/2026-09-02-multilevel-bullets-visual-review.md +0 -82
- package/docs/validation-reports/2026-09-02-multimodal-visual-samples.md +0 -114
- package/docs/validation-reports/2026-09-02-visual-failures-preflight.md +0 -79
package/node/docx-document.js
CHANGED
|
@@ -11,11 +11,42 @@ import { acceptTrackedChangesInOoxml, rejectTrackedChangesInOoxml, deleteComment
|
|
|
11
11
|
import { createSerializer, parseOoxmlSafe } from '../adapters/xml-adapter.js';
|
|
12
12
|
import { createHash } from 'node:crypto';
|
|
13
13
|
import { MemoryZip, unzipDocx, zipDocx } from './zip-archive.js';
|
|
14
|
-
import { computeRevisionTokenSync, validateRevisionToken, areRevisionTokensEqual } from '../services/revision-token.js';
|
|
14
|
+
import { computeRevisionTokenSync, validateRevisionToken, areRevisionTokensEqual } from '../services/revision-token.js';
|
|
15
|
+
import { createRetryPlan, normalizeErrorWithRecovery } from '../services/error-recovery.js';
|
|
15
16
|
|
|
16
17
|
configureXmlProvider({ DOMParser, XMLSerializer });
|
|
17
|
-
const text = (entries, path) => entries.get(path)?.toString('utf8') || null;
|
|
18
|
-
const cloneEntries = entries => new Map([...entries].map(([name, data]) => [name, Buffer.from(data)]));
|
|
18
|
+
const text = (entries, path) => entries.get(path)?.toString('utf8') || null;
|
|
19
|
+
const cloneEntries = entries => new Map([...entries].map(([name, data]) => [name, Buffer.from(data)]));
|
|
20
|
+
|
|
21
|
+
function rolledBackOperationPayload(operationResult, operationCount) {
|
|
22
|
+
const rollbackReceipt = receipt => {
|
|
23
|
+
if (!receipt || typeof receipt !== 'object') return receipt;
|
|
24
|
+
if (receipt.attemptedDisposition !== 'applied' && receipt.committed !== true) return { ...receipt };
|
|
25
|
+
return { ...receipt, committed: false, finalDisposition: 'rolled_back' };
|
|
26
|
+
};
|
|
27
|
+
const receipts = (operationResult?.receipts || []).map(rollbackReceipt);
|
|
28
|
+
const receiptByIndex = new Map(receipts.map(receipt => [receipt.operationIndex, receipt]));
|
|
29
|
+
const results = (operationResult?.results || []).map(result => ({
|
|
30
|
+
...result,
|
|
31
|
+
...(result.receipt ? {
|
|
32
|
+
receipt: receiptByIndex.get(result.index) || rollbackReceipt(result.receipt)
|
|
33
|
+
} : {})
|
|
34
|
+
}));
|
|
35
|
+
return {
|
|
36
|
+
results,
|
|
37
|
+
receipts,
|
|
38
|
+
executionOrder: operationResult?.executionOrder || [],
|
|
39
|
+
authorsUsed: [],
|
|
40
|
+
rolledBack: true,
|
|
41
|
+
retryPlan: createRetryPlan({
|
|
42
|
+
atomic: true,
|
|
43
|
+
rolledBack: true,
|
|
44
|
+
results,
|
|
45
|
+
receipts,
|
|
46
|
+
operationCount
|
|
47
|
+
})
|
|
48
|
+
};
|
|
49
|
+
}
|
|
19
50
|
|
|
20
51
|
/**
|
|
21
52
|
* Computes a package-scoped revision token over all uncompressed entries in a DOCX archive.
|
|
@@ -84,60 +115,55 @@ export class DocxDocument {
|
|
|
84
115
|
get revisionToken() { return this.getRevisionToken(); }
|
|
85
116
|
preflight(operations, author = getDefaultAuthor(), options = {}) { return preflightOperations(text(this.entries, 'word/document.xml'), operations, author || getDefaultAuthor(), { ...options, _existingCommentDetails: existingCommentDetails(this.entries) }); }
|
|
86
117
|
toBuffer() { return zipDocx(this.entries); }
|
|
87
|
-
async applyOperations(operations, options = {}) {
|
|
88
|
-
|
|
118
|
+
async applyOperations(operations, options = {}) {
|
|
119
|
+
const failedApply = error => {
|
|
120
|
+
const results = [];
|
|
121
|
+
const receipts = [];
|
|
122
|
+
return {
|
|
123
|
+
status: 'error',
|
|
124
|
+
hasChanges: false,
|
|
125
|
+
written: false,
|
|
126
|
+
rolledBack: true,
|
|
127
|
+
results,
|
|
128
|
+
receipts,
|
|
129
|
+
artifactsChanged: [],
|
|
130
|
+
error: normalizeErrorWithRecovery(error),
|
|
131
|
+
retryPlan: createRetryPlan({
|
|
132
|
+
atomic: true,
|
|
133
|
+
rolledBack: true,
|
|
134
|
+
results,
|
|
135
|
+
receipts,
|
|
136
|
+
operationCount: Array.isArray(operations) ? operations.length : 0
|
|
137
|
+
}),
|
|
138
|
+
validation: { originalIssues: [], generatedIssues: [] },
|
|
139
|
+
buffer: Buffer.from(this.originalBuffer),
|
|
140
|
+
toBuffer: () => Buffer.from(this.originalBuffer)
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
if (options?.expectedRevision) {
|
|
89
144
|
const tokenValidation = validateRevisionToken(options.expectedRevision);
|
|
90
145
|
if (!tokenValidation.valid) {
|
|
91
|
-
return {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
rolledBack: true,
|
|
96
|
-
results: [],
|
|
97
|
-
artifactsChanged: [],
|
|
98
|
-
error: {
|
|
99
|
-
code: tokenValidation.error?.code || 'INVALID_REVISION_TOKEN',
|
|
100
|
-
message: tokenValidation.error?.message || 'Invalid revision token.'
|
|
101
|
-
},
|
|
102
|
-
validation: { originalIssues: [], generatedIssues: [] },
|
|
103
|
-
buffer: Buffer.from(this.originalBuffer),
|
|
104
|
-
toBuffer: () => Buffer.from(this.originalBuffer)
|
|
105
|
-
};
|
|
146
|
+
return failedApply({
|
|
147
|
+
code: tokenValidation.error?.code || 'INVALID_REVISION_TOKEN',
|
|
148
|
+
message: tokenValidation.error?.message || 'Invalid revision token.'
|
|
149
|
+
});
|
|
106
150
|
}
|
|
107
151
|
if (options.expectedRevision.scope !== 'package') {
|
|
108
|
-
return {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
artifactsChanged: [],
|
|
115
|
-
error: {
|
|
116
|
-
code: 'REVISION_TOKEN_SCOPE_MISMATCH',
|
|
117
|
-
message: `Revision token scope mismatch: expected 'package', got '${options.expectedRevision.scope}'.`
|
|
118
|
-
},
|
|
119
|
-
validation: { originalIssues: [], generatedIssues: [] },
|
|
120
|
-
buffer: Buffer.from(this.originalBuffer),
|
|
121
|
-
toBuffer: () => Buffer.from(this.originalBuffer)
|
|
122
|
-
};
|
|
152
|
+
return failedApply({
|
|
153
|
+
code: 'REVISION_TOKEN_SCOPE_MISMATCH',
|
|
154
|
+
message: `Revision token scope mismatch: expected 'package', got '${options.expectedRevision.scope}'.`,
|
|
155
|
+
expectedScope: 'package',
|
|
156
|
+
actualScope: options.expectedRevision.scope
|
|
157
|
+
});
|
|
123
158
|
}
|
|
124
159
|
const currentToken = computePackageRevisionToken(this.entries);
|
|
125
160
|
if (!areRevisionTokensEqual(currentToken.value, options.expectedRevision.value)) {
|
|
126
|
-
return {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
artifactsChanged: [],
|
|
133
|
-
error: {
|
|
134
|
-
code: 'REVISION_MISMATCH',
|
|
135
|
-
message: `Document revision mismatch: expected '${options.expectedRevision.value}', current is '${currentToken.value}'.`
|
|
136
|
-
},
|
|
137
|
-
validation: { originalIssues: [], generatedIssues: [] },
|
|
138
|
-
buffer: Buffer.from(this.originalBuffer),
|
|
139
|
-
toBuffer: () => Buffer.from(this.originalBuffer)
|
|
140
|
-
};
|
|
161
|
+
return failedApply({
|
|
162
|
+
code: 'REVISION_MISMATCH',
|
|
163
|
+
message: `Document revision mismatch: expected '${options.expectedRevision.value}', current is '${currentToken.value}'.`,
|
|
164
|
+
expectedRevision: options.expectedRevision,
|
|
165
|
+
currentRevision: currentToken
|
|
166
|
+
});
|
|
141
167
|
}
|
|
142
168
|
}
|
|
143
169
|
|
|
@@ -163,7 +189,17 @@ export class DocxDocument {
|
|
|
163
189
|
_existingCommentDetails: existingCommentDetails(working),
|
|
164
190
|
commentIdAllocator: nextCommentId(working)
|
|
165
191
|
});
|
|
166
|
-
if (result.rolledBack || result.status === 'error')
|
|
192
|
+
if (result.rolledBack || result.status === 'error') {
|
|
193
|
+
return {
|
|
194
|
+
...result,
|
|
195
|
+
...rolledBackOperationPayload(result, Array.isArray(operations) ? operations.length : 0),
|
|
196
|
+
written: false,
|
|
197
|
+
artifactsChanged: [],
|
|
198
|
+
validation: { originalIssues, generatedIssues: [] },
|
|
199
|
+
buffer: this.originalBuffer,
|
|
200
|
+
toBuffer: () => Buffer.from(this.originalBuffer)
|
|
201
|
+
};
|
|
202
|
+
}
|
|
167
203
|
if (!result.hasChanges) return { ...result, status: result.status || 'ok', written: false, artifactsChanged: [], validation: { originalIssues, generatedIssues: [] }, buffer: Buffer.from(this.originalBuffer), toBuffer: () => Buffer.from(this.originalBuffer) };
|
|
168
204
|
working.set('word/document.xml', Buffer.from(result.documentXml));
|
|
169
205
|
await ensureNumberingArtifactsInZip(zip, result.numberingXmlParts, { mergeNumberingXml: mergeNumberingXmlBySchemaOrder });
|
|
@@ -197,23 +233,26 @@ export class DocxDocument {
|
|
|
197
233
|
this.originalBuffer = Buffer.from(output);
|
|
198
234
|
const artifactsChanged = [...working].filter(([name, data]) => !originalEntries.has(name) || !data.equals(originalEntries.get(name))).map(([name]) => name);
|
|
199
235
|
return { ...result, status: result.status || 'ok', written: true, artifactsChanged, validation: { originalIssues, generatedIssues: [] }, buffer: output, inspection: this.inspect(), toBuffer: () => Buffer.from(output) };
|
|
200
|
-
} catch (error) {
|
|
201
|
-
this.entries = originalEntries;
|
|
202
|
-
const generatedIssues = error.issues || [{ source: 'package', code: 'PACKAGE_OPERATION_FAILED', severity: 'error', message: error.message }];
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
236
|
+
} catch (error) {
|
|
237
|
+
this.entries = originalEntries;
|
|
238
|
+
const generatedIssues = error.issues || [{ source: 'package', code: 'PACKAGE_OPERATION_FAILED', severity: 'error', message: error.message }];
|
|
239
|
+
const rollbackPayload = rolledBackOperationPayload(
|
|
240
|
+
operationResult,
|
|
241
|
+
Array.isArray(operations) ? operations.length : 0
|
|
242
|
+
);
|
|
243
|
+
return {
|
|
244
|
+
...rollbackPayload,
|
|
245
|
+
status: 'error',
|
|
246
|
+
hasChanges: false,
|
|
247
|
+
written: false,
|
|
248
|
+
artifactsChanged: [],
|
|
249
|
+
error: normalizeErrorWithRecovery({
|
|
250
|
+
code: 'PACKAGE_OPERATION_FAILED',
|
|
251
|
+
message: error.message,
|
|
252
|
+
stage: 'package',
|
|
253
|
+
issues: generatedIssues
|
|
254
|
+
}),
|
|
255
|
+
validation: { originalIssues, generatedIssues },
|
|
217
256
|
issues: generatedIssues,
|
|
218
257
|
buffer: Buffer.from(this.originalBuffer),
|
|
219
258
|
toBuffer: () => Buffer.from(this.originalBuffer)
|
|
@@ -301,5 +340,17 @@ export class DocxDocument {
|
|
|
301
340
|
}
|
|
302
341
|
}
|
|
303
342
|
|
|
304
|
-
function packageFailure(source, code, message) {
|
|
343
|
+
function packageFailure(source, code, message) {
|
|
344
|
+
return {
|
|
345
|
+
status: 'error',
|
|
346
|
+
hasChanges: false,
|
|
347
|
+
written: false,
|
|
348
|
+
rolledBack: true,
|
|
349
|
+
error: normalizeErrorWithRecovery({ code, message }),
|
|
350
|
+
retryPlan: createRetryPlan({ atomic: true, rolledBack: true }),
|
|
351
|
+
artifactsChanged: [],
|
|
352
|
+
buffer: Buffer.from(source),
|
|
353
|
+
toBuffer: () => Buffer.from(source)
|
|
354
|
+
};
|
|
355
|
+
}
|
|
305
356
|
export function openDocx(input) { return new DocxDocument(input); }
|
package/node/index.d.ts
CHANGED
|
@@ -27,5 +27,9 @@ export class DocxDocument {
|
|
|
27
27
|
}
|
|
28
28
|
export function computePackageRevisionToken(input: unknown): RevisionToken;
|
|
29
29
|
export function openDocx(input: Uint8Array): DocxDocument;
|
|
30
|
-
export
|
|
31
|
-
|
|
30
|
+
export interface CliIo {
|
|
31
|
+
stdin?: AsyncIterable<string | Uint8Array>;
|
|
32
|
+
stdout: { write(value: string): unknown };
|
|
33
|
+
}
|
|
34
|
+
export function executeCli(argv: string[], io?: Partial<CliIo>): Promise<Record<string, unknown>>;
|
|
35
|
+
export function runCli(argv?: string[], io?: CliIo): Promise<number>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ansonlai/docx-redline-js",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Host-independent OOXML reconciliation engine for .docx manipulation with track changes",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -44,7 +44,13 @@
|
|
|
44
44
|
"bin/",
|
|
45
45
|
"orchestration/",
|
|
46
46
|
"scripts/",
|
|
47
|
-
"
|
|
47
|
+
"!scripts/benchmark-agent-workflow.mjs",
|
|
48
|
+
"!scripts/lib/agent-performance-cases.mjs",
|
|
49
|
+
"docs/AGENT_FAST_START.md",
|
|
50
|
+
"docs/AGENT_KNOWLEDGE_BASE.md",
|
|
51
|
+
"docs/TESTING.md",
|
|
52
|
+
"docs/schemas/document-operations.schema.json",
|
|
53
|
+
"docs/validation-reports/2026-09-12-agent-protocol-rollout.md",
|
|
48
54
|
"index.js",
|
|
49
55
|
"index.d.ts",
|
|
50
56
|
"dist/",
|
|
@@ -77,10 +83,11 @@
|
|
|
77
83
|
"scripts": {
|
|
78
84
|
"build": "node scripts/build.mjs",
|
|
79
85
|
"check:types": "tsc -p tsconfig.types.json && node scripts/check-types.mjs",
|
|
80
|
-
"lint": "eslint index.js adapters core engine pipeline services orchestration scripts tests",
|
|
86
|
+
"lint": "eslint index.js adapters core engine pipeline services orchestration scripts examples tests",
|
|
81
87
|
"test:coverage": "c8 --reporter=text --reporter=json --reporter=json-summary --reports-dir=coverage node scripts/run-tests.mjs",
|
|
82
88
|
"coverage:gaps": "node scripts/report-coverage-gaps.mjs",
|
|
83
89
|
"benchmark:session": "node scripts/benchmark-operation-session.mjs",
|
|
90
|
+
"benchmark:agent": "node scripts/benchmark-agent-workflow.mjs",
|
|
84
91
|
"benchmark:targeting": "node scripts/benchmark-targeting-hot-paths.mjs",
|
|
85
92
|
"benchmark:tests": "node scripts/benchmark-test-runner.mjs",
|
|
86
93
|
"profile:routes": "node scripts/profile-route-selection.mjs",
|
|
@@ -76,7 +76,7 @@ try {
|
|
|
76
76
|
|
|
77
77
|
# -------------------------------------------------------------------------
|
|
78
78
|
# Scenario 1: insert-interior
|
|
79
|
-
# Author A (
|
|
79
|
+
# Author A (John) inserts: "amended by this Agreement."
|
|
80
80
|
# Author B (Anson) inserts "MASTER " before "Agreement"
|
|
81
81
|
# -------------------------------------------------------------------------
|
|
82
82
|
Write-Host "1. insert-interior"
|
|
@@ -85,8 +85,8 @@ try {
|
|
|
85
85
|
$doc.Range(0, 0).Text = "Contract terms "
|
|
86
86
|
|
|
87
87
|
# Author A insertion
|
|
88
|
-
$global:word.UserName = "
|
|
89
|
-
$global:word.UserInitials = "
|
|
88
|
+
$global:word.UserName = "John Doe"
|
|
89
|
+
$global:word.UserInitials = "JD"
|
|
90
90
|
$doc.TrackRevisions = $true
|
|
91
91
|
$endR = $doc.Range($doc.Content.End - 1, $doc.Content.End - 1)
|
|
92
92
|
$endR.Text = "amended by this Agreement."
|
|
@@ -103,7 +103,7 @@ try {
|
|
|
103
103
|
|
|
104
104
|
# -------------------------------------------------------------------------
|
|
105
105
|
# Scenario 2: delete-interior
|
|
106
|
-
# Author A (
|
|
106
|
+
# Author A (John) inserts: "The Platform will process the Data to generate deliverables for Client."
|
|
107
107
|
# Author B (Anson) deletes: "generate "
|
|
108
108
|
# -------------------------------------------------------------------------
|
|
109
109
|
Write-Host "2. delete-interior"
|
|
@@ -112,11 +112,11 @@ try {
|
|
|
112
112
|
$doc.Range(0, 0).Text = "Background. "
|
|
113
113
|
|
|
114
114
|
# Author A insertion
|
|
115
|
-
$global:word.UserName = "
|
|
116
|
-
$global:word.UserInitials = "
|
|
115
|
+
$global:word.UserName = "John Doe"
|
|
116
|
+
$global:word.UserInitials = "JD"
|
|
117
117
|
$doc.TrackRevisions = $true
|
|
118
118
|
$endR = $doc.Range($doc.Content.End - 1, $doc.Content.End - 1)
|
|
119
|
-
$endR.Text = "The
|
|
119
|
+
$endR.Text = "The Platform will process the Data to generate deliverables for Client."
|
|
120
120
|
|
|
121
121
|
# Author B deletion inside Author A's insertion
|
|
122
122
|
$global:word.UserName = "Anson Lai"
|
|
@@ -129,8 +129,8 @@ try {
|
|
|
129
129
|
|
|
130
130
|
# -------------------------------------------------------------------------
|
|
131
131
|
# Scenario 3: delete-boundary-start
|
|
132
|
-
# Author A (
|
|
133
|
-
# Author B (Anson) deletes: "Notwithstanding the
|
|
132
|
+
# Author A (John) inserts: "Notwithstanding anything to the contrary, the confidentiality terms remain in effect."
|
|
133
|
+
# Author B (Anson) deletes: "Notwithstanding anything to the contrary, "
|
|
134
134
|
# -------------------------------------------------------------------------
|
|
135
135
|
Write-Host "3. delete-boundary-start"
|
|
136
136
|
$doc = $global:word.Documents.Add()
|
|
@@ -138,16 +138,16 @@ try {
|
|
|
138
138
|
$doc.Range(0, 0).Text = "Section 1. "
|
|
139
139
|
|
|
140
140
|
# Author A insertion
|
|
141
|
-
$global:word.UserName = "
|
|
142
|
-
$global:word.UserInitials = "
|
|
141
|
+
$global:word.UserName = "John Doe"
|
|
142
|
+
$global:word.UserInitials = "JD"
|
|
143
143
|
$doc.TrackRevisions = $true
|
|
144
144
|
$endR = $doc.Range($doc.Content.End - 1, $doc.Content.End - 1)
|
|
145
|
-
$endR.Text = "Notwithstanding the
|
|
145
|
+
$endR.Text = "Notwithstanding anything to the contrary, the confidentiality terms remain in effect."
|
|
146
146
|
|
|
147
147
|
# Author B deletion at start of insertion
|
|
148
148
|
$global:word.UserName = "Anson Lai"
|
|
149
149
|
$global:word.UserInitials = "AL"
|
|
150
|
-
$delWord = "Notwithstanding the
|
|
150
|
+
$delWord = "Notwithstanding anything to the contrary, "
|
|
151
151
|
$foundPos = Find-RequiredText $doc $delWord "delete-boundary-start"
|
|
152
152
|
$delRange = $doc.Range($foundPos, $foundPos + $delWord.Length)
|
|
153
153
|
$delRange.Delete() | Out-Null
|
|
@@ -155,8 +155,8 @@ try {
|
|
|
155
155
|
|
|
156
156
|
# -------------------------------------------------------------------------
|
|
157
157
|
# Scenario 4: delete-boundary-end
|
|
158
|
-
# Author A (
|
|
159
|
-
# Author B (Anson) deletes: " and applicable
|
|
158
|
+
# Author A (John) inserts: "subject to Section 4.2 and applicable standards."
|
|
159
|
+
# Author B (Anson) deletes: " and applicable standards."
|
|
160
160
|
# -------------------------------------------------------------------------
|
|
161
161
|
Write-Host "4. delete-boundary-end"
|
|
162
162
|
$doc = $global:word.Documents.Add()
|
|
@@ -164,16 +164,16 @@ try {
|
|
|
164
164
|
$doc.Range(0, 0).Text = "Compliance: "
|
|
165
165
|
|
|
166
166
|
# Author A insertion
|
|
167
|
-
$global:word.UserName = "
|
|
168
|
-
$global:word.UserInitials = "
|
|
167
|
+
$global:word.UserName = "John Doe"
|
|
168
|
+
$global:word.UserInitials = "JD"
|
|
169
169
|
$doc.TrackRevisions = $true
|
|
170
170
|
$endR = $doc.Range($doc.Content.End - 1, $doc.Content.End - 1)
|
|
171
|
-
$endR.Text = "subject to Section 2
|
|
171
|
+
$endR.Text = "subject to Section 4.2 and applicable standards."
|
|
172
172
|
|
|
173
173
|
# Author B deletion at end of insertion
|
|
174
174
|
$global:word.UserName = "Anson Lai"
|
|
175
175
|
$global:word.UserInitials = "AL"
|
|
176
|
-
$delWord = " and applicable
|
|
176
|
+
$delWord = " and applicable standards."
|
|
177
177
|
$foundPos = Find-RequiredText $doc $delWord "delete-boundary-end"
|
|
178
178
|
$delRange = $doc.Range($foundPos, $foundPos + $delWord.Length)
|
|
179
179
|
$delRange.Delete() | Out-Null
|
|
@@ -182,7 +182,7 @@ try {
|
|
|
182
182
|
# -------------------------------------------------------------------------
|
|
183
183
|
# Scenario 5: delete-straddle-baseline-insertion
|
|
184
184
|
# Baseline: "Baseline start "
|
|
185
|
-
# Author A (
|
|
185
|
+
# Author A (John) inserts: "inserted finish."
|
|
186
186
|
# Author B (Anson) deletes: "start inserted" (straddling baseline and insertion)
|
|
187
187
|
# -------------------------------------------------------------------------
|
|
188
188
|
Write-Host "5. delete-straddle-baseline-insertion"
|
|
@@ -191,8 +191,8 @@ try {
|
|
|
191
191
|
$doc.Range(0, 0).Text = "Baseline start "
|
|
192
192
|
|
|
193
193
|
# Author A insertion
|
|
194
|
-
$global:word.UserName = "
|
|
195
|
-
$global:word.UserInitials = "
|
|
194
|
+
$global:word.UserName = "John Doe"
|
|
195
|
+
$global:word.UserInitials = "JD"
|
|
196
196
|
$doc.TrackRevisions = $true
|
|
197
197
|
$endR = $doc.Range($doc.Content.End - 1, $doc.Content.End - 1)
|
|
198
198
|
$endR.Text = "inserted finish."
|
|
@@ -209,7 +209,7 @@ try {
|
|
|
209
209
|
# -------------------------------------------------------------------------
|
|
210
210
|
# Scenario 6: multi-author-stacked
|
|
211
211
|
# Baseline: "Provision "
|
|
212
|
-
# Author A (
|
|
212
|
+
# Author A (John) inserts: "first draft of the proposal with initial metrics."
|
|
213
213
|
# Author B (Anson) deletes: "of the proposal "
|
|
214
214
|
# Author C (Chris) deletes: "initial " from the remaining text
|
|
215
215
|
# -------------------------------------------------------------------------
|
|
@@ -219,8 +219,8 @@ try {
|
|
|
219
219
|
$doc.Range(0, 0).Text = "Provision "
|
|
220
220
|
|
|
221
221
|
# Author A insertion
|
|
222
|
-
$global:word.UserName = "
|
|
223
|
-
$global:word.UserInitials = "
|
|
222
|
+
$global:word.UserName = "John Doe"
|
|
223
|
+
$global:word.UserInitials = "JD"
|
|
224
224
|
$doc.TrackRevisions = $true
|
|
225
225
|
$endR = $doc.Range($doc.Content.End - 1, $doc.Content.End - 1)
|
|
226
226
|
$endR.Text = "first draft of the proposal with initial metrics."
|