@ansonlai/docx-redline-js 0.8.1 → 0.8.3
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 +586 -539
- package/README.md +901 -890
- package/core/list-targeting.js +12 -10
- package/dist/docx-redline-js.esm.js +280 -33
- package/dist/docx-redline-js.esm.js.map +3 -3
- package/dist/docx-redline-js.esm.min.js +86 -86
- package/dist/docx-redline-js.esm.min.js.map +3 -3
- package/dist/docx-redline.bundle.cjs +280 -33
- package/dist/docx-redline.bundle.cjs.map +3 -3
- package/dist/docx-redline.bundle.js +280 -33
- package/dist/docx-redline.bundle.js.map +3 -3
- package/engine/reconstruction-mode.js +183 -54
- package/orchestration/list-structural-fallback.js +530 -518
- package/package.json +1 -1
- package/pipeline/diff-engine.js +274 -258
- package/pipeline/list-generation.js +203 -168
- package/scripts/run-tests.mjs +14 -2
- package/services/document-inspection.js +10 -7
- package/services/document-operation-mutations.js +1597 -1586
- package/services/numbering-helpers.js +108 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// @ansonlai/docx-redline-js standalone bundle v0.8.
|
|
1
|
+
// @ansonlai/docx-redline-js standalone bundle v0.8.3 — https://github.com/AnsonLai/docx-redline-js
|
|
2
2
|
var __create = Object.create;
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -9001,15 +9001,29 @@ function createDiffEngine(options = {}) {
|
|
|
9001
9001
|
engine.Diff_Timeout = timeout;
|
|
9002
9002
|
return engine;
|
|
9003
9003
|
}
|
|
9004
|
-
function tokenize(text2) {
|
|
9004
|
+
function tokenize(text2, atomicChars = null) {
|
|
9005
9005
|
const tokens = [];
|
|
9006
|
+
const pushWord = (word) => {
|
|
9007
|
+
if (!atomicChars || atomicChars.size === 0) {
|
|
9008
|
+
tokens.push(word);
|
|
9009
|
+
return;
|
|
9010
|
+
}
|
|
9011
|
+
let start = 0;
|
|
9012
|
+
for (let index = 0; index < word.length; index++) {
|
|
9013
|
+
if (!atomicChars.has(word[index])) continue;
|
|
9014
|
+
if (index > start) tokens.push(word.slice(start, index));
|
|
9015
|
+
tokens.push(word[index]);
|
|
9016
|
+
start = index + 1;
|
|
9017
|
+
}
|
|
9018
|
+
if (start < word.length) tokens.push(word.slice(start));
|
|
9019
|
+
};
|
|
9006
9020
|
const leading = text2.match(/^\s+/);
|
|
9007
9021
|
if (leading) tokens.push(leading[0]);
|
|
9008
9022
|
const regex = /(\S+)(\s*)/g;
|
|
9009
9023
|
regex.lastIndex = leading?.[0].length || 0;
|
|
9010
9024
|
let match;
|
|
9011
9025
|
while ((match = regex.exec(text2)) !== null) {
|
|
9012
|
-
if (match[1])
|
|
9026
|
+
if (match[1]) pushWord(match[1]);
|
|
9013
9027
|
if (match[2]) tokens.push(match[2]);
|
|
9014
9028
|
}
|
|
9015
9029
|
return tokens;
|
|
@@ -9037,8 +9051,8 @@ function wordsToChars(text1, text2, options = {}) {
|
|
|
9037
9051
|
}
|
|
9038
9052
|
return { chars, tokenIds };
|
|
9039
9053
|
}
|
|
9040
|
-
const tokens1 = tokenize(text1);
|
|
9041
|
-
const tokens2 = tokenize(text2);
|
|
9054
|
+
const tokens1 = tokenize(text1, options.atomicChars);
|
|
9055
|
+
const tokens2 = tokenize(text2, options.atomicChars);
|
|
9042
9056
|
const encoded1 = mapTokensToChars(tokens1);
|
|
9043
9057
|
const encoded2 = mapTokensToChars(tokens2);
|
|
9044
9058
|
return {
|
|
@@ -10438,7 +10452,37 @@ async function executeListGeneration(options) {
|
|
|
10438
10452
|
}];
|
|
10439
10453
|
}
|
|
10440
10454
|
}
|
|
10441
|
-
|
|
10455
|
+
const sourceParagraphCount = (originalRunModel || []).filter((run) => run.kind === RunKind.PARAGRAPH_START).length;
|
|
10456
|
+
if (generateRedlines && sourceParagraphCount > 0 && (sourceParagraphCount > 1 || deletionRuns.length === 0)) {
|
|
10457
|
+
let segment = null;
|
|
10458
|
+
const flushSegment = () => {
|
|
10459
|
+
if (!segment) return;
|
|
10460
|
+
results.push(serializeToOoxml(segment, null, [], {
|
|
10461
|
+
author,
|
|
10462
|
+
generateRedlines,
|
|
10463
|
+
revisionIdAllocator
|
|
10464
|
+
}));
|
|
10465
|
+
segment = null;
|
|
10466
|
+
};
|
|
10467
|
+
for (const run of originalRunModel) {
|
|
10468
|
+
if (run.kind === RunKind.PARAGRAPH_START) {
|
|
10469
|
+
flushSegment();
|
|
10470
|
+
segment = [{
|
|
10471
|
+
...run,
|
|
10472
|
+
pPrElement: null,
|
|
10473
|
+
pPrXml: addParagraphMarkRevision(
|
|
10474
|
+
run.pPrElement || run.pPrXml || null,
|
|
10475
|
+
"del",
|
|
10476
|
+
author,
|
|
10477
|
+
revisionIdAllocator
|
|
10478
|
+
)
|
|
10479
|
+
}];
|
|
10480
|
+
} else if (segment && (run.kind === "text" || run.kind === "run")) {
|
|
10481
|
+
segment.push({ ...run, kind: "deletion", author });
|
|
10482
|
+
}
|
|
10483
|
+
}
|
|
10484
|
+
flushSegment();
|
|
10485
|
+
} else if (generateRedlines && deletionRuns.length > 0) {
|
|
10442
10486
|
const deletedPPr = addParagraphMarkRevision(sourcePPr, "del", author, revisionIdAllocator);
|
|
10443
10487
|
const deletedParagraph = serializeToOoxml(deletionRuns, deletedPPr, [], {
|
|
10444
10488
|
author,
|
|
@@ -14443,7 +14487,11 @@ function applyReconstructionMode(xmlDoc, originalText, modifiedText, serializer,
|
|
|
14443
14487
|
if (mapping.paragraphs.length === 0) {
|
|
14444
14488
|
return withOoxmlSourceType({ oxml: serializer.serializeToString(xmlDoc), hasChanges: false });
|
|
14445
14489
|
}
|
|
14446
|
-
const
|
|
14490
|
+
const wordDiffs = computeWordDiffs(mapping.originalFullText, mapping.processedModifiedText, {
|
|
14491
|
+
...diffOptions,
|
|
14492
|
+
atomicChars: new Set(mapping.referenceMap.keys())
|
|
14493
|
+
});
|
|
14494
|
+
const diffs = keepUnchangedTextOutsideWrappers(anchorSharedReferences(wordDiffs, mapping.referenceMap), mapping);
|
|
14447
14495
|
return withOoxmlSourceType(applyReconstructionDiffs(
|
|
14448
14496
|
xmlDoc,
|
|
14449
14497
|
diffs,
|
|
@@ -14455,6 +14503,109 @@ function applyReconstructionMode(xmlDoc, originalText, modifiedText, serializer,
|
|
|
14455
14503
|
options
|
|
14456
14504
|
));
|
|
14457
14505
|
}
|
|
14506
|
+
function forEachChangeGroup(diffs, onEqual, onGroup) {
|
|
14507
|
+
let index = 0;
|
|
14508
|
+
while (index < diffs.length) {
|
|
14509
|
+
if (diffs[index][0] === 0) {
|
|
14510
|
+
onEqual(diffs[index]);
|
|
14511
|
+
index++;
|
|
14512
|
+
continue;
|
|
14513
|
+
}
|
|
14514
|
+
const group = [];
|
|
14515
|
+
while (index < diffs.length && diffs[index][0] !== 0) group.push(diffs[index++]);
|
|
14516
|
+
onGroup(
|
|
14517
|
+
group,
|
|
14518
|
+
group.filter(([op]) => op === -1).map(([, text2]) => text2).join(""),
|
|
14519
|
+
group.filter(([op]) => op === 1).map(([, text2]) => text2).join("")
|
|
14520
|
+
);
|
|
14521
|
+
}
|
|
14522
|
+
}
|
|
14523
|
+
function pushChange(result, deleted, inserted) {
|
|
14524
|
+
if (deleted === inserted) {
|
|
14525
|
+
if (deleted) result.push([0, deleted]);
|
|
14526
|
+
return;
|
|
14527
|
+
}
|
|
14528
|
+
if (deleted) result.push([-1, deleted]);
|
|
14529
|
+
if (inserted) result.push([1, inserted]);
|
|
14530
|
+
}
|
|
14531
|
+
function anchorSharedReferences(diffs, referenceMap) {
|
|
14532
|
+
if (referenceMap.size === 0) return diffs;
|
|
14533
|
+
const result = [];
|
|
14534
|
+
forEachChangeGroup(diffs, (part) => result.push(part), (group, deleted, inserted) => {
|
|
14535
|
+
const deletedRefs = [...deleted].filter((char) => referenceMap.has(char) && inserted.includes(char));
|
|
14536
|
+
const insertedRefs = [...inserted].filter((char) => deletedRefs.includes(char));
|
|
14537
|
+
if (deletedRefs.length === 0 || deletedRefs.join("") !== insertedRefs.join("")) {
|
|
14538
|
+
result.push(...group);
|
|
14539
|
+
return;
|
|
14540
|
+
}
|
|
14541
|
+
let deletedStart = 0;
|
|
14542
|
+
let insertedStart = 0;
|
|
14543
|
+
for (const ref of deletedRefs) {
|
|
14544
|
+
const deletedAt = deleted.indexOf(ref, deletedStart);
|
|
14545
|
+
const insertedAt = inserted.indexOf(ref, insertedStart);
|
|
14546
|
+
pushChange(result, deleted.slice(deletedStart, deletedAt), inserted.slice(insertedStart, insertedAt));
|
|
14547
|
+
result.push([0, ref]);
|
|
14548
|
+
deletedStart = deletedAt + 1;
|
|
14549
|
+
insertedStart = insertedAt + 1;
|
|
14550
|
+
}
|
|
14551
|
+
pushChange(result, deleted.slice(deletedStart), inserted.slice(insertedStart));
|
|
14552
|
+
});
|
|
14553
|
+
return result;
|
|
14554
|
+
}
|
|
14555
|
+
function commonPrefixLength(left, right) {
|
|
14556
|
+
const limit = Math.min(left.length, right.length);
|
|
14557
|
+
let length = 0;
|
|
14558
|
+
while (length < limit && left[length] === right[length]) length++;
|
|
14559
|
+
return length;
|
|
14560
|
+
}
|
|
14561
|
+
function commonSuffixLength(left, right, limit) {
|
|
14562
|
+
let length = 0;
|
|
14563
|
+
while (length < limit && left[left.length - 1 - length] === right[right.length - 1 - length]) length++;
|
|
14564
|
+
return length;
|
|
14565
|
+
}
|
|
14566
|
+
function keepUnchangedTextOutsideWrappers(diffs, mapping) {
|
|
14567
|
+
const wrapperAt = (index) => mapping.getRunProperties(index).wrapper || null;
|
|
14568
|
+
const result = [];
|
|
14569
|
+
let originalOffset = 0;
|
|
14570
|
+
forEachChangeGroup(diffs, (part) => {
|
|
14571
|
+
result.push(part);
|
|
14572
|
+
originalOffset += part[1].length;
|
|
14573
|
+
}, (group, deleted, inserted) => {
|
|
14574
|
+
const start = originalOffset;
|
|
14575
|
+
const end = start + deleted.length;
|
|
14576
|
+
originalOffset = end;
|
|
14577
|
+
const isWrapperBoundary = (index) => index > start && index < end && wrapperAt(index - 1) !== wrapperAt(index);
|
|
14578
|
+
let prefix = 0;
|
|
14579
|
+
let suffix = 0;
|
|
14580
|
+
if (deleted && inserted) {
|
|
14581
|
+
const sharedSuffix = commonSuffixLength(deleted, inserted, Math.min(deleted.length, inserted.length));
|
|
14582
|
+
for (let length = sharedSuffix; length > 0; length--) {
|
|
14583
|
+
if (isWrapperBoundary(end - length)) {
|
|
14584
|
+
suffix = length;
|
|
14585
|
+
break;
|
|
14586
|
+
}
|
|
14587
|
+
}
|
|
14588
|
+
const sharedPrefix = Math.min(
|
|
14589
|
+
commonPrefixLength(deleted, inserted),
|
|
14590
|
+
Math.min(deleted.length, inserted.length) - suffix
|
|
14591
|
+
);
|
|
14592
|
+
for (let length = sharedPrefix; length > 0; length--) {
|
|
14593
|
+
if (isWrapperBoundary(start + length)) {
|
|
14594
|
+
prefix = length;
|
|
14595
|
+
break;
|
|
14596
|
+
}
|
|
14597
|
+
}
|
|
14598
|
+
}
|
|
14599
|
+
if (prefix === 0 && suffix === 0) {
|
|
14600
|
+
result.push(...group);
|
|
14601
|
+
return;
|
|
14602
|
+
}
|
|
14603
|
+
if (prefix > 0) result.push([0, deleted.slice(0, prefix)]);
|
|
14604
|
+
pushChange(result, deleted.slice(prefix, deleted.length - suffix), inserted.slice(prefix, inserted.length - suffix));
|
|
14605
|
+
if (suffix > 0) result.push([0, deleted.slice(deleted.length - suffix)]);
|
|
14606
|
+
});
|
|
14607
|
+
return result;
|
|
14608
|
+
}
|
|
14458
14609
|
|
|
14459
14610
|
// engine/table-mode.js
|
|
14460
14611
|
function noChanges(serializer, xmlDoc) {
|
|
@@ -16529,12 +16680,12 @@ function validateParagraphBoundaryMutation(targetParagraph, modifiedText, option
|
|
|
16529
16680
|
}
|
|
16530
16681
|
|
|
16531
16682
|
// core/list-targeting.js
|
|
16532
|
-
function
|
|
16533
|
-
if (!node
|
|
16534
|
-
const
|
|
16535
|
-
|
|
16536
|
-
|
|
16537
|
-
return
|
|
16683
|
+
function getDirectChildByLocalName(node, localName2) {
|
|
16684
|
+
if (!node) return null;
|
|
16685
|
+
for (const child of Array.from(node.childNodes || [])) {
|
|
16686
|
+
if (child?.nodeType === 1 && child.localName === localName2) return child;
|
|
16687
|
+
}
|
|
16688
|
+
return null;
|
|
16538
16689
|
}
|
|
16539
16690
|
function readValAttribute(element) {
|
|
16540
16691
|
if (!element) return null;
|
|
@@ -16651,15 +16802,15 @@ function buildListEntriesForInsertion(parsedItems, normalizedTargetText, anchorL
|
|
|
16651
16802
|
}
|
|
16652
16803
|
function getParagraphListInfo(paragraph) {
|
|
16653
16804
|
if (!paragraph) return null;
|
|
16654
|
-
const pPr =
|
|
16805
|
+
const pPr = getDirectChildByLocalName(paragraph, "pPr");
|
|
16655
16806
|
if (!pPr) return null;
|
|
16656
|
-
const numPr =
|
|
16807
|
+
const numPr = getDirectChildByLocalName(pPr, "numPr");
|
|
16657
16808
|
if (!numPr) return null;
|
|
16658
|
-
const numIdEl =
|
|
16809
|
+
const numIdEl = getDirectChildByLocalName(numPr, "numId");
|
|
16659
16810
|
if (!numIdEl) return null;
|
|
16660
16811
|
const numId = readValAttribute(numIdEl);
|
|
16661
16812
|
if (!numId || numId === "0") return null;
|
|
16662
|
-
const ilvlEl =
|
|
16813
|
+
const ilvlEl = getDirectChildByLocalName(numPr, "ilvl");
|
|
16663
16814
|
const ilvlRaw = readValAttribute(ilvlEl);
|
|
16664
16815
|
const ilvl = Number.parseInt(ilvlRaw || "0", 10);
|
|
16665
16816
|
return {
|
|
@@ -17069,8 +17220,13 @@ function enforceListBindingOnParagraphNodes(nodes, options = {}) {
|
|
|
17069
17220
|
}
|
|
17070
17221
|
return updated;
|
|
17071
17222
|
}
|
|
17223
|
+
function parseOxmlFragment(oxml) {
|
|
17224
|
+
const text2 = String(oxml || "");
|
|
17225
|
+
const declared = /xmlns:w\s*=/.test(text2);
|
|
17226
|
+
return parseOoxmlSafe(declared ? text2 : `<w:root xmlns:w="${NS_W}">${text2}</w:root>`, "application/xml").doc;
|
|
17227
|
+
}
|
|
17072
17228
|
function getFirstParagraphFromOxml(oxml) {
|
|
17073
|
-
const doc =
|
|
17229
|
+
const doc = parseOxmlFragment(oxml);
|
|
17074
17230
|
if (!doc) return null;
|
|
17075
17231
|
const parseError = getXmlParseError(doc);
|
|
17076
17232
|
if (parseError) return null;
|
|
@@ -17097,17 +17253,17 @@ function setElementVal(element, value) {
|
|
|
17097
17253
|
element.setAttribute("w:val", String(value));
|
|
17098
17254
|
}
|
|
17099
17255
|
function extractFirstParagraphNumIdFromOxml(oxml) {
|
|
17100
|
-
const doc =
|
|
17256
|
+
const doc = parseOxmlFragment(oxml);
|
|
17101
17257
|
if (!doc) return null;
|
|
17102
17258
|
const parseError = getXmlParseError(doc);
|
|
17103
17259
|
if (parseError) return null;
|
|
17104
17260
|
const paragraphs = getDocumentParagraphNodes(doc);
|
|
17105
|
-
const
|
|
17106
|
-
|
|
17107
|
-
|
|
17108
|
-
|
|
17109
|
-
|
|
17110
|
-
|
|
17261
|
+
for (const paragraph of paragraphs) {
|
|
17262
|
+
const numIdNodes = Array.from(paragraph.getElementsByTagNameNS("*", "numId"));
|
|
17263
|
+
for (const numIdNode of numIdNodes) {
|
|
17264
|
+
const numId = getElementId(numIdNode, ["w:val", "val"]);
|
|
17265
|
+
if (numId != null) return String(numId);
|
|
17266
|
+
}
|
|
17111
17267
|
}
|
|
17112
17268
|
return null;
|
|
17113
17269
|
}
|
|
@@ -17603,6 +17759,8 @@ function createDynamicNumberingIdState(numberingXml, options = {}) {
|
|
|
17603
17759
|
const baseNumId = Math.max(minId, maxUsedNumId + 1);
|
|
17604
17760
|
const baseAbstractNumId = Math.max(minId, maxUsedAbstractNumId + 1);
|
|
17605
17761
|
return {
|
|
17762
|
+
// Kept so list edits can recognise which existing definition a source list uses and continue it.
|
|
17763
|
+
sourceNumberingXml: String(numberingXml || ""),
|
|
17606
17764
|
nextNumId: nextAvailableId(baseNumId, usedNumIds, maxPreferred),
|
|
17607
17765
|
nextAbstractNumId: nextAvailableId(baseAbstractNumId, usedAbstractNumIds, maxPreferred),
|
|
17608
17766
|
usedNumIds,
|
|
@@ -17743,6 +17901,82 @@ function buildExplicitDecimalMultilevelNumberingXml(numId, abstractNumId, startA
|
|
|
17743
17901
|
</w:num>
|
|
17744
17902
|
</w:numbering>`.trim();
|
|
17745
17903
|
}
|
|
17904
|
+
function isTrackedDeletedParagraph(node) {
|
|
17905
|
+
if (!node || node.nodeType !== 1 || node.localName !== "p") return false;
|
|
17906
|
+
const pPr = Array.from(node.childNodes || []).find((child) => isDirectWordChild(child, "pPr"));
|
|
17907
|
+
const rPr = pPr && Array.from(pPr.childNodes || []).find((child) => isDirectWordChild(child, "rPr"));
|
|
17908
|
+
return !!rPr && Array.from(rPr.childNodes || []).some((child) => isDirectWordChild(child, "del"));
|
|
17909
|
+
}
|
|
17910
|
+
function paragraphNumIdNodes(node) {
|
|
17911
|
+
return Array.from(node?.getElementsByTagNameNS?.("*", "numId") || []).filter((numIdNode) => numIdNode.parentNode?.localName === "numPr");
|
|
17912
|
+
}
|
|
17913
|
+
function levelFormats(abstractNum) {
|
|
17914
|
+
const formats = /* @__PURE__ */ new Map();
|
|
17915
|
+
for (const lvl of Array.from(abstractNum?.getElementsByTagNameNS?.("*", "lvl") || [])) {
|
|
17916
|
+
const ilvl = getElementId2(lvl, ["w:ilvl", "ilvl"]);
|
|
17917
|
+
const fmt = Array.from(lvl.getElementsByTagNameNS("*", "numFmt"))[0]?.getAttribute("w:val") || null;
|
|
17918
|
+
if (ilvl != null && fmt) formats.set(ilvl, fmt);
|
|
17919
|
+
}
|
|
17920
|
+
return formats;
|
|
17921
|
+
}
|
|
17922
|
+
function normalizeListFormat(format) {
|
|
17923
|
+
return format === "bullet" || format === "circle" || format === "square" ? "bullet" : format;
|
|
17924
|
+
}
|
|
17925
|
+
function abstractNumForNumId(numberingDoc, numId) {
|
|
17926
|
+
const num = Array.from(numberingDoc.getElementsByTagNameNS("*", "num")).find((candidate) => getElementId2(candidate, ["w:numId", "numId"]) === numId);
|
|
17927
|
+
const abstractId = num && getElementId2(Array.from(num.getElementsByTagNameNS("*", "abstractNumId"))[0], ["w:val", "val"]);
|
|
17928
|
+
if (abstractId == null) return null;
|
|
17929
|
+
return Array.from(numberingDoc.getElementsByTagNameNS("*", "abstractNum")).find((candidate) => getElementId2(candidate, ["w:abstractNumId", "abstractNumId"]) === abstractId) || null;
|
|
17930
|
+
}
|
|
17931
|
+
function reuseSourceListNumbering(numberingXml, replacementNodes, sourceParagraphs, numberingIdState) {
|
|
17932
|
+
const sourceXml = numberingIdState?.sourceNumberingXml;
|
|
17933
|
+
if (!numberingXml || !String(sourceXml || "").trim() || !Array.isArray(replacementNodes)) return null;
|
|
17934
|
+
const sourceNumIds = /* @__PURE__ */ new Set();
|
|
17935
|
+
for (const paragraph of sourceParagraphs || []) {
|
|
17936
|
+
for (const numIdNode of paragraphNumIdNodes(paragraph)) {
|
|
17937
|
+
const id = getElementId2(numIdNode, ["w:val", "val"]);
|
|
17938
|
+
if (id != null && id !== 0) sourceNumIds.add(id);
|
|
17939
|
+
}
|
|
17940
|
+
}
|
|
17941
|
+
if (sourceNumIds.size !== 1) return null;
|
|
17942
|
+
const [sourceNumId] = sourceNumIds;
|
|
17943
|
+
const sourceDoc = parseOoxml(sourceXml);
|
|
17944
|
+
const payloadDoc = parseOoxml(numberingXml);
|
|
17945
|
+
if (hasXmlParseError(sourceDoc) || hasXmlParseError(payloadDoc)) return null;
|
|
17946
|
+
const sourceAbstract = abstractNumForNumId(sourceDoc, sourceNumId);
|
|
17947
|
+
if (!sourceAbstract) return null;
|
|
17948
|
+
const sourceFormats = levelFormats(sourceAbstract);
|
|
17949
|
+
const newParagraphNumIds = [];
|
|
17950
|
+
for (const node of replacementNodes) {
|
|
17951
|
+
if (isTrackedDeletedParagraph(node)) continue;
|
|
17952
|
+
for (const numIdNode of paragraphNumIdNodes(node)) {
|
|
17953
|
+
const ilvlNode = Array.from(numIdNode.parentNode.childNodes || []).find((child) => child.localName === "ilvl");
|
|
17954
|
+
newParagraphNumIds.push({
|
|
17955
|
+
numId: getElementId2(numIdNode, ["w:val", "val"]),
|
|
17956
|
+
ilvl: ilvlNode ? getElementId2(ilvlNode, ["w:val", "val"]) ?? 0 : 0
|
|
17957
|
+
});
|
|
17958
|
+
}
|
|
17959
|
+
}
|
|
17960
|
+
if (newParagraphNumIds.length === 0) return null;
|
|
17961
|
+
const payloadFormats = /* @__PURE__ */ new Map();
|
|
17962
|
+
for (const { numId, ilvl } of newParagraphNumIds) {
|
|
17963
|
+
if (numId == null) return null;
|
|
17964
|
+
if (!payloadFormats.has(numId)) {
|
|
17965
|
+
const abstract = abstractNumForNumId(payloadDoc, numId);
|
|
17966
|
+
if (!abstract) return null;
|
|
17967
|
+
payloadFormats.set(numId, levelFormats(abstract));
|
|
17968
|
+
}
|
|
17969
|
+
const generated = payloadFormats.get(numId).get(ilvl);
|
|
17970
|
+
const existing = sourceFormats.get(ilvl);
|
|
17971
|
+
if (!generated || !existing || normalizeListFormat(generated) !== normalizeListFormat(existing)) return null;
|
|
17972
|
+
}
|
|
17973
|
+
const clonedNodes = replacementNodes.map((node) => node?.cloneNode ? node.cloneNode(true) : node);
|
|
17974
|
+
for (const node of clonedNodes) {
|
|
17975
|
+
if (isTrackedDeletedParagraph(node)) continue;
|
|
17976
|
+
for (const numIdNode of paragraphNumIdNodes(node)) setElementVal2(numIdNode, sourceNumId);
|
|
17977
|
+
}
|
|
17978
|
+
return { numId: sourceNumId, replacementNodes: clonedNodes };
|
|
17979
|
+
}
|
|
17746
17980
|
function remapNumberingPayloadForDocument(numberingXml, replacementNodes, numberingIdState) {
|
|
17747
17981
|
const numberingDoc = parseOoxml(numberingXml);
|
|
17748
17982
|
if (hasXmlParseError(numberingDoc)) {
|
|
@@ -17780,6 +18014,7 @@ function remapNumberingPayloadForDocument(numberingXml, replacementNodes, number
|
|
|
17780
18014
|
}
|
|
17781
18015
|
const clonedNodes = Array.isArray(replacementNodes) ? replacementNodes.map((node) => node?.cloneNode ? node.cloneNode(true) : node) : [];
|
|
17782
18016
|
for (const node of clonedNodes) {
|
|
18017
|
+
if (isTrackedDeletedParagraph(node)) continue;
|
|
17783
18018
|
const numIdNodes = Array.from(node?.getElementsByTagNameNS?.("*", "numId") || []);
|
|
17784
18019
|
for (const numIdNode of numIdNodes) {
|
|
17785
18020
|
const oldNumRef = getElementId2(numIdNode, ["w:val", "val"]);
|
|
@@ -18600,6 +18835,8 @@ function areRevisionTokensEqual(a, b) {
|
|
|
18600
18835
|
var attr2 = (node, name) => node?.getAttribute?.(`w:${name}`) || node?.getAttribute?.(name) || "";
|
|
18601
18836
|
var descendants = (node, name) => Array.from(node?.getElementsByTagNameNS?.(NS_W, name) || []);
|
|
18602
18837
|
var first = (node, name) => descendants(node, name)[0] || null;
|
|
18838
|
+
var directChild2 = (node, name) => Array.from(node?.childNodes || []).find((child) => child?.nodeType === 1 && child.localName === name && (!child.namespaceURI || child.namespaceURI === NS_W)) || null;
|
|
18839
|
+
var currentPPr = (paragraph) => directChild2(paragraph, "pPr");
|
|
18603
18840
|
function hasAncestor(node, localName2) {
|
|
18604
18841
|
let cursor = node?.parentNode;
|
|
18605
18842
|
while (cursor) {
|
|
@@ -18615,11 +18852,11 @@ function parseXml2(xml, partName, required = false) {
|
|
|
18615
18852
|
return { doc: parsed.doc, warnings: parsed.warnings || [] };
|
|
18616
18853
|
}
|
|
18617
18854
|
function paragraphListProperties(paragraph) {
|
|
18618
|
-
const numPr =
|
|
18855
|
+
const numPr = directChild2(currentPPr(paragraph), "numPr");
|
|
18619
18856
|
if (!numPr) return null;
|
|
18620
|
-
const numId = attr2(
|
|
18857
|
+
const numId = attr2(directChild2(numPr, "numId"), "val");
|
|
18621
18858
|
if (!numId || numId === "0") return null;
|
|
18622
|
-
return { numId, level: Number.parseInt(attr2(
|
|
18859
|
+
return { numId, level: Number.parseInt(attr2(directChild2(numPr, "ilvl"), "val") || "0", 10) || 0 };
|
|
18623
18860
|
}
|
|
18624
18861
|
function parseNumbering(numberingDoc) {
|
|
18625
18862
|
const abstracts = /* @__PURE__ */ new Map();
|
|
@@ -18704,11 +18941,11 @@ function createNumberingResolver(numberingDoc) {
|
|
|
18704
18941
|
};
|
|
18705
18942
|
}
|
|
18706
18943
|
function headingLevel(paragraph) {
|
|
18707
|
-
const pPr =
|
|
18708
|
-
const style = attr2(
|
|
18944
|
+
const pPr = currentPPr(paragraph);
|
|
18945
|
+
const style = attr2(directChild2(pPr, "pStyle"), "val");
|
|
18709
18946
|
const match = style.match(/^heading\s*([1-9])$/i);
|
|
18710
18947
|
if (match) return Math.min(Number(match[1]), 6);
|
|
18711
|
-
const outline = Number.parseInt(attr2(
|
|
18948
|
+
const outline = Number.parseInt(attr2(directChild2(pPr, "outlineLvl"), "val"), 10);
|
|
18712
18949
|
return Number.isInteger(outline) ? Math.min(outline + 1, 6) : null;
|
|
18713
18950
|
}
|
|
18714
18951
|
function structuralContext(paragraph, text2) {
|
|
@@ -18887,7 +19124,7 @@ function inspectDocumentParts(parts, options = {}) {
|
|
|
18887
19124
|
const ids = [...new Set([...descendants(paragraph, "commentRangeStart"), ...descendants(paragraph, "commentReference")].map((node) => attr2(node, "id")).filter(Boolean))];
|
|
18888
19125
|
const authors = revisionAuthors(paragraph);
|
|
18889
19126
|
const list = resolveNumbering(paragraphListProperties(paragraph));
|
|
18890
|
-
const styleId = attr2(
|
|
19127
|
+
const styleId = attr2(directChild2(currentPPr(paragraph), "pStyle"), "val") || null;
|
|
18891
19128
|
const structure = structuralContext(paragraph, text2);
|
|
18892
19129
|
const index = zeroIndex + 1;
|
|
18893
19130
|
const provision = list?.label && list.format !== "bullet" ? list.label : null;
|
|
@@ -24288,7 +24525,9 @@ async function applyToParagraphByExactText(documentXml, targetText, modifiedText
|
|
|
24288
24525
|
paragraphText,
|
|
24289
24526
|
generateRedlines ? createRevisionMetadata(author, xmlDoc) : null,
|
|
24290
24527
|
author,
|
|
24291
|
-
|
|
24528
|
+
// A wholly inserted paragraph must track its own paragraph mark; otherwise Word's
|
|
24529
|
+
// Reject All removes the text but leaves an empty paragraph behind.
|
|
24530
|
+
{ generateRedlines, trackParagraphMark: true }
|
|
24292
24531
|
);
|
|
24293
24532
|
const imported = xmlDoc.importNode(plainParagraph, true);
|
|
24294
24533
|
ensureParagraphIdsOnImportedNode(imported, operationSession);
|
|
@@ -24419,6 +24658,14 @@ async function applyToParagraphByExactText(documentXml, targetText, modifiedText
|
|
|
24419
24658
|
const extracted = extractReplacementNodes(result.oxml);
|
|
24420
24659
|
let replacementNodes = removeListPackagingSentinel(extracted.replacementNodes, result.warnings);
|
|
24421
24660
|
let numberingXml = extracted.numberingXml;
|
|
24661
|
+
if (numberingXml && runtimeContext?.numberingIdState && !useTableScope) {
|
|
24662
|
+
const sourceParagraphs = useListScope ? listScopeEdit.paragraphs : explicitRangeParagraphs || [targetParagraph];
|
|
24663
|
+
const continued = reuseSourceListNumbering(numberingXml, replacementNodes, sourceParagraphs, runtimeContext.numberingIdState);
|
|
24664
|
+
if (continued) {
|
|
24665
|
+
replacementNodes = continued.replacementNodes;
|
|
24666
|
+
numberingXml = null;
|
|
24667
|
+
}
|
|
24668
|
+
}
|
|
24422
24669
|
if (numberingXml && runtimeContext?.numberingIdState) {
|
|
24423
24670
|
const normalizedNumbering = remapNumberingPayloadForDocument(numberingXml, replacementNodes, runtimeContext.numberingIdState);
|
|
24424
24671
|
replacementNodes = normalizedNumbering.replacementNodes;
|