@ansonlai/docx-redline-js 0.8.4 → 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 +176 -0
- package/README.md +125 -12
- 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 +4189 -767
- package/dist/docx-redline-js.esm.js.map +4 -4
- package/dist/docx-redline-js.esm.min.js +111 -108
- package/dist/docx-redline-js.esm.min.js.map +4 -4
- package/dist/docx-redline.bundle.cjs +4292 -870
- package/dist/docx-redline.bundle.cjs.map +4 -4
- package/dist/docx-redline.bundle.js +4292 -870
- package/dist/docx-redline.bundle.js.map +4 -4
- package/docs/AGENT_FAST_START.md +2 -0
- package/docs/AGENT_KNOWLEDGE_BASE.md +19 -3
- package/docs/SKILL_AUTHORING.md +165 -150
- package/docs/TESTING.md +1142 -1059
- package/docs/schemas/document-operations.schema.json +54 -1
- package/document/docx-document.js +1022 -1010
- package/engine/oxml-engine.js +736 -749
- package/engine/paragraph-mark-revisions.js +292 -0
- package/engine/reconstruction-mapper.js +312 -311
- 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 +47 -1
- package/index.js +11 -2
- package/node/cli-help.js +1 -0
- package/node/cli.js +992 -975
- 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/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 +23 -3
- package/services/capture-engine.js +228 -226
- package/services/document-operation-applier.js +213 -0
- package/services/document-operation-contract.js +75 -0
- package/services/document-operation-mutations.js +3346 -2721
- 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 +183 -11
- package/services/operation-preflight.js +1 -0
- package/services/receipt-collector.js +288 -288
- package/services/revision-comment-management.js +38 -5
- package/services/revision-fidelity-verifier.js +498 -0
- package/services/standalone-docx-plumbing.js +627 -631
- package/services/standalone-operation-runner.d.ts +182 -5
- package/services/table-reconciliation.js +59 -7
|
@@ -87,6 +87,55 @@
|
|
|
87
87
|
}
|
|
88
88
|
]
|
|
89
89
|
},
|
|
90
|
+
"paragraphFormatProperties": {
|
|
91
|
+
"description": "Closed set. Unknown keys are rejected with INVALID_OPERATION (field properties.<key>) since 0.9.0.",
|
|
92
|
+
"type": "object",
|
|
93
|
+
"properties": {
|
|
94
|
+
"alignment": { "type": "string", "examples": ["left", "center", "right", "both"] },
|
|
95
|
+
"keepNext": { "type": "boolean" },
|
|
96
|
+
"keepLines": { "type": "boolean" },
|
|
97
|
+
"pageBreakBefore": { "type": "boolean" },
|
|
98
|
+
"style": { "type": "string", "description": "Paragraph style id (w:pStyle)." },
|
|
99
|
+
"numbering": {
|
|
100
|
+
"description": "Direct list binding recorded as a tracked w:pPrChange. An object binds the paragraph to an EXISTING numId at a level; null removes the direct binding. Never allocates a list. Refused with PARAGRAPH_NUMBERING_NOT_FOUND when the numId or level is not defined.",
|
|
101
|
+
"oneOf": [
|
|
102
|
+
{ "type": "null" },
|
|
103
|
+
{
|
|
104
|
+
"type": "object",
|
|
105
|
+
"required": ["numId"],
|
|
106
|
+
"properties": {
|
|
107
|
+
"numId": { "oneOf": [ { "type": "integer", "minimum": 1 }, { "type": "string", "pattern": "^[1-9][0-9]*$" } ] },
|
|
108
|
+
"level": { "type": "integer", "minimum": 0, "maximum": 8, "default": 0 }
|
|
109
|
+
},
|
|
110
|
+
"additionalProperties": false
|
|
111
|
+
}
|
|
112
|
+
]
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
"additionalProperties": false
|
|
116
|
+
},
|
|
117
|
+
"listFormat": {
|
|
118
|
+
"description": "list-format-v1 (CLI contract version 9). convert-plain binds plain paragraphs to a NEW list definition in place: the binding is a tracked w:pPrChange and, with strip \"marker\" (default), the typed marker (A. / 1. / 1) / iv. / - ) is removed with a tracked deletion; Reject All restores the literal marker and the unnumbered paragraph. Each marker's value is the item's start value; consecutive values share one list, and a later convert-plain in the same batch whose first value continues the previous one joins that list. Refusals: LIST_MARKER_NOT_FOUND, LIST_MARKER_AMBIGUOUS (single roman-looking letter such as I. or C.; set format), LIST_MARKER_UNSUPPORTED (mixed markers, multi-level 2.1., (a), marker not in plain runs, format mismatch), LIST_FORMAT_TARGET_IS_LIST, LIST_FORMAT_STYLE_NUMBERED, PARAGRAPH_FORMAT_REVISION_CONFLICT. change-format and join (capability list-format-change-v1, same contract version): change-format allocates a NEW abstractNum + num copying the source definition (levels, indentation, fonts) with only the requested level redefined, and rebinds the list items to it with one tracked w:pPrChange each; the shared definition is never edited in place, so Reject All restores the original labels and Accept All shows the new ones. join rebinds the target list to the numId of list.continueFrom (an earlier list) so it continues that count. Tracked-deleted paragraphs keep their numPr. Refusals: LIST_FORMAT_TARGET_NOT_LIST, LIST_FORMAT_MIXED_RANGE (non-list paragraphs, several lists, several levels), LIST_FORMAT_STYLE_LINKED, LIST_FORMAT_STYLE_NUMBERED, LIST_FORMAT_SPLIT_UNSUPPORTED (mid-sequence range, nested restart, shared abstract definition, interleaved join), LIST_FORMAT_DEFINITION_UNSUPPORTED (missing definition, instance level override, lvlRestart in a split), LIST_FORMAT_JOIN_INVALID, PARAGRAPH_FORMAT_REVISION_CONFLICT; LIST_FORMAT_UNCHANGED is a warning on a no-op. Body only (no part). Composition: one single-paragraph redline/replace of the same paragraph may share the batch when it keeps the typed marker exactly (\"1. Old\" -> \"1. New\" = redline + convert-plain); the redline always runs first. scope \"list\" counts as a write to every rebound item. Other combinations fail LIST_FORMAT_COMPOSITION_CONFLICT. detach and materializeMarker are not available.",
|
|
119
|
+
"type": "object",
|
|
120
|
+
"required": ["mode"],
|
|
121
|
+
"properties": {
|
|
122
|
+
"mode": { "enum": ["convert-plain", "change-format", "join"] },
|
|
123
|
+
"kind": { "enum": ["bullet", "numbered"] },
|
|
124
|
+
"format": { "enum": ["decimal", "upperLetter", "lowerLetter", "upperRoman", "lowerRoman", "bullet"], "description": "convert-plain: required with strip \"none\"; with strip \"marker\" it must match the typed markers and disambiguates letters from roman numerals. change-format: the new numbering format of the level." },
|
|
125
|
+
"level": { "type": "integer", "minimum": 0, "maximum": 8, "description": "convert-plain: the level to bind (default 0). change-format: the level to redefine (default: the single level the target paragraphs use; refused LIST_FORMAT_MIXED_RANGE reason levels when they use several)." },
|
|
126
|
+
"strip": { "enum": ["marker", "none"], "default": "marker", "description": "convert-plain only. marker: remove the typed marker (tracked). none: keep the text and only bind." },
|
|
127
|
+
"start": { "type": "integer", "minimum": 1, "maximum": 32767, "description": "convert-plain: strip \"none\" only; defaults to continuing the batch's previous list of the same format, else 1 (with strip \"marker\" the start is the typed marker's value). change-format: restart value of the level, written as the w:start of the new definition (scope \"list\" only)." },
|
|
128
|
+
"lvlText": { "type": "string", "minLength": 1, "maxLength": 32, "description": "change-format only: the level text. Numbered: %1..%9 placeholders including the level's own (\"%1.\", \"(%2)\"); bullet: the bullet character. Default: the source level text when the kind stays, \"%<level+1>.\" for bullet -> numbered, \"•\" for numbered -> bullet." },
|
|
129
|
+
"scope": { "enum": ["list", "range"], "default": "list", "description": "change-format and join. list: every live paragraph of the target's list is rebound (paragraphs outside the target range included; result items carry inTarget). range: only the target range, which must run to the end of its list (LIST_FORMAT_SPLIT_UNSUPPORTED reason mid-sequence otherwise); change-format continues the count with per-level start values on the new definition." },
|
|
130
|
+
"continueFrom": { "$ref": "#/$defs/target", "description": "join only (required): an item of the earlier list the target list continues; bound at batch start like target." }
|
|
131
|
+
},
|
|
132
|
+
"allOf": [
|
|
133
|
+
{ "if": { "properties": { "mode": { "const": "convert-plain" } } }, "then": { "not": { "anyOf": [ { "required": ["lvlText"] }, { "required": ["scope"] }, { "required": ["continueFrom"] } ] } } },
|
|
134
|
+
{ "if": { "properties": { "mode": { "const": "change-format" } } }, "then": { "anyOf": [ { "required": ["format"] }, { "required": ["kind"] }, { "required": ["lvlText"] }, { "required": ["start"] } ], "not": { "anyOf": [ { "required": ["strip"] }, { "required": ["continueFrom"] } ] } } },
|
|
135
|
+
{ "if": { "properties": { "mode": { "const": "join" } } }, "then": { "required": ["continueFrom"], "not": { "anyOf": [ { "required": ["kind"] }, { "required": ["format"] }, { "required": ["level"] }, { "required": ["strip"] }, { "required": ["start"] }, { "required": ["lvlText"] } ] } } }
|
|
136
|
+
],
|
|
137
|
+
"additionalProperties": false
|
|
138
|
+
},
|
|
90
139
|
"base": {
|
|
91
140
|
"type": "object",
|
|
92
141
|
"required": ["type", "target"],
|
|
@@ -98,6 +147,7 @@
|
|
|
98
147
|
"author": { "type": "string", "minLength": 1 }, "generateRedlines": { "type": "boolean" },
|
|
99
148
|
"existingRevisions": { "enum": ["merge-same-author", "slice-cross-author", "reject-input", "accept-all-first", "accept-all-first-keep-normalized"] },
|
|
100
149
|
"pairReplacements": { "type": "boolean" },
|
|
150
|
+
"listMarkers": { "const": "literal", "description": "Accepts list-marker text as literal text. Suppresses LIST_MARKER_NOT_BOUND / UNSUPPORTED_LIST_CONVERSION and LIST_FORMAT_NOT_APPLIED / UNSUPPORTED_LIST_FORMAT_CHANGE for this operation." },
|
|
101
151
|
"insertionAffinity": {
|
|
102
152
|
"type": "object",
|
|
103
153
|
"properties": {
|
|
@@ -160,7 +210,10 @@
|
|
|
160
210
|
"allOf": [ { "$ref": "#/$defs/base" }, { "type": "object", "required": ["textToFormat", "properties"], "properties": { "type": { "enum": ["format", "character-format"] }, "textToFormat": { "type": "string", "minLength": 1 }, "textOccurrence": { "type": "integer", "minimum": 1, "default": 1 }, "properties": { "type": "object" }, "formattingRevisionPolicy": { "enum": ["always", "coalesce-own-insertion"] } } } ]
|
|
161
211
|
},
|
|
162
212
|
{
|
|
163
|
-
"allOf": [ { "$ref": "#/$defs/base" }, { "type": "object", "required": ["
|
|
213
|
+
"allOf": [ { "$ref": "#/$defs/base" }, { "type": "object", "required": ["list"], "not": { "anyOf": [ { "required": ["part"] }, { "required": ["modified"] }, { "required": ["replacements"] } ] }, "properties": { "type": { "const": "list-format" }, "list": { "$ref": "#/$defs/listFormat" }, "targetEnd": { "$ref": "#/$defs/target" }, "targetEndRef": { "type": ["integer", "string", "null"] } } } ]
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
"allOf": [ { "$ref": "#/$defs/base" }, { "type": "object", "required": ["properties"], "properties": { "type": { "const": "paragraph-format" }, "properties": { "$ref": "#/$defs/paragraphFormatProperties" } } } ]
|
|
164
217
|
}
|
|
165
218
|
]
|
|
166
219
|
}
|