@ansonlai/docx-redline-js 0.8.3 → 0.9.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/ARCHITECTURE.md +221 -12
- package/CHANGELOG.md +803 -586
- package/README.md +1018 -901
- package/core/current-properties.js +136 -0
- package/core/paragraph-text.js +211 -209
- package/core/types.js +9 -3
- package/core/word-revision-semantics.js +256 -0
- package/dist/docx-redline-js.esm.js +4551 -967
- package/dist/docx-redline-js.esm.js.map +4 -4
- package/dist/docx-redline-js.esm.min.js +112 -106
- package/dist/docx-redline-js.esm.min.js.map +4 -4
- package/dist/docx-redline.bundle.cjs +4690 -1106
- package/dist/docx-redline.bundle.cjs.map +4 -4
- package/dist/docx-redline.bundle.js +4690 -1106
- package/dist/docx-redline.bundle.js.map +4 -4
- package/docs/AGENT_FAST_START.md +2 -0
- package/docs/AGENT_KNOWLEDGE_BASE.md +23 -4
- package/docs/SKILL_AUTHORING.md +165 -150
- package/docs/TESTING.md +1142 -1059
- package/docs/schemas/document-operations.schema.json +221 -168
- package/document/docx-document.js +1022 -1010
- package/engine/oxml-engine.js +567 -560
- package/engine/paragraph-mark-revisions.js +292 -0
- package/engine/reconstruction-mapper.js +312 -311
- package/engine/reconstruction-mode.js +183 -183
- package/engine/reconstruction-writer.js +67 -10
- package/engine/rpr-helpers.js +42 -0
- package/engine/run-builders.js +0 -73
- package/engine/surgical-diff-application.js +604 -605
- package/engine/table-mode.js +63 -63
- package/index.d.ts +51 -1
- package/index.js +47 -3
- package/node/cli-help.js +1 -0
- package/node/cli.js +992 -974
- package/orchestration/list-structural-fallback.js +67 -9
- package/package.json +1 -1
- package/pipeline/diff-engine.js +130 -1
- package/pipeline/ingestion-export.js +227 -243
- package/pipeline/ingestion-paragraph.js +93 -98
- package/pipeline/list-generation.js +415 -419
- package/pipeline/pipeline.js +206 -204
- package/pipeline/serialization.js +111 -94
- package/scripts/export-validation-fixtures.mjs +19 -6
- package/scripts/generate-word-revision-semantics-matrix.mjs +134 -0
- package/scripts/lib/word-coverage-catalogue.mjs +7 -2
- package/scripts/render-multilevel-bullet-visual.ps1 +2 -2
- package/scripts/word-com-corpus-visual-suite.ps1 +2 -2
- package/scripts/word-com-differential.ps1 +443 -335
- package/scripts/word-com-visual-suite.ps1 +2 -2
- package/scripts/word-revision-semantics-matrix.ps1 +108 -0
- package/services/batch-operation-orchestrator.js +26 -0
- package/services/capture-engine.js +228 -226
- package/services/document-operation-applier.js +215 -0
- package/services/document-operation-contract.js +628 -537
- package/services/document-operation-mutations.js +789 -46
- package/services/error-recovery.js +17 -0
- package/services/list-conversion-diagnostics.js +296 -0
- package/services/list-format-change.js +586 -0
- package/services/list-format-mutation.js +416 -0
- package/services/list-format.js +305 -0
- package/services/numbering-allocation.js +642 -0
- package/services/numbering-helpers.js +354 -524
- package/services/operation-batch-compiler.js +612 -436
- package/services/operation-heuristics.js +197 -173
- package/services/operation-preflight.js +1 -0
- package/services/receipt-collector.js +288 -288
- package/services/revision-comment-management.js +634 -594
- package/services/revision-fidelity-verifier.js +498 -0
- package/services/standalone-docx-plumbing.js +627 -631
- package/services/standalone-operation-runner.d.ts +606 -427
- package/services/table-reconciliation.js +103 -49
package/ARCHITECTURE.md
CHANGED
|
@@ -38,8 +38,10 @@ No Word add-in entrypoints or host-specific integration layers are part of this
|
|
|
38
38
|
│ ├── logger.js
|
|
39
39
|
│ └── xml-adapter.js
|
|
40
40
|
├── core/
|
|
41
|
+
│ ├── current-properties.js
|
|
41
42
|
│ ├── paragraph-text.js
|
|
42
43
|
│ ├── sha256.js
|
|
44
|
+
│ ├── word-revision-semantics.js
|
|
43
45
|
│ └── word-xml.js
|
|
44
46
|
├── document/
|
|
45
47
|
│ ├── docx-document.js
|
|
@@ -50,18 +52,27 @@ No Word add-in entrypoints or host-specific integration layers are part of this
|
|
|
50
52
|
│ ├── surgical-mode.js
|
|
51
53
|
│ ├── reconstruction-mode.js
|
|
52
54
|
│ ├── run-builders.js
|
|
55
|
+
│ ├── paragraph-mark-revisions.js
|
|
53
56
|
│ └── formatting-removal.js
|
|
54
57
|
├── orchestration/
|
|
55
58
|
├── pipeline/
|
|
56
59
|
├── services/
|
|
57
60
|
│ ├── comment-engine.js
|
|
58
61
|
│ ├── numbering-helpers.js
|
|
62
|
+
│ ├── numbering-allocation.js
|
|
63
|
+
│ ├── list-conversion-diagnostics.js
|
|
64
|
+
│ ├── list-format.js
|
|
65
|
+
│ ├── list-format-mutation.js
|
|
66
|
+
│ ├── list-format-change.js
|
|
67
|
+
│ ├── operation-batch-compiler.js
|
|
68
|
+
│ ├── localized-replacement-compiler.js
|
|
59
69
|
│ ├── revision-comment-management.js
|
|
60
70
|
│ ├── document-inspection.js
|
|
61
71
|
│ ├── document-operation-session.js
|
|
62
72
|
│ ├── document-operation-applier.js
|
|
63
73
|
│ ├── document-operation-mutations.js
|
|
64
74
|
│ ├── batch-operation-orchestrator.js
|
|
75
|
+
│ ├── revision-fidelity-verifier.js
|
|
65
76
|
│ ├── operation-heuristics.js
|
|
66
77
|
│ ├── standalone-docx-plumbing.js
|
|
67
78
|
│ └── standalone-operation-runner.js
|
|
@@ -116,6 +127,24 @@ No Word add-in entrypoints or host-specific integration layers are part of this
|
|
|
116
127
|
- `core/validation-delta.js`
|
|
117
128
|
- Stable issue signatures and multiset subtraction for classifying baseline
|
|
118
129
|
versus generated validation issues without hiding added duplicate errors.
|
|
130
|
+
- `core/word-revision-semantics.js`
|
|
131
|
+
- Pure DOM projection of what Word shows after Reject All or Accept All
|
|
132
|
+
(`projectWordRevisionView`, `wordRevisionParagraphTexts`,
|
|
133
|
+
`paragraphMarkRevision`). It encodes Word's paragraph-mark rules: a
|
|
134
|
+
tracked-inserted mark vanishes on Reject and its content merges into the
|
|
135
|
+
following paragraph of the same container, a tracked-deleted mark does the
|
|
136
|
+
same on Accept, a table cell keeps its last paragraph, rows marked inserted
|
|
137
|
+
or deleted vanish, and Reject restores `w:pPrChange` snapshots. It never
|
|
138
|
+
mutates or serializes. The rules are validated against recorded desktop
|
|
139
|
+
Word 16 COM results (`tests/fixtures/word-revision-semantics/`).
|
|
140
|
+
- `core/current-properties.js`
|
|
141
|
+
- Direct-child accessors for the current paragraph/run properties
|
|
142
|
+
(`getCurrentParagraphProperties`, `getCurrentRunProperties`,
|
|
143
|
+
`getCurrentChild`, `getCurrentNumIdElements`, ...). Descendant lookups cross
|
|
144
|
+
`w:pPrChange` / `w:rPrChange`, so a historical `numPr` or `pStyle` would look
|
|
145
|
+
current; the snapshot is reachable only through the explicit
|
|
146
|
+
`getHistoricalParagraphProperties` / `getHistoricalRunProperties` and
|
|
147
|
+
`getAllReferencedNumIdElements`. Depends only on `core/types.js`.
|
|
119
148
|
- `core/revision-cloning.js`
|
|
120
149
|
- Shared effective-property cloning strips historical revision descendants;
|
|
121
150
|
intentional revision-bearing splits refresh cloned property-change IDs.
|
|
@@ -125,7 +154,20 @@ No Word add-in entrypoints or host-specific integration layers are part of this
|
|
|
125
154
|
- Internal reconciliation capability matrix and opt-in diagnostic route
|
|
126
155
|
instrumentation. It observes policy; it does not expose a route override.
|
|
127
156
|
- `engine/run-builders.js`
|
|
128
|
-
- Shared builders for insertion/deletion wrappers,
|
|
157
|
+
- Shared builders for insertion/deletion wrappers, visible run content, and run-property changes. It does not build paragraph-mark revisions.
|
|
158
|
+
- `engine/paragraph-mark-revisions.js`
|
|
159
|
+
- The single construction site for a tracked paragraph mark (`w:ins` / `w:del`
|
|
160
|
+
under `w:pPr/w:rPr`). DOM entry points (`markParagraphInserted`,
|
|
161
|
+
`markParagraphDeleted`, `setParagraphPropertiesMarkRevision`,
|
|
162
|
+
`clearParagraphMarkRevision`, `restoreParagraphMarkInserted`) and string
|
|
163
|
+
builders (`paragraphMarkRevisionXml`, `paragraphMarkPPrXml`) share one
|
|
164
|
+
metadata path, so ids are allocated through the document's allocator and
|
|
165
|
+
recorded in receipts. `planParagraphMarks` is a pure check that an
|
|
166
|
+
alignment gives every source paragraph exactly one untracked or deleted
|
|
167
|
+
mark and every new target paragraph an inserted mark, so Reject All yields
|
|
168
|
+
the source paragraph count and a deleted paragraph is never collapsed into
|
|
169
|
+
another. Reconstruction, list and table generation, and document-level
|
|
170
|
+
shortcuts all call it. Depends only on `core/`.
|
|
129
171
|
- `engine/surgical-*.js`
|
|
130
172
|
- Surgical run splitting, diff application, and span helpers for localized edits that preserve surrounding markup. Plain-text edit groups execute from right to left with a fresh live span index, while space/NBSP-only replacement hunks are refined to character-local changes so unchanged hyperlink containers survive.
|
|
131
173
|
The shared carrier splitter also handles explicit rejected-view deletion
|
|
@@ -148,7 +190,36 @@ No Word add-in entrypoints or host-specific integration layers are part of this
|
|
|
148
190
|
- `services/comment-engine.js`
|
|
149
191
|
- Comment creation and package-level comment XML handling.
|
|
150
192
|
- `services/numbering-helpers.js`
|
|
151
|
-
-
|
|
193
|
+
- Document-scoped numbering ID state (`createDynamicNumberingIdState`,
|
|
194
|
+
`reserveNextNumberingIdPair`), numbering payload remapping, and shared DOM
|
|
195
|
+
predicates. It no longer owns a merge.
|
|
196
|
+
- `services/numbering-allocation.js`
|
|
197
|
+
- The single place that creates, continues, merges and validates numbering
|
|
198
|
+
definitions. `allocateNumberingDefinition` builds a new `w:abstractNum` +
|
|
199
|
+
`w:num` (source levels copied, chosen levels redefined, start overrides)
|
|
200
|
+
from ids reserved through the document state; `allocateNumberingForReplacement`
|
|
201
|
+
holds the reuse-source-list policy (`continue-source`, `allocate`,
|
|
202
|
+
`passthrough`) so no call site decides it; `continueBatchListSequence` lets
|
|
203
|
+
separate operations of one batch that generate items of the same kind,
|
|
204
|
+
format and level continue one numbering instance (reused only while its
|
|
205
|
+
`numId` is still bound in the live document). `mergeNumberingParts` /
|
|
206
|
+
`mergeNumberingXmlBySchemaOrder` are the one numbering merge, used by the
|
|
207
|
+
runner's consumers and the `openDocx` facade; an incoming `w:abstractNum` /
|
|
208
|
+
`w:num` id that exists with different content throws `NUMBERING_ID_CONFLICT`.
|
|
209
|
+
`checkNumberingBinding` validates a direct `{ numId, level }` binding and
|
|
210
|
+
`validateNumberingIntegrity` reports dangling `numId`, `abstractNumId` and
|
|
211
|
+
`ilvl` (`NUMBERING_*` issues) for the facade's baseline-delta validation.
|
|
212
|
+
Old definitions are never deleted or overwritten, and tracked-deleted source
|
|
213
|
+
paragraphs keep their `numPr`.
|
|
214
|
+
- `services/list-conversion-diagnostics.js`
|
|
215
|
+
- Safety diagnostics for text edits that retype list markers
|
|
216
|
+
(`LIST_MARKER_NOT_BOUND` / `UNSUPPORTED_LIST_CONVERSION`,
|
|
217
|
+
`LIST_FORMAT_NOT_APPLIED` / `UNSUPPORTED_LIST_FORMAT_CHANGE`; warning by
|
|
218
|
+
default, error under `strictListConversion`, silenced by
|
|
219
|
+
`listMarkers: 'literal'`), the closed `paragraph-format` key set (unknown
|
|
220
|
+
keys are `INVALID_OPERATION`) and the `numbering` shape check behind
|
|
221
|
+
`paragraph-format` numbering binding. Recovery points at `list-format`
|
|
222
|
+
through `recovery.suggestedOperation`.
|
|
152
223
|
- `services/standalone-docx-plumbing.js`
|
|
153
224
|
- Package-level extraction/wiring/validation for `word/document.xml`, `word/numbering.xml`, and `word/comments.xml`.
|
|
154
225
|
- `services/revision-comment-management.js`
|
|
@@ -160,7 +231,13 @@ No Word add-in entrypoints or host-specific integration layers are part of this
|
|
|
160
231
|
- Canonical single-operation validation, author resolution, dispatch, and
|
|
161
232
|
result metadata assembly. Before commit it validates the entire live
|
|
162
233
|
document against the operation savepoint and refuses newly generated
|
|
163
|
-
structural errors, including duplicate revision IDs.
|
|
234
|
+
structural errors, including duplicate revision IDs. For localized
|
|
235
|
+
`replacements` it also checks, before commit, that the target's accepted text
|
|
236
|
+
(read from the successor paragraph via `SourceTargetRegistry.previewSuccessor`,
|
|
237
|
+
or the restored paragraph) equals the compiled desired text; otherwise the
|
|
238
|
+
savepoint is restored and `PATCH_ROUNDTRIP_MISMATCH` is returned, because a
|
|
239
|
+
tracked whole-paragraph deletion rejects back to the source and the Reject
|
|
240
|
+
All verifier alone cannot see it.
|
|
164
241
|
- `services/document-operation-mutations.js`
|
|
165
242
|
- Coupled OOXML mutation implementations for redline, highlight, and comment
|
|
166
243
|
operations. For text-bearing edits, the resolved paragraph's exact
|
|
@@ -188,6 +265,50 @@ No Word add-in entrypoints or host-specific integration layers are part of this
|
|
|
188
265
|
- `services/document-operation-contract.js`
|
|
189
266
|
- Compatibility normalization, canonical operation kinds, author precedence,
|
|
190
267
|
and stable runtime validation for document operations.
|
|
268
|
+
- `services/list-format.js` and `services/list-format-mutation.js`
|
|
269
|
+
- The `list-format` operation (`convert-plain`, plus the shared request shape
|
|
270
|
+
for `change-format` and `join`): contract shape, the narrow
|
|
271
|
+
typed-marker grammar (letter versus roman disambiguation by sequence or an
|
|
272
|
+
explicit `format`), and the in-place DOM core. Every refusal is decided
|
|
273
|
+
before mutation; the binding reuses the `paragraph-format.numbering` path
|
|
274
|
+
(`snapshotAndAttachPPrChange` + `applyParagraphPropertiesToPPr`), the marker
|
|
275
|
+
becomes one tracked `w:del`, definitions come from
|
|
276
|
+
`allocateNumberingDefinition`, and batch continuity uses
|
|
277
|
+
`runtimeContext.listFallbackSequenceState` (an entry is reused only while
|
|
278
|
+
its `numId` is bound in the live document). Text-equal redline header
|
|
279
|
+
conversions for letters, roman numerals and bullets call the same core.
|
|
280
|
+
The `paragraph-format` numbering binding (`properties.numbering`,
|
|
281
|
+
`{ numId, level }` or `null`) lives in `document-operation-mutations.js`: it
|
|
282
|
+
snapshots the earliest same-author `w:pPrChange`, refuses another author's
|
|
283
|
+
pending snapshot (`PARAGRAPH_FORMAT_REVISION_CONFLICT`), and checks the
|
|
284
|
+
binding with `checkNumberingBinding`. `list-format` is body-only; `openDocx`
|
|
285
|
+
refuses it with a `part` selector.
|
|
286
|
+
- `services/list-format-change.js`
|
|
287
|
+
- `list-format` `change-format` and `join` (`scope: 'list'` or `'range'`): rebind existing list items with
|
|
288
|
+
one tracked `w:pPrChange` each, never editing a shared definition.
|
|
289
|
+
`change-format` allocates a new definition through
|
|
290
|
+
`allocateNumberingDefinition` (source levels copied, one redefined, start
|
|
291
|
+
values on the new abstract); `join` reuses the earlier list's `numId`.
|
|
292
|
+
Planning models Word's counters (shared abstracts continue each other, a
|
|
293
|
+
level start re-applies on restart, deeper items start unused levels) and
|
|
294
|
+
refuses splits, joins and style-linked or instance-overridden definitions
|
|
295
|
+
it cannot reproduce exactly. Definitions are read from the source part plus
|
|
296
|
+
the batch's pending numbering parts.
|
|
297
|
+
- `services/operation-batch-compiler.js`
|
|
298
|
+
- Binds every operation to batch-start source paragraphs
|
|
299
|
+
(`SourceTargetRegistry`), compiles localized `replacements`, and detects
|
|
300
|
+
overlap before any mutation. Composition rule for `redline` + `list-format`:
|
|
301
|
+
exactly one single-paragraph `redline` (no `targetEnd`, anchor, part or
|
|
302
|
+
structured content) that keeps the typed marker and changes the text after
|
|
303
|
+
it composes with one `list-format` on the same paragraph; the compiler fixes
|
|
304
|
+
the order by setting `_compiledRunAfter` on the list-format, which the batch
|
|
305
|
+
orchestrator honours, so the redline always runs first. Everything else on a
|
|
306
|
+
list-format target is refused with `LIST_FORMAT_COMPOSITION_CONFLICT`
|
|
307
|
+
(`reason`: `marker-changed`, `redline-unchanged`, `redline-shape`, or
|
|
308
|
+
`list-rebind` when a `scope: 'list'` `change-format`/`join` rebinds an item
|
|
309
|
+
that another operation also writes). `list.continueFrom` is bound at batch
|
|
310
|
+
start as a read-only target. `previewSuccessor` lets the applier find a
|
|
311
|
+
target's replacement paragraph before commit.
|
|
191
312
|
- `services/operation-preflight.js`
|
|
192
313
|
- Read-only strict target and anchor resolution, revision-policy diagnostics,
|
|
193
314
|
artifact prediction, and same-paragraph conflict reporting.
|
|
@@ -213,6 +334,42 @@ No Word add-in entrypoints or host-specific integration layers are part of this
|
|
|
213
334
|
Mutation commands expose a compact contract: package/XML payloads and full
|
|
214
335
|
validation arrays remain internal, while stdout contains durability fields,
|
|
215
336
|
per-operation evidence, validation counts, and a derived completion flag.
|
|
337
|
+
- `services/revision-fidelity-verifier.js`
|
|
338
|
+
- Post-apply invariant check built on `core/word-revision-semantics.js`.
|
|
339
|
+
`verifyRevisionFidelity` compares Reject All of the output with Reject All
|
|
340
|
+
of the savepoint (both reject every author's revisions) and reports
|
|
341
|
+
`REJECT_PARAGRAPH_COUNT`, `REJECT_PARAGRAPH_TEXT`, `REJECT_PARAGRAPH_PROPS`,
|
|
342
|
+
`REJECT_NUMBERING_REFS` and `REJECT_WRAPPERS`. Under accept-first
|
|
343
|
+
existing-revision policies the baseline is the accepted view, scoped to the
|
|
344
|
+
resolved target range when known (otherwise the changed region between the
|
|
345
|
+
unchanged prefix and suffix). `REJECT_NUMBERING_REFS`
|
|
346
|
+
(`verifyNumberingReferences`) also refuses a numId that the output binds or
|
|
347
|
+
Reject All restores when the source did not use it and no `w:num` ->
|
|
348
|
+
`w:abstractNum` -> `w:lvl` defines it in the numbering available to the
|
|
349
|
+
operation (numbering existence). `verifyUntrackedLocality` covers
|
|
350
|
+
`generateRedlines: false` single-target operations with `ACCEPT_NEIGHBORS`:
|
|
351
|
+
no paragraph outside the target may change in either view.
|
|
352
|
+
`verifyNoCreatedRevisions` adds `UNTRACKED_CREATED_REVISION`: an untracked
|
|
353
|
+
operation may not introduce a revision id that was not in the source
|
|
354
|
+
(fragments of a sliced source revision, same element, author and date, are
|
|
355
|
+
allowed). `verifyAcceptIntent` adds `ACCEPT_INTENT`: a tracked plain-text
|
|
356
|
+
`redline` with complete `modified` (single paragraph or `targetEnd` range)
|
|
357
|
+
must read as `modified` in the Accept All view of its target; accept-first
|
|
358
|
+
range targets use the exact accepted scope.
|
|
359
|
+
`buildRevisionFidelityError` produces the `REVISION_FIDELITY_VIOLATION`
|
|
360
|
+
payload (`violations[].explanation`, `source.sourceParagraphIndex`,
|
|
361
|
+
`recovery.retryGuidance`). Modes are `enforce` (default, refuse and roll
|
|
362
|
+
back), `warn` (apply and append a warning) and `off`, resolved by
|
|
363
|
+
`resolveRevisionFidelityMode`: explicit `verifyRevisionFidelity` option,
|
|
364
|
+
then the diagnostic `DOCX_REDLINE_REVISION_FIDELITY` environment variable,
|
|
365
|
+
then `enforce`. The view memo is `createFidelityViews(document)`: lazily
|
|
366
|
+
filled `accepted` / `rejected` projections, revision-id signatures and
|
|
367
|
+
numbering references for one DOM. The applier builds a memo for the savepoint
|
|
368
|
+
(taking over `session._fidelityViews` when it still describes the live
|
|
369
|
+
document) and one for the result; after a committed tracked or untracked
|
|
370
|
+
operation the result's memo is stored back in `session._fidelityViews` as
|
|
371
|
+
the next operation's baseline, and a refused operation restores the prior
|
|
372
|
+
memo, so each view is computed at most once per DOM.
|
|
216
373
|
- `orchestration/*`
|
|
217
374
|
- Route planning and list fallback orchestration utilities.
|
|
218
375
|
|
|
@@ -221,15 +378,25 @@ No Word add-in entrypoints or host-specific integration layers are part of this
|
|
|
221
378
|
1. Caller imports from `index.js`.
|
|
222
379
|
2. Caller configures XML provider/logger/defaults when needed via `adapters/*`.
|
|
223
380
|
3. Caller invokes reconciliation APIs (`applyRedlineToOxml`, operation runner, ingestion/export helpers).
|
|
224
|
-
4. A full-document batch parses once, captures its initial target snapshot,
|
|
225
|
-
|
|
381
|
+
4. A full-document batch parses once, captures its initial target snapshot,
|
|
382
|
+
compiles the operations against it (`operation-batch-compiler.js`: batch-start
|
|
383
|
+
source binding, localized replacements, overlap and list-format composition
|
|
384
|
+
checks, all before any mutation), and creates an operation savepoint before
|
|
385
|
+
each mutation.
|
|
226
386
|
5. `engine/oxml-engine.js` routes each selected scope to format, table, list,
|
|
227
387
|
surgical, or reconstruction flows; successful scoped output is imported
|
|
228
388
|
into the live document.
|
|
229
|
-
6.
|
|
389
|
+
6. After each mutation the applier (`services/document-operation-applier.js`)
|
|
390
|
+
validates the generated OOXML against the savepoint, checks the localized
|
|
391
|
+
replacement intent, then runs the revision fidelity verifier (Reject All,
|
|
392
|
+
Accept All intent, neighbor, created-revision and numbering-existence
|
|
393
|
+
invariants); a violation in `enforce` mode restores the savepoint and
|
|
394
|
+
refuses the operation before anything is committed. Failed and no-op
|
|
395
|
+
operations restore their savepoint. A successful changed
|
|
230
396
|
batch serializes the full document once; atomic failures and all-no-op
|
|
231
397
|
batches return the exact input string without serialization.
|
|
232
|
-
7. Pipeline/services return OOXML, optional package artifacts (`numberingXml`, comments payloads
|
|
398
|
+
7. Pipeline/services return OOXML, optional package artifacts (`numberingXml`, comments payloads; numbering parts are merged by `mergeNumberingParts` and
|
|
399
|
+
checked by `validateNumberingIntegrity`), and non-breaking `status`/`error` fields where applicable.
|
|
233
400
|
8. Optional revision/comment management transforms can accept/reject revisions, including move revisions, or delete comments by author.
|
|
234
401
|
9. Caller writes resulting XML back to package/document boundaries.
|
|
235
402
|
|
|
@@ -265,6 +432,28 @@ still be re-exported from `index.js`.
|
|
|
265
432
|
`COMMENTED_CONTENT_MERGE`; never discard anchors as a side effect of restoring
|
|
266
433
|
the pre-revision baseline.
|
|
267
434
|
Pass `existingRevisions: 'accept-all-first'` to normalize prior revisions explicitly.
|
|
435
|
+
- Every operation is checked after it is applied
|
|
436
|
+
(`services/revision-fidelity-verifier.js`, default `enforce`): Word's Reject
|
|
437
|
+
All of a tracked output must equal Word's Reject All of the source (`REJECT_*`),
|
|
438
|
+
a plain-text `redline` must read as its `modified` text under Accept All
|
|
439
|
+
(`ACCEPT_INTENT`), and an untracked edit must neither change other paragraphs
|
|
440
|
+
(`ACCEPT_NEIGHBORS`) nor create a revision (`UNTRACKED_CREATED_REVISION`). A
|
|
441
|
+
violation restores the operation savepoint and returns
|
|
442
|
+
`REVISION_FIDELITY_VIOLATION`; `warn` applies and warns, `off` is for
|
|
443
|
+
diagnosis only.
|
|
444
|
+
- Allocate, continue, merge and validate numbering only through
|
|
445
|
+
`services/numbering-allocation.js`. Never edit a shared `w:abstractNum` or
|
|
446
|
+
`w:num` in place, never delete a definition Reject All may need, and keep
|
|
447
|
+
`numPr` on tracked-deleted source paragraphs.
|
|
448
|
+
- Construct paragraph-mark `w:ins` / `w:del` only through
|
|
449
|
+
`engine/paragraph-mark-revisions.js`, and read current paragraph/run
|
|
450
|
+
properties only through `core/current-properties.js`. Two source-scanning
|
|
451
|
+
tests enforce this: `tests/paragraph_mark_single_site_tests.mjs` rejects
|
|
452
|
+
paragraph-mark revision construction (templates opening an `rPr` with
|
|
453
|
+
`ins`/`del`, DOM creation attached to an `rPr`, retired helper names) outside
|
|
454
|
+
the helper, and `tests/current_properties_usage_tests.mjs` rejects descendant
|
|
455
|
+
lookups of property names (`numPr`, `pStyle`, `b`, ...) outside the accessor.
|
|
456
|
+
Exceptions need an entry with a written reason in each test's allowlist.
|
|
268
457
|
- Do not write unknown `result.oxml` payloads directly into `word/document.xml`;
|
|
269
458
|
normalize with `extractReplacementNodesFromOoxml(...)` or use
|
|
270
459
|
`applyOperationToDocumentXml(...).documentXml` for full-document replacement.
|
|
@@ -339,8 +528,10 @@ still be re-exported from `index.js`.
|
|
|
339
528
|
- Comment IDs must be allocated against both document anchors and the existing
|
|
340
529
|
`word/comments.xml` part. Revision IDs must be allocated against the complete
|
|
341
530
|
document revision scope.
|
|
342
|
-
- Numbering payloads
|
|
343
|
-
|
|
531
|
+
- Numbering payloads are merged, never replaced, by the single merge in
|
|
532
|
+
`services/numbering-allocation.js` (`mergeNumberingParts`), which both the
|
|
533
|
+
runner's consumers and the `openDocx` facade call; conflicting ids fail with
|
|
534
|
+
`NUMBERING_ID_CONFLICT`.
|
|
344
535
|
- Safe package mutation is transactional: retain the original package, apply
|
|
345
536
|
operations, merge all artifacts, validate redline markup and package wiring,
|
|
346
537
|
and commit only if every required check succeeds.
|
|
@@ -370,7 +561,7 @@ still be re-exported from `index.js`.
|
|
|
370
561
|
text-bearing mutation. Mutation uses canonical accepted-view source text, and `resolvedTarget.targetTextMatch`
|
|
371
562
|
records `exact`, `space_equivalent`, or `normalized` selection plus bounded
|
|
372
563
|
invisible-character diagnostics.
|
|
373
|
-
- CLI contract version
|
|
564
|
+
- The CLI contract (version 9; `docx-redline version` lists the capabilities) is deliberately narrower than library result objects.
|
|
374
565
|
`apply`, `accept`, `reject`, and `delete-comments` omit `documentXml`, package
|
|
375
566
|
parts, inspection text, and full issue arrays. `completion` is true only when
|
|
376
567
|
`written === true`, top-level status is neither error nor partial, and every
|
|
@@ -400,6 +591,10 @@ still be re-exported from `index.js`.
|
|
|
400
591
|
is parsed from the serialized output XML parts (`word/document.xml`, `word/comments.xml`,
|
|
401
592
|
`word/numbering.xml`). Any discrepancy immediately fails the transaction and triggers
|
|
402
593
|
atomic rollback.
|
|
594
|
+
- The oracle checks that durable IDs are committed; the revision fidelity
|
|
595
|
+
verifier checks what Reject All would restore. A refused operation restores
|
|
596
|
+
its savepoint and receipt state like any other refusal, so it contributes no
|
|
597
|
+
committed IDs (`finalDisposition: 'refused'`).
|
|
403
598
|
|
|
404
599
|
|
|
405
600
|
## Build Output
|
|
@@ -437,11 +632,21 @@ The bundle inlines `diff-match-patch` and keeps `@xmldom/xmldom` external.
|
|
|
437
632
|
- `npm run smoke:word:diff`
|
|
438
633
|
- Windows/Word COM differential test: Word itself accepts/rejects the
|
|
439
634
|
generated fixtures and the resulting text is compared to expectations.
|
|
635
|
+
Structural checks also compare paragraph counts, and list cases compare
|
|
636
|
+
`ListFormat.ListString` labels after `Revisions.AcceptAll()` /
|
|
637
|
+
`RejectAll()`.
|
|
440
638
|
- `bash scripts/validate-fixtures-xsd.sh`
|
|
441
639
|
- Validates exported fixtures against the ECMA-376 transitional `wml.xsd`.
|
|
640
|
+
- `tests/reject_roundtrip_matrix_tests.mjs` (part of `npm test`)
|
|
641
|
+
- Generated operation matrix over fixtures and operation kinds, asserting the
|
|
642
|
+
revision fidelity invariants and receipt reconciliation (a
|
|
643
|
+
`RECEIPT_RECONCILIATION_FAILED` fails the case). Replay with `FUZZ_SEED` /
|
|
644
|
+
`MATRIX_ITERATIONS`.
|
|
442
645
|
- `.github/workflows/validation.yml`
|
|
443
646
|
- Nightly independent-oracle validation: XSD schema check, LibreOffice
|
|
444
|
-
conversion,
|
|
647
|
+
conversion, an extended 20k-case fuzz sweep with a fresh seed, and the
|
|
648
|
+
`matrix-extended` job (1000 reject-roundtrip matrix cases with a
|
|
649
|
+
date-derived seed; a failure prints its seed and replay command).
|
|
445
650
|
|
|
446
651
|
Use these checks before publishing or tagging. See [docs/TESTING.md](./docs/TESTING.md#release-validation-and-independent-oracles).
|
|
447
652
|
|
|
@@ -454,7 +659,11 @@ Use this sequence to understand or modify behavior without reading everything:
|
|
|
454
659
|
3. For targeting bugs, inspect `core/paragraph-targeting.js`, `core/list-targeting.js`, and `core/table-targeting.js`.
|
|
455
660
|
4. For package wiring issues, inspect `services/standalone-docx-plumbing.js`.
|
|
456
661
|
5. For revision/comment cleanup behavior, inspect `services/revision-comment-management.js`.
|
|
457
|
-
6. For numbering/list issues, inspect `services/numbering-
|
|
662
|
+
6. For numbering/list issues, inspect `services/numbering-allocation.js`,
|
|
663
|
+
`services/list-format*.js`, `services/list-conversion-diagnostics.js` and
|
|
664
|
+
orchestration list-fallback modules; for batch composition,
|
|
665
|
+
`services/operation-batch-compiler.js`; for Reject All refusals,
|
|
666
|
+
`services/revision-fidelity-verifier.js`.
|
|
458
667
|
7. For reliability regressions, start with `tests/roundtrip_invariant_tests.mjs`,
|
|
459
668
|
`tests/engine_reliability_tests.mjs`, `tests/paragraph_mark_revision_tests.mjs`,
|
|
460
669
|
`tests/move_revision_tests.mjs`, and `tests/hardening_status_tests.mjs`.
|