@ansonlai/docx-redline-js 0.8.2 → 0.8.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/CHANGELOG.md +75 -1
- package/README.md +28 -13
- package/core/list-targeting.js +12 -10
- package/dist/docx-redline-js.esm.js +837 -549
- package/dist/docx-redline-js.esm.js.map +4 -4
- package/dist/docx-redline-js.esm.min.js +93 -90
- package/dist/docx-redline-js.esm.min.js.map +4 -4
- package/dist/docx-redline.bundle.cjs +837 -549
- package/dist/docx-redline.bundle.cjs.map +4 -4
- package/dist/docx-redline.bundle.js +837 -549
- package/dist/docx-redline.bundle.js.map +4 -4
- package/docs/AGENT_KNOWLEDGE_BASE.md +4 -1
- package/docs/schemas/document-operations.schema.json +168 -168
- package/engine/oxml-engine.js +215 -195
- package/engine/reconstruction-mode.js +183 -183
- package/index.d.ts +4 -0
- package/index.js +36 -1
- package/node/cli.js +2 -1
- package/orchestration/list-structural-fallback.js +530 -518
- package/package.json +1 -1
- package/pipeline/list-generation.js +203 -168
- package/pipeline/serialization.js +111 -94
- package/services/batch-operation-orchestrator.js +6 -0
- package/services/document-inspection.js +10 -7
- package/services/document-operation-applier.js +2 -0
- package/services/document-operation-contract.js +553 -537
- package/services/document-operation-mutations.js +1140 -1011
- package/services/numbering-helpers.js +108 -0
- package/services/operation-batch-compiler.js +440 -436
- package/services/operation-heuristics.js +197 -173
- package/services/revision-comment-management.js +601 -594
- package/services/standalone-operation-runner.d.ts +429 -427
- package/services/table-reconciliation.js +48 -46
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
* Converts patched run model back to OOXML with track changes.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { RunKind, escapeXml, createRevisionMetadata } from '../core/types.js';
|
|
8
|
-
import { getApplicableFormatHints } from './markdown-processor.js';
|
|
9
|
-
import { serializeXml } from '../adapters/xml-adapter.js';
|
|
10
|
-
import { warn } from '../adapters/logger.js';
|
|
11
|
-
import { buildDocumentFragmentPackage } from '../services/package-builder.js';
|
|
12
|
-
import { getDefaultAuthor } from '../adapters/config.js';
|
|
13
|
-
|
|
14
|
-
const XMLNS_ATTR_REGEX = /\s+xmlns:[^=]+="[^"]*"/g;
|
|
7
|
+
import { RunKind, escapeXml, createRevisionMetadata } from '../core/types.js';
|
|
8
|
+
import { getApplicableFormatHints } from './markdown-processor.js';
|
|
9
|
+
import { serializeXml } from '../adapters/xml-adapter.js';
|
|
10
|
+
import { warn } from '../adapters/logger.js';
|
|
11
|
+
import { buildDocumentFragmentPackage } from '../services/package-builder.js';
|
|
12
|
+
import { getDefaultAuthor } from '../adapters/config.js';
|
|
13
|
+
|
|
14
|
+
const XMLNS_ATTR_REGEX = /\s+xmlns:[^=]+="[^"]*"/g;
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Serializes a patched run model to OOXML.
|
|
@@ -22,48 +22,48 @@ const XMLNS_ATTR_REGEX = /\s+xmlns:[^=]+="[^"]*"/g;
|
|
|
22
22
|
* @param {import('../core/types.js').SerializationOptions} [options={}] - Serialization options
|
|
23
23
|
* @returns {string} OOXML paragraph string (WITHOUT namespace - added by wrapper)
|
|
24
24
|
*/
|
|
25
|
-
export function serializeToOoxml(patchedModel, pPr, formatHints = [], options = {}) {
|
|
26
|
-
const serializationOptions = normalizeSerializationOptions(options);
|
|
27
|
-
const { generateRedlines } = serializationOptions;
|
|
28
|
-
const paragraphs = [];
|
|
29
|
-
let currentPPrXml = '';
|
|
30
|
-
let currentPPrElement = null;
|
|
31
|
-
let currentRuns = [];
|
|
25
|
+
export function serializeToOoxml(patchedModel, pPr, formatHints = [], options = {}) {
|
|
26
|
+
const serializationOptions = normalizeSerializationOptions(options);
|
|
27
|
+
const { generateRedlines } = serializationOptions;
|
|
28
|
+
const paragraphs = [];
|
|
29
|
+
let currentPPrXml = '';
|
|
30
|
+
let currentPPrElement = null;
|
|
31
|
+
let currentRuns = [];
|
|
32
32
|
|
|
33
33
|
// Helper to flush accumulated runs into a paragraph
|
|
34
34
|
function flushParagraph() {
|
|
35
35
|
if (currentRuns.length > 0 || paragraphs.length === 0) {
|
|
36
36
|
// Build paragraph properties - handle both string and DOM element
|
|
37
|
-
let pPrContent = '';
|
|
38
|
-
if (currentPPrXml) {
|
|
39
|
-
pPrContent = stripNamespaceDeclarations(currentPPrXml);
|
|
40
|
-
} else if (currentPPrElement) {
|
|
41
|
-
currentPPrXml = stripNamespaceDeclarations(serializeXml(currentPPrElement));
|
|
42
|
-
pPrContent = currentPPrXml;
|
|
43
|
-
} else if (pPr) {
|
|
44
|
-
// Fallback to legacy pPr if no PARAGRAPH_START was seen
|
|
45
|
-
if (typeof pPr === 'string') {
|
|
46
|
-
pPrContent = pPr;
|
|
47
|
-
} else {
|
|
48
|
-
pPrContent = serializeXml(pPr);
|
|
49
|
-
}
|
|
50
|
-
pPrContent = stripNamespaceDeclarations(pPrContent);
|
|
51
|
-
}
|
|
52
|
-
paragraphs.push(`<w:p>${pPrContent}${currentRuns.join('')}</w:p>`);
|
|
53
|
-
currentRuns = [];
|
|
54
|
-
}
|
|
37
|
+
let pPrContent = '';
|
|
38
|
+
if (currentPPrXml) {
|
|
39
|
+
pPrContent = stripNamespaceDeclarations(currentPPrXml);
|
|
40
|
+
} else if (currentPPrElement) {
|
|
41
|
+
currentPPrXml = stripNamespaceDeclarations(serializeXml(currentPPrElement));
|
|
42
|
+
pPrContent = currentPPrXml;
|
|
43
|
+
} else if (pPr) {
|
|
44
|
+
// Fallback to legacy pPr if no PARAGRAPH_START was seen
|
|
45
|
+
if (typeof pPr === 'string') {
|
|
46
|
+
pPrContent = pPr;
|
|
47
|
+
} else {
|
|
48
|
+
pPrContent = serializeXml(pPr);
|
|
49
|
+
}
|
|
50
|
+
pPrContent = stripNamespaceDeclarations(pPrContent);
|
|
51
|
+
}
|
|
52
|
+
paragraphs.push(`<w:p>${pPrContent}${currentRuns.join('')}</w:p>`);
|
|
53
|
+
currentRuns = [];
|
|
54
|
+
}
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
for (const item of patchedModel) {
|
|
58
58
|
switch (item.kind) {
|
|
59
59
|
case RunKind.PARAGRAPH_START:
|
|
60
60
|
// Flush previous paragraph before starting a new one
|
|
61
|
-
if (currentRuns.length > 0 || paragraphs.length > 0) {
|
|
62
|
-
flushParagraph();
|
|
63
|
-
}
|
|
64
|
-
currentPPrXml = item.pPrXml || '';
|
|
65
|
-
currentPPrElement = item.pPrElement || null;
|
|
66
|
-
break;
|
|
61
|
+
if (currentRuns.length > 0 || paragraphs.length > 0) {
|
|
62
|
+
flushParagraph();
|
|
63
|
+
}
|
|
64
|
+
currentPPrXml = item.pPrXml || '';
|
|
65
|
+
currentPPrElement = item.pPrElement || null;
|
|
66
|
+
break;
|
|
67
67
|
|
|
68
68
|
case RunKind.TEXT:
|
|
69
69
|
currentRuns.push(buildRunXmlWithHints(item, formatHints, serializationOptions));
|
|
@@ -87,11 +87,11 @@ export function serializeToOoxml(patchedModel, pPr, formatHints = [], options =
|
|
|
87
87
|
|
|
88
88
|
case RunKind.BOOKMARK:
|
|
89
89
|
case RunKind.HYPERLINK:
|
|
90
|
-
// Pass through original XML - but strip any namespace declarations
|
|
91
|
-
if (item.nodeXml) {
|
|
92
|
-
currentRuns.push(stripNamespaceDeclarations(item.nodeXml));
|
|
93
|
-
}
|
|
94
|
-
break;
|
|
90
|
+
// Pass through original XML - but strip any namespace declarations
|
|
91
|
+
if (item.nodeXml) {
|
|
92
|
+
currentRuns.push(stripNamespaceDeclarations(item.nodeXml));
|
|
93
|
+
}
|
|
94
|
+
break;
|
|
95
95
|
|
|
96
96
|
case RunKind.CONTAINER_START:
|
|
97
97
|
if (item.containerKind === 'sdt') {
|
|
@@ -134,29 +134,29 @@ export function serializeToOoxml(patchedModel, pPr, formatHints = [], options =
|
|
|
134
134
|
* @param {import('../core/types.js').SerializationOptions|string|undefined|null} options - Raw options
|
|
135
135
|
* @returns {import('../core/types.js').SerializationOptions}
|
|
136
136
|
*/
|
|
137
|
-
function normalizeSerializationOptions(options) {
|
|
138
|
-
// Backward compatibility: accept legacy `font` string signature.
|
|
139
|
-
if (typeof options === 'string') {
|
|
140
|
-
return {
|
|
141
|
-
author: getDefaultAuthor(),
|
|
142
|
-
generateRedlines: true,
|
|
143
|
-
font: options,
|
|
144
|
-
revisionIdAllocator: null
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
const normalized = options && typeof options === 'object' ? options : {};
|
|
149
|
-
const resolvedAuthor = typeof normalized.author === 'string' && normalized.author.trim()
|
|
150
|
-
? normalized.author.trim()
|
|
151
|
-
: getDefaultAuthor();
|
|
152
|
-
|
|
153
|
-
return {
|
|
154
|
-
author: resolvedAuthor,
|
|
155
|
-
generateRedlines: normalized.generateRedlines ?? true,
|
|
156
|
-
font: normalized.font ?? null,
|
|
157
|
-
revisionIdAllocator: normalized.revisionIdAllocator ?? null
|
|
158
|
-
};
|
|
159
|
-
}
|
|
137
|
+
function normalizeSerializationOptions(options) {
|
|
138
|
+
// Backward compatibility: accept legacy `font` string signature.
|
|
139
|
+
if (typeof options === 'string') {
|
|
140
|
+
return {
|
|
141
|
+
author: getDefaultAuthor(),
|
|
142
|
+
generateRedlines: true,
|
|
143
|
+
font: options,
|
|
144
|
+
revisionIdAllocator: null
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const normalized = options && typeof options === 'object' ? options : {};
|
|
149
|
+
const resolvedAuthor = typeof normalized.author === 'string' && normalized.author.trim()
|
|
150
|
+
? normalized.author.trim()
|
|
151
|
+
: getDefaultAuthor();
|
|
152
|
+
|
|
153
|
+
return {
|
|
154
|
+
author: resolvedAuthor,
|
|
155
|
+
generateRedlines: normalized.generateRedlines ?? true,
|
|
156
|
+
font: normalized.font ?? null,
|
|
157
|
+
revisionIdAllocator: normalized.revisionIdAllocator ?? null
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
160
|
|
|
161
161
|
/**
|
|
162
162
|
* Builds a run XML element, applying format hints if applicable.
|
|
@@ -166,10 +166,10 @@ function normalizeSerializationOptions(options) {
|
|
|
166
166
|
* @param {import('../core/types.js').SerializationOptions} options - Serialization options
|
|
167
167
|
* @returns {string}
|
|
168
168
|
*/
|
|
169
|
-
function buildRunXmlWithHints(item, formatHints, options = {}) {
|
|
170
|
-
const applicableHints = getApplicableFormatHints(formatHints, item.startOffset, item.endOffset);
|
|
171
|
-
const font = options?.font ?? null;
|
|
172
|
-
let cleanRPr = item.rPrXml ? stripNamespaceDeclarations(item.rPrXml) : '';
|
|
169
|
+
function buildRunXmlWithHints(item, formatHints, options = {}) {
|
|
170
|
+
const applicableHints = getApplicableFormatHints(formatHints, item.startOffset, item.endOffset);
|
|
171
|
+
const font = options?.font ?? null;
|
|
172
|
+
let cleanRPr = item.rPrXml ? stripNamespaceDeclarations(item.rPrXml) : '';
|
|
173
173
|
|
|
174
174
|
if (font) {
|
|
175
175
|
cleanRPr = applyFont(cleanRPr, font);
|
|
@@ -219,7 +219,24 @@ function buildRunXmlWithHints(item, formatHints, options = {}) {
|
|
|
219
219
|
function buildSimpleRun(text, rPrXml) {
|
|
220
220
|
if (!text) return '';
|
|
221
221
|
const rPr = rPrXml || '';
|
|
222
|
-
return `<w:r>${rPr}
|
|
222
|
+
return `<w:r>${rPr}${buildRunContent(text, 'w:t')}</w:r>`;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Builds run content, restoring in-run line breaks and tabs (ingested from
|
|
227
|
+
* w:br/w:cr/w:tab as "\n"/"\t") as elements; raw control characters inside
|
|
228
|
+
* w:t or w:delText render as spaces in Word.
|
|
229
|
+
*
|
|
230
|
+
* @param {string} text - Run text
|
|
231
|
+
* @param {'w:t'|'w:delText'} textTag - Text element name
|
|
232
|
+
* @returns {string}
|
|
233
|
+
*/
|
|
234
|
+
function buildRunContent(text, textTag) {
|
|
235
|
+
return String(text).split(/(\r\n|[\n\r\v\t])/).map(part => {
|
|
236
|
+
if (part === '\t') return '<w:tab/>';
|
|
237
|
+
if (part === '\n' || part === '\r' || part === '\r\n' || part === '\v') return '<w:br/>';
|
|
238
|
+
return part ? `<${textTag} xml:space="preserve">${escapeXml(part)}</${textTag}>` : '';
|
|
239
|
+
}).join('');
|
|
223
240
|
}
|
|
224
241
|
|
|
225
242
|
/**
|
|
@@ -229,21 +246,21 @@ function buildSimpleRun(text, rPrXml) {
|
|
|
229
246
|
* @param {import('../core/types.js').SerializationOptions} options - Serialization options
|
|
230
247
|
* @returns {string}
|
|
231
248
|
*/
|
|
232
|
-
function buildDeletionXml(item, options = {}) {
|
|
233
|
-
const metadata = createRevisionMetadata(
|
|
234
|
-
options.author ?? getDefaultAuthor(),
|
|
235
|
-
options.revisionIdAllocator,
|
|
236
|
-
'del'
|
|
237
|
-
);
|
|
238
|
-
const font = options.font ?? null;
|
|
239
|
-
let rPr = item.rPrXml ? stripNamespaceDeclarations(item.rPrXml) : '';
|
|
249
|
+
function buildDeletionXml(item, options = {}) {
|
|
250
|
+
const metadata = createRevisionMetadata(
|
|
251
|
+
options.author ?? getDefaultAuthor(),
|
|
252
|
+
options.revisionIdAllocator,
|
|
253
|
+
'del'
|
|
254
|
+
);
|
|
255
|
+
const font = options.font ?? null;
|
|
256
|
+
let rPr = item.rPrXml ? stripNamespaceDeclarations(item.rPrXml) : '';
|
|
240
257
|
|
|
241
258
|
if (font) {
|
|
242
259
|
rPr = applyFont(rPr, font);
|
|
243
260
|
}
|
|
244
261
|
|
|
245
262
|
return `<w:del w:id="${metadata.id}" w:author="${escapeXml(metadata.author)}" w:date="${metadata.date}">` +
|
|
246
|
-
`<w:r>${rPr}
|
|
263
|
+
`<w:r>${rPr}${buildRunContent(item.text, 'w:delText')}</w:r>` +
|
|
247
264
|
`</w:del>`;
|
|
248
265
|
}
|
|
249
266
|
|
|
@@ -255,18 +272,18 @@ function buildDeletionXml(item, options = {}) {
|
|
|
255
272
|
* @param {import('../core/types.js').SerializationOptions} options - Serialization options
|
|
256
273
|
* @returns {string}
|
|
257
274
|
*/
|
|
258
|
-
function buildInsertionXml(item, formatHints, options = {}) {
|
|
259
|
-
const metadata = createRevisionMetadata(
|
|
260
|
-
options.author ?? getDefaultAuthor(),
|
|
261
|
-
options.revisionIdAllocator,
|
|
262
|
-
'ins'
|
|
263
|
-
);
|
|
275
|
+
function buildInsertionXml(item, formatHints, options = {}) {
|
|
276
|
+
const metadata = createRevisionMetadata(
|
|
277
|
+
options.author ?? getDefaultAuthor(),
|
|
278
|
+
options.revisionIdAllocator,
|
|
279
|
+
'ins'
|
|
280
|
+
);
|
|
264
281
|
const font = options.font ?? null;
|
|
265
282
|
|
|
266
283
|
// Build the inner run content with format hints
|
|
267
284
|
const applicableHints = getApplicableFormatHints(formatHints, item.startOffset, item.endOffset);
|
|
268
285
|
let innerContent = '';
|
|
269
|
-
let cleanRPr = item.rPrXml ? stripNamespaceDeclarations(item.rPrXml) : '';
|
|
286
|
+
let cleanRPr = item.rPrXml ? stripNamespaceDeclarations(item.rPrXml) : '';
|
|
270
287
|
|
|
271
288
|
if (font) {
|
|
272
289
|
cleanRPr = applyFont(cleanRPr, font);
|
|
@@ -383,7 +400,7 @@ export function wrapInDocumentFragment(paragraphXml, options = {}) {
|
|
|
383
400
|
* @param {import('../core/types.js').DocumentFragmentOptions|boolean|undefined|null} options - Raw options
|
|
384
401
|
* @returns {import('../core/types.js').DocumentFragmentOptions}
|
|
385
402
|
*/
|
|
386
|
-
function normalizeFragmentOptions(options) {
|
|
403
|
+
function normalizeFragmentOptions(options) {
|
|
387
404
|
if (typeof options === 'boolean') {
|
|
388
405
|
return { includeNumbering: options };
|
|
389
406
|
}
|
|
@@ -397,9 +414,9 @@ function normalizeFragmentOptions(options) {
|
|
|
397
414
|
numberingXml: options.numberingXml ?? null,
|
|
398
415
|
appendTrailingParagraph: options.appendTrailingParagraph ?? true
|
|
399
416
|
};
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
function stripNamespaceDeclarations(xml) {
|
|
403
|
-
return xml ? xml.replace(XMLNS_ATTR_REGEX, '') : '';
|
|
404
|
-
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
function stripNamespaceDeclarations(xml) {
|
|
420
|
+
return xml ? xml.replace(XMLNS_ATTR_REGEX, '') : '';
|
|
421
|
+
}
|
|
405
422
|
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
reconcileReceiptsAgainstOutput
|
|
25
25
|
} from './receipt-collector.js';
|
|
26
26
|
import { compileOperationBatch } from './operation-batch-compiler.js';
|
|
27
|
+
import { createDynamicNumberingIdState } from './numbering-helpers.js';
|
|
27
28
|
import { createRetryPlan } from './error-recovery.js';
|
|
28
29
|
|
|
29
30
|
const NS_W = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';
|
|
@@ -368,6 +369,11 @@ export async function applyOperationsToDocumentXml(documentXml, operations, auth
|
|
|
368
369
|
|
|
369
370
|
const atomic = options.atomic === true;
|
|
370
371
|
const continueOnError = options.continueOnError !== false;
|
|
372
|
+
// Generated list definitions must not collide with the supplied source numbering part.
|
|
373
|
+
if (runtimeContext && typeof runtimeContext === 'object' && !runtimeContext.numberingIdState
|
|
374
|
+
&& typeof runtimeContext.numberingXml === 'string' && runtimeContext.numberingXml.trim()) {
|
|
375
|
+
runtimeContext.numberingIdState = createDynamicNumberingIdState(runtimeContext.numberingXml);
|
|
376
|
+
}
|
|
371
377
|
const context = cloneBatchRuntimeContext(runtimeContext);
|
|
372
378
|
if (!(context.targetRefSnapshot instanceof Map)) {
|
|
373
379
|
context.targetRefSnapshot = session.initialTargetReferenceSnapshot;
|
|
@@ -8,6 +8,9 @@ import { extractDocumentPartsEntries, computeRevisionTokenSync } from './revisio
|
|
|
8
8
|
const attr = (node, name) => node?.getAttribute?.(`w:${name}`) || node?.getAttribute?.(name) || '';
|
|
9
9
|
const descendants = (node, name) => Array.from(node?.getElementsByTagNameNS?.(NS_W, name) || []);
|
|
10
10
|
const first = (node, name) => descendants(node, name)[0] || null;
|
|
11
|
+
const directChild = (node, name) => Array.from(node?.childNodes || []).find(child => child?.nodeType === 1 && child.localName === name && (!child.namespaceURI || child.namespaceURI === NS_W)) || null;
|
|
12
|
+
/** Current paragraph properties: the paragraph's direct w:pPr only (never the historical w:pPrChange/w:pPr). */
|
|
13
|
+
const currentPPr = paragraph => directChild(paragraph, 'pPr');
|
|
11
14
|
function hasAncestor(node, localName) { let cursor = node?.parentNode; while (cursor) { if (cursor.localName === localName && (!cursor.namespaceURI || cursor.namespaceURI === NS_W)) return true; cursor = cursor.parentNode; } return false; }
|
|
12
15
|
|
|
13
16
|
function parseXml(xml, partName, required = false) {
|
|
@@ -18,11 +21,11 @@ function parseXml(xml, partName, required = false) {
|
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
function paragraphListProperties(paragraph) {
|
|
21
|
-
const numPr =
|
|
24
|
+
const numPr = directChild(currentPPr(paragraph), 'numPr');
|
|
22
25
|
if (!numPr) return null;
|
|
23
|
-
const numId = attr(
|
|
26
|
+
const numId = attr(directChild(numPr, 'numId'), 'val');
|
|
24
27
|
if (!numId || numId === '0') return null;
|
|
25
|
-
return { numId, level: Number.parseInt(attr(
|
|
28
|
+
return { numId, level: Number.parseInt(attr(directChild(numPr, 'ilvl'), 'val') || '0', 10) || 0 };
|
|
26
29
|
}
|
|
27
30
|
|
|
28
31
|
function parseNumbering(numberingDoc) {
|
|
@@ -100,11 +103,11 @@ function createNumberingResolver(numberingDoc) {
|
|
|
100
103
|
}
|
|
101
104
|
|
|
102
105
|
function headingLevel(paragraph) {
|
|
103
|
-
const pPr =
|
|
104
|
-
const style = attr(
|
|
106
|
+
const pPr = currentPPr(paragraph);
|
|
107
|
+
const style = attr(directChild(pPr, 'pStyle'), 'val');
|
|
105
108
|
const match = style.match(/^heading\s*([1-9])$/i);
|
|
106
109
|
if (match) return Math.min(Number(match[1]), 6);
|
|
107
|
-
const outline = Number.parseInt(attr(
|
|
110
|
+
const outline = Number.parseInt(attr(directChild(pPr, 'outlineLvl'), 'val'), 10);
|
|
108
111
|
return Number.isInteger(outline) ? Math.min(outline + 1, 6) : null;
|
|
109
112
|
}
|
|
110
113
|
|
|
@@ -283,7 +286,7 @@ export function inspectDocumentParts(parts, options = {}) {
|
|
|
283
286
|
const ids = [...new Set([...descendants(paragraph, 'commentRangeStart'), ...descendants(paragraph, 'commentReference')].map(node => attr(node, 'id')).filter(Boolean))];
|
|
284
287
|
const authors = revisionAuthors(paragraph);
|
|
285
288
|
const list = resolveNumbering(paragraphListProperties(paragraph));
|
|
286
|
-
const styleId = attr(
|
|
289
|
+
const styleId = attr(directChild(currentPPr(paragraph), 'pStyle'), 'val') || null;
|
|
287
290
|
const structure = structuralContext(paragraph, text);
|
|
288
291
|
const index = zeroIndex + 1;
|
|
289
292
|
const provision = list?.label && list.format !== 'bullet' ? list.label : null;
|
|
@@ -216,9 +216,11 @@ export async function applyOperationToDocumentXml(documentXml, op, author, runti
|
|
|
216
216
|
...(operation.existingRevisions ? { existingRevisions: operation.existingRevisions } : {}),
|
|
217
217
|
structuredContent: typeof operation.structuredContent === 'boolean' ? operation.structuredContent : (options.structuredContent !== false),
|
|
218
218
|
explicitStructuredContent: operation.structuredContent === true,
|
|
219
|
+
...(operation._localizedReplacementCompilation && operation.structuredContent !== true ? { literalTextEdit: true } : {}),
|
|
219
220
|
pairReplacements: typeof operation.pairReplacements === 'boolean' ? operation.pairReplacements : (options.pairReplacements !== false),
|
|
220
221
|
...(operation.insertionAffinity ? { insertionAffinity: operation.insertionAffinity } : {}),
|
|
221
222
|
...(operation.formattingRevisionPolicy ? { formattingRevisionPolicy: operation.formattingRevisionPolicy } : {}),
|
|
223
|
+
...(operation.operationKind === 'format' && Number.isInteger(operation.textOccurrence) ? { textOccurrence: operation.textOccurrence } : {}),
|
|
222
224
|
targetDescriptor: operation.targetDescriptor,
|
|
223
225
|
targetEndDescriptor: operation.targetEndDescriptor,
|
|
224
226
|
_compiledSourceId: operation._compiledSourceId || null,
|