@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 CommonJS bundle v0.8.
|
|
1
|
+
// @ansonlai/docx-redline-js standalone CommonJS 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;
|
|
@@ -9139,15 +9139,29 @@ function createDiffEngine(options = {}) {
|
|
|
9139
9139
|
engine.Diff_Timeout = timeout;
|
|
9140
9140
|
return engine;
|
|
9141
9141
|
}
|
|
9142
|
-
function tokenize(text2) {
|
|
9142
|
+
function tokenize(text2, atomicChars = null) {
|
|
9143
9143
|
const tokens = [];
|
|
9144
|
+
const pushWord = (word) => {
|
|
9145
|
+
if (!atomicChars || atomicChars.size === 0) {
|
|
9146
|
+
tokens.push(word);
|
|
9147
|
+
return;
|
|
9148
|
+
}
|
|
9149
|
+
let start = 0;
|
|
9150
|
+
for (let index = 0; index < word.length; index++) {
|
|
9151
|
+
if (!atomicChars.has(word[index])) continue;
|
|
9152
|
+
if (index > start) tokens.push(word.slice(start, index));
|
|
9153
|
+
tokens.push(word[index]);
|
|
9154
|
+
start = index + 1;
|
|
9155
|
+
}
|
|
9156
|
+
if (start < word.length) tokens.push(word.slice(start));
|
|
9157
|
+
};
|
|
9144
9158
|
const leading = text2.match(/^\s+/);
|
|
9145
9159
|
if (leading) tokens.push(leading[0]);
|
|
9146
9160
|
const regex = /(\S+)(\s*)/g;
|
|
9147
9161
|
regex.lastIndex = leading?.[0].length || 0;
|
|
9148
9162
|
let match;
|
|
9149
9163
|
while ((match = regex.exec(text2)) !== null) {
|
|
9150
|
-
if (match[1])
|
|
9164
|
+
if (match[1]) pushWord(match[1]);
|
|
9151
9165
|
if (match[2]) tokens.push(match[2]);
|
|
9152
9166
|
}
|
|
9153
9167
|
return tokens;
|
|
@@ -9175,8 +9189,8 @@ function wordsToChars(text1, text2, options = {}) {
|
|
|
9175
9189
|
}
|
|
9176
9190
|
return { chars, tokenIds };
|
|
9177
9191
|
}
|
|
9178
|
-
const tokens1 = tokenize(text1);
|
|
9179
|
-
const tokens2 = tokenize(text2);
|
|
9192
|
+
const tokens1 = tokenize(text1, options.atomicChars);
|
|
9193
|
+
const tokens2 = tokenize(text2, options.atomicChars);
|
|
9180
9194
|
const encoded1 = mapTokensToChars(tokens1);
|
|
9181
9195
|
const encoded2 = mapTokensToChars(tokens2);
|
|
9182
9196
|
return {
|
|
@@ -10576,7 +10590,37 @@ async function executeListGeneration(options) {
|
|
|
10576
10590
|
}];
|
|
10577
10591
|
}
|
|
10578
10592
|
}
|
|
10579
|
-
|
|
10593
|
+
const sourceParagraphCount = (originalRunModel || []).filter((run) => run.kind === RunKind.PARAGRAPH_START).length;
|
|
10594
|
+
if (generateRedlines && sourceParagraphCount > 0 && (sourceParagraphCount > 1 || deletionRuns.length === 0)) {
|
|
10595
|
+
let segment = null;
|
|
10596
|
+
const flushSegment = () => {
|
|
10597
|
+
if (!segment) return;
|
|
10598
|
+
results.push(serializeToOoxml(segment, null, [], {
|
|
10599
|
+
author,
|
|
10600
|
+
generateRedlines,
|
|
10601
|
+
revisionIdAllocator
|
|
10602
|
+
}));
|
|
10603
|
+
segment = null;
|
|
10604
|
+
};
|
|
10605
|
+
for (const run of originalRunModel) {
|
|
10606
|
+
if (run.kind === RunKind.PARAGRAPH_START) {
|
|
10607
|
+
flushSegment();
|
|
10608
|
+
segment = [{
|
|
10609
|
+
...run,
|
|
10610
|
+
pPrElement: null,
|
|
10611
|
+
pPrXml: addParagraphMarkRevision(
|
|
10612
|
+
run.pPrElement || run.pPrXml || null,
|
|
10613
|
+
"del",
|
|
10614
|
+
author,
|
|
10615
|
+
revisionIdAllocator
|
|
10616
|
+
)
|
|
10617
|
+
}];
|
|
10618
|
+
} else if (segment && (run.kind === "text" || run.kind === "run")) {
|
|
10619
|
+
segment.push({ ...run, kind: "deletion", author });
|
|
10620
|
+
}
|
|
10621
|
+
}
|
|
10622
|
+
flushSegment();
|
|
10623
|
+
} else if (generateRedlines && deletionRuns.length > 0) {
|
|
10580
10624
|
const deletedPPr = addParagraphMarkRevision(sourcePPr, "del", author, revisionIdAllocator);
|
|
10581
10625
|
const deletedParagraph = serializeToOoxml(deletionRuns, deletedPPr, [], {
|
|
10582
10626
|
author,
|
|
@@ -14581,7 +14625,11 @@ function applyReconstructionMode(xmlDoc, originalText, modifiedText, serializer,
|
|
|
14581
14625
|
if (mapping.paragraphs.length === 0) {
|
|
14582
14626
|
return withOoxmlSourceType({ oxml: serializer.serializeToString(xmlDoc), hasChanges: false });
|
|
14583
14627
|
}
|
|
14584
|
-
const
|
|
14628
|
+
const wordDiffs = computeWordDiffs(mapping.originalFullText, mapping.processedModifiedText, {
|
|
14629
|
+
...diffOptions,
|
|
14630
|
+
atomicChars: new Set(mapping.referenceMap.keys())
|
|
14631
|
+
});
|
|
14632
|
+
const diffs = keepUnchangedTextOutsideWrappers(anchorSharedReferences(wordDiffs, mapping.referenceMap), mapping);
|
|
14585
14633
|
return withOoxmlSourceType(applyReconstructionDiffs(
|
|
14586
14634
|
xmlDoc,
|
|
14587
14635
|
diffs,
|
|
@@ -14593,6 +14641,109 @@ function applyReconstructionMode(xmlDoc, originalText, modifiedText, serializer,
|
|
|
14593
14641
|
options
|
|
14594
14642
|
));
|
|
14595
14643
|
}
|
|
14644
|
+
function forEachChangeGroup(diffs, onEqual, onGroup) {
|
|
14645
|
+
let index = 0;
|
|
14646
|
+
while (index < diffs.length) {
|
|
14647
|
+
if (diffs[index][0] === 0) {
|
|
14648
|
+
onEqual(diffs[index]);
|
|
14649
|
+
index++;
|
|
14650
|
+
continue;
|
|
14651
|
+
}
|
|
14652
|
+
const group = [];
|
|
14653
|
+
while (index < diffs.length && diffs[index][0] !== 0) group.push(diffs[index++]);
|
|
14654
|
+
onGroup(
|
|
14655
|
+
group,
|
|
14656
|
+
group.filter(([op]) => op === -1).map(([, text2]) => text2).join(""),
|
|
14657
|
+
group.filter(([op]) => op === 1).map(([, text2]) => text2).join("")
|
|
14658
|
+
);
|
|
14659
|
+
}
|
|
14660
|
+
}
|
|
14661
|
+
function pushChange(result, deleted, inserted) {
|
|
14662
|
+
if (deleted === inserted) {
|
|
14663
|
+
if (deleted) result.push([0, deleted]);
|
|
14664
|
+
return;
|
|
14665
|
+
}
|
|
14666
|
+
if (deleted) result.push([-1, deleted]);
|
|
14667
|
+
if (inserted) result.push([1, inserted]);
|
|
14668
|
+
}
|
|
14669
|
+
function anchorSharedReferences(diffs, referenceMap) {
|
|
14670
|
+
if (referenceMap.size === 0) return diffs;
|
|
14671
|
+
const result = [];
|
|
14672
|
+
forEachChangeGroup(diffs, (part) => result.push(part), (group, deleted, inserted) => {
|
|
14673
|
+
const deletedRefs = [...deleted].filter((char) => referenceMap.has(char) && inserted.includes(char));
|
|
14674
|
+
const insertedRefs = [...inserted].filter((char) => deletedRefs.includes(char));
|
|
14675
|
+
if (deletedRefs.length === 0 || deletedRefs.join("") !== insertedRefs.join("")) {
|
|
14676
|
+
result.push(...group);
|
|
14677
|
+
return;
|
|
14678
|
+
}
|
|
14679
|
+
let deletedStart = 0;
|
|
14680
|
+
let insertedStart = 0;
|
|
14681
|
+
for (const ref of deletedRefs) {
|
|
14682
|
+
const deletedAt = deleted.indexOf(ref, deletedStart);
|
|
14683
|
+
const insertedAt = inserted.indexOf(ref, insertedStart);
|
|
14684
|
+
pushChange(result, deleted.slice(deletedStart, deletedAt), inserted.slice(insertedStart, insertedAt));
|
|
14685
|
+
result.push([0, ref]);
|
|
14686
|
+
deletedStart = deletedAt + 1;
|
|
14687
|
+
insertedStart = insertedAt + 1;
|
|
14688
|
+
}
|
|
14689
|
+
pushChange(result, deleted.slice(deletedStart), inserted.slice(insertedStart));
|
|
14690
|
+
});
|
|
14691
|
+
return result;
|
|
14692
|
+
}
|
|
14693
|
+
function commonPrefixLength(left, right) {
|
|
14694
|
+
const limit = Math.min(left.length, right.length);
|
|
14695
|
+
let length = 0;
|
|
14696
|
+
while (length < limit && left[length] === right[length]) length++;
|
|
14697
|
+
return length;
|
|
14698
|
+
}
|
|
14699
|
+
function commonSuffixLength(left, right, limit) {
|
|
14700
|
+
let length = 0;
|
|
14701
|
+
while (length < limit && left[left.length - 1 - length] === right[right.length - 1 - length]) length++;
|
|
14702
|
+
return length;
|
|
14703
|
+
}
|
|
14704
|
+
function keepUnchangedTextOutsideWrappers(diffs, mapping) {
|
|
14705
|
+
const wrapperAt = (index) => mapping.getRunProperties(index).wrapper || null;
|
|
14706
|
+
const result = [];
|
|
14707
|
+
let originalOffset = 0;
|
|
14708
|
+
forEachChangeGroup(diffs, (part) => {
|
|
14709
|
+
result.push(part);
|
|
14710
|
+
originalOffset += part[1].length;
|
|
14711
|
+
}, (group, deleted, inserted) => {
|
|
14712
|
+
const start = originalOffset;
|
|
14713
|
+
const end = start + deleted.length;
|
|
14714
|
+
originalOffset = end;
|
|
14715
|
+
const isWrapperBoundary = (index) => index > start && index < end && wrapperAt(index - 1) !== wrapperAt(index);
|
|
14716
|
+
let prefix = 0;
|
|
14717
|
+
let suffix = 0;
|
|
14718
|
+
if (deleted && inserted) {
|
|
14719
|
+
const sharedSuffix = commonSuffixLength(deleted, inserted, Math.min(deleted.length, inserted.length));
|
|
14720
|
+
for (let length = sharedSuffix; length > 0; length--) {
|
|
14721
|
+
if (isWrapperBoundary(end - length)) {
|
|
14722
|
+
suffix = length;
|
|
14723
|
+
break;
|
|
14724
|
+
}
|
|
14725
|
+
}
|
|
14726
|
+
const sharedPrefix = Math.min(
|
|
14727
|
+
commonPrefixLength(deleted, inserted),
|
|
14728
|
+
Math.min(deleted.length, inserted.length) - suffix
|
|
14729
|
+
);
|
|
14730
|
+
for (let length = sharedPrefix; length > 0; length--) {
|
|
14731
|
+
if (isWrapperBoundary(start + length)) {
|
|
14732
|
+
prefix = length;
|
|
14733
|
+
break;
|
|
14734
|
+
}
|
|
14735
|
+
}
|
|
14736
|
+
}
|
|
14737
|
+
if (prefix === 0 && suffix === 0) {
|
|
14738
|
+
result.push(...group);
|
|
14739
|
+
return;
|
|
14740
|
+
}
|
|
14741
|
+
if (prefix > 0) result.push([0, deleted.slice(0, prefix)]);
|
|
14742
|
+
pushChange(result, deleted.slice(prefix, deleted.length - suffix), inserted.slice(prefix, inserted.length - suffix));
|
|
14743
|
+
if (suffix > 0) result.push([0, deleted.slice(deleted.length - suffix)]);
|
|
14744
|
+
});
|
|
14745
|
+
return result;
|
|
14746
|
+
}
|
|
14596
14747
|
|
|
14597
14748
|
// engine/table-mode.js
|
|
14598
14749
|
function noChanges(serializer, xmlDoc) {
|
|
@@ -16667,12 +16818,12 @@ function validateParagraphBoundaryMutation(targetParagraph, modifiedText, option
|
|
|
16667
16818
|
}
|
|
16668
16819
|
|
|
16669
16820
|
// core/list-targeting.js
|
|
16670
|
-
function
|
|
16671
|
-
if (!node
|
|
16672
|
-
const
|
|
16673
|
-
|
|
16674
|
-
|
|
16675
|
-
return
|
|
16821
|
+
function getDirectChildByLocalName(node, localName2) {
|
|
16822
|
+
if (!node) return null;
|
|
16823
|
+
for (const child of Array.from(node.childNodes || [])) {
|
|
16824
|
+
if (child?.nodeType === 1 && child.localName === localName2) return child;
|
|
16825
|
+
}
|
|
16826
|
+
return null;
|
|
16676
16827
|
}
|
|
16677
16828
|
function readValAttribute(element) {
|
|
16678
16829
|
if (!element) return null;
|
|
@@ -16789,15 +16940,15 @@ function buildListEntriesForInsertion(parsedItems, normalizedTargetText, anchorL
|
|
|
16789
16940
|
}
|
|
16790
16941
|
function getParagraphListInfo(paragraph) {
|
|
16791
16942
|
if (!paragraph) return null;
|
|
16792
|
-
const pPr =
|
|
16943
|
+
const pPr = getDirectChildByLocalName(paragraph, "pPr");
|
|
16793
16944
|
if (!pPr) return null;
|
|
16794
|
-
const numPr =
|
|
16945
|
+
const numPr = getDirectChildByLocalName(pPr, "numPr");
|
|
16795
16946
|
if (!numPr) return null;
|
|
16796
|
-
const numIdEl =
|
|
16947
|
+
const numIdEl = getDirectChildByLocalName(numPr, "numId");
|
|
16797
16948
|
if (!numIdEl) return null;
|
|
16798
16949
|
const numId = readValAttribute(numIdEl);
|
|
16799
16950
|
if (!numId || numId === "0") return null;
|
|
16800
|
-
const ilvlEl =
|
|
16951
|
+
const ilvlEl = getDirectChildByLocalName(numPr, "ilvl");
|
|
16801
16952
|
const ilvlRaw = readValAttribute(ilvlEl);
|
|
16802
16953
|
const ilvl = Number.parseInt(ilvlRaw || "0", 10);
|
|
16803
16954
|
return {
|
|
@@ -17207,8 +17358,13 @@ function enforceListBindingOnParagraphNodes(nodes, options = {}) {
|
|
|
17207
17358
|
}
|
|
17208
17359
|
return updated;
|
|
17209
17360
|
}
|
|
17361
|
+
function parseOxmlFragment(oxml) {
|
|
17362
|
+
const text2 = String(oxml || "");
|
|
17363
|
+
const declared = /xmlns:w\s*=/.test(text2);
|
|
17364
|
+
return parseOoxmlSafe(declared ? text2 : `<w:root xmlns:w="${NS_W}">${text2}</w:root>`, "application/xml").doc;
|
|
17365
|
+
}
|
|
17210
17366
|
function getFirstParagraphFromOxml(oxml) {
|
|
17211
|
-
const doc =
|
|
17367
|
+
const doc = parseOxmlFragment(oxml);
|
|
17212
17368
|
if (!doc) return null;
|
|
17213
17369
|
const parseError = getXmlParseError(doc);
|
|
17214
17370
|
if (parseError) return null;
|
|
@@ -17235,17 +17391,17 @@ function setElementVal(element, value) {
|
|
|
17235
17391
|
element.setAttribute("w:val", String(value));
|
|
17236
17392
|
}
|
|
17237
17393
|
function extractFirstParagraphNumIdFromOxml(oxml) {
|
|
17238
|
-
const doc =
|
|
17394
|
+
const doc = parseOxmlFragment(oxml);
|
|
17239
17395
|
if (!doc) return null;
|
|
17240
17396
|
const parseError = getXmlParseError(doc);
|
|
17241
17397
|
if (parseError) return null;
|
|
17242
17398
|
const paragraphs = getDocumentParagraphNodes(doc);
|
|
17243
|
-
const
|
|
17244
|
-
|
|
17245
|
-
|
|
17246
|
-
|
|
17247
|
-
|
|
17248
|
-
|
|
17399
|
+
for (const paragraph of paragraphs) {
|
|
17400
|
+
const numIdNodes = Array.from(paragraph.getElementsByTagNameNS("*", "numId"));
|
|
17401
|
+
for (const numIdNode of numIdNodes) {
|
|
17402
|
+
const numId = getElementId(numIdNode, ["w:val", "val"]);
|
|
17403
|
+
if (numId != null) return String(numId);
|
|
17404
|
+
}
|
|
17249
17405
|
}
|
|
17250
17406
|
return null;
|
|
17251
17407
|
}
|
|
@@ -17741,6 +17897,8 @@ function createDynamicNumberingIdState(numberingXml, options = {}) {
|
|
|
17741
17897
|
const baseNumId = Math.max(minId, maxUsedNumId + 1);
|
|
17742
17898
|
const baseAbstractNumId = Math.max(minId, maxUsedAbstractNumId + 1);
|
|
17743
17899
|
return {
|
|
17900
|
+
// Kept so list edits can recognise which existing definition a source list uses and continue it.
|
|
17901
|
+
sourceNumberingXml: String(numberingXml || ""),
|
|
17744
17902
|
nextNumId: nextAvailableId(baseNumId, usedNumIds, maxPreferred),
|
|
17745
17903
|
nextAbstractNumId: nextAvailableId(baseAbstractNumId, usedAbstractNumIds, maxPreferred),
|
|
17746
17904
|
usedNumIds,
|
|
@@ -17881,6 +18039,82 @@ function buildExplicitDecimalMultilevelNumberingXml(numId, abstractNumId, startA
|
|
|
17881
18039
|
</w:num>
|
|
17882
18040
|
</w:numbering>`.trim();
|
|
17883
18041
|
}
|
|
18042
|
+
function isTrackedDeletedParagraph(node) {
|
|
18043
|
+
if (!node || node.nodeType !== 1 || node.localName !== "p") return false;
|
|
18044
|
+
const pPr = Array.from(node.childNodes || []).find((child) => isDirectWordChild(child, "pPr"));
|
|
18045
|
+
const rPr = pPr && Array.from(pPr.childNodes || []).find((child) => isDirectWordChild(child, "rPr"));
|
|
18046
|
+
return !!rPr && Array.from(rPr.childNodes || []).some((child) => isDirectWordChild(child, "del"));
|
|
18047
|
+
}
|
|
18048
|
+
function paragraphNumIdNodes(node) {
|
|
18049
|
+
return Array.from(node?.getElementsByTagNameNS?.("*", "numId") || []).filter((numIdNode) => numIdNode.parentNode?.localName === "numPr");
|
|
18050
|
+
}
|
|
18051
|
+
function levelFormats(abstractNum) {
|
|
18052
|
+
const formats = /* @__PURE__ */ new Map();
|
|
18053
|
+
for (const lvl of Array.from(abstractNum?.getElementsByTagNameNS?.("*", "lvl") || [])) {
|
|
18054
|
+
const ilvl = getElementId2(lvl, ["w:ilvl", "ilvl"]);
|
|
18055
|
+
const fmt = Array.from(lvl.getElementsByTagNameNS("*", "numFmt"))[0]?.getAttribute("w:val") || null;
|
|
18056
|
+
if (ilvl != null && fmt) formats.set(ilvl, fmt);
|
|
18057
|
+
}
|
|
18058
|
+
return formats;
|
|
18059
|
+
}
|
|
18060
|
+
function normalizeListFormat(format) {
|
|
18061
|
+
return format === "bullet" || format === "circle" || format === "square" ? "bullet" : format;
|
|
18062
|
+
}
|
|
18063
|
+
function abstractNumForNumId(numberingDoc, numId) {
|
|
18064
|
+
const num = Array.from(numberingDoc.getElementsByTagNameNS("*", "num")).find((candidate) => getElementId2(candidate, ["w:numId", "numId"]) === numId);
|
|
18065
|
+
const abstractId = num && getElementId2(Array.from(num.getElementsByTagNameNS("*", "abstractNumId"))[0], ["w:val", "val"]);
|
|
18066
|
+
if (abstractId == null) return null;
|
|
18067
|
+
return Array.from(numberingDoc.getElementsByTagNameNS("*", "abstractNum")).find((candidate) => getElementId2(candidate, ["w:abstractNumId", "abstractNumId"]) === abstractId) || null;
|
|
18068
|
+
}
|
|
18069
|
+
function reuseSourceListNumbering(numberingXml, replacementNodes, sourceParagraphs, numberingIdState) {
|
|
18070
|
+
const sourceXml = numberingIdState?.sourceNumberingXml;
|
|
18071
|
+
if (!numberingXml || !String(sourceXml || "").trim() || !Array.isArray(replacementNodes)) return null;
|
|
18072
|
+
const sourceNumIds = /* @__PURE__ */ new Set();
|
|
18073
|
+
for (const paragraph of sourceParagraphs || []) {
|
|
18074
|
+
for (const numIdNode of paragraphNumIdNodes(paragraph)) {
|
|
18075
|
+
const id = getElementId2(numIdNode, ["w:val", "val"]);
|
|
18076
|
+
if (id != null && id !== 0) sourceNumIds.add(id);
|
|
18077
|
+
}
|
|
18078
|
+
}
|
|
18079
|
+
if (sourceNumIds.size !== 1) return null;
|
|
18080
|
+
const [sourceNumId] = sourceNumIds;
|
|
18081
|
+
const sourceDoc = parseOoxml(sourceXml);
|
|
18082
|
+
const payloadDoc = parseOoxml(numberingXml);
|
|
18083
|
+
if (hasXmlParseError(sourceDoc) || hasXmlParseError(payloadDoc)) return null;
|
|
18084
|
+
const sourceAbstract = abstractNumForNumId(sourceDoc, sourceNumId);
|
|
18085
|
+
if (!sourceAbstract) return null;
|
|
18086
|
+
const sourceFormats = levelFormats(sourceAbstract);
|
|
18087
|
+
const newParagraphNumIds = [];
|
|
18088
|
+
for (const node of replacementNodes) {
|
|
18089
|
+
if (isTrackedDeletedParagraph(node)) continue;
|
|
18090
|
+
for (const numIdNode of paragraphNumIdNodes(node)) {
|
|
18091
|
+
const ilvlNode = Array.from(numIdNode.parentNode.childNodes || []).find((child) => child.localName === "ilvl");
|
|
18092
|
+
newParagraphNumIds.push({
|
|
18093
|
+
numId: getElementId2(numIdNode, ["w:val", "val"]),
|
|
18094
|
+
ilvl: ilvlNode ? getElementId2(ilvlNode, ["w:val", "val"]) ?? 0 : 0
|
|
18095
|
+
});
|
|
18096
|
+
}
|
|
18097
|
+
}
|
|
18098
|
+
if (newParagraphNumIds.length === 0) return null;
|
|
18099
|
+
const payloadFormats = /* @__PURE__ */ new Map();
|
|
18100
|
+
for (const { numId, ilvl } of newParagraphNumIds) {
|
|
18101
|
+
if (numId == null) return null;
|
|
18102
|
+
if (!payloadFormats.has(numId)) {
|
|
18103
|
+
const abstract = abstractNumForNumId(payloadDoc, numId);
|
|
18104
|
+
if (!abstract) return null;
|
|
18105
|
+
payloadFormats.set(numId, levelFormats(abstract));
|
|
18106
|
+
}
|
|
18107
|
+
const generated = payloadFormats.get(numId).get(ilvl);
|
|
18108
|
+
const existing = sourceFormats.get(ilvl);
|
|
18109
|
+
if (!generated || !existing || normalizeListFormat(generated) !== normalizeListFormat(existing)) return null;
|
|
18110
|
+
}
|
|
18111
|
+
const clonedNodes = replacementNodes.map((node) => node?.cloneNode ? node.cloneNode(true) : node);
|
|
18112
|
+
for (const node of clonedNodes) {
|
|
18113
|
+
if (isTrackedDeletedParagraph(node)) continue;
|
|
18114
|
+
for (const numIdNode of paragraphNumIdNodes(node)) setElementVal2(numIdNode, sourceNumId);
|
|
18115
|
+
}
|
|
18116
|
+
return { numId: sourceNumId, replacementNodes: clonedNodes };
|
|
18117
|
+
}
|
|
17884
18118
|
function remapNumberingPayloadForDocument(numberingXml, replacementNodes, numberingIdState) {
|
|
17885
18119
|
const numberingDoc = parseOoxml(numberingXml);
|
|
17886
18120
|
if (hasXmlParseError(numberingDoc)) {
|
|
@@ -17918,6 +18152,7 @@ function remapNumberingPayloadForDocument(numberingXml, replacementNodes, number
|
|
|
17918
18152
|
}
|
|
17919
18153
|
const clonedNodes = Array.isArray(replacementNodes) ? replacementNodes.map((node) => node?.cloneNode ? node.cloneNode(true) : node) : [];
|
|
17920
18154
|
for (const node of clonedNodes) {
|
|
18155
|
+
if (isTrackedDeletedParagraph(node)) continue;
|
|
17921
18156
|
const numIdNodes = Array.from(node?.getElementsByTagNameNS?.("*", "numId") || []);
|
|
17922
18157
|
for (const numIdNode of numIdNodes) {
|
|
17923
18158
|
const oldNumRef = getElementId2(numIdNode, ["w:val", "val"]);
|
|
@@ -18738,6 +18973,8 @@ function areRevisionTokensEqual(a, b) {
|
|
|
18738
18973
|
var attr2 = (node, name) => node?.getAttribute?.(`w:${name}`) || node?.getAttribute?.(name) || "";
|
|
18739
18974
|
var descendants = (node, name) => Array.from(node?.getElementsByTagNameNS?.(NS_W, name) || []);
|
|
18740
18975
|
var first = (node, name) => descendants(node, name)[0] || null;
|
|
18976
|
+
var directChild2 = (node, name) => Array.from(node?.childNodes || []).find((child) => child?.nodeType === 1 && child.localName === name && (!child.namespaceURI || child.namespaceURI === NS_W)) || null;
|
|
18977
|
+
var currentPPr = (paragraph) => directChild2(paragraph, "pPr");
|
|
18741
18978
|
function hasAncestor(node, localName2) {
|
|
18742
18979
|
let cursor = node?.parentNode;
|
|
18743
18980
|
while (cursor) {
|
|
@@ -18753,11 +18990,11 @@ function parseXml2(xml, partName, required = false) {
|
|
|
18753
18990
|
return { doc: parsed.doc, warnings: parsed.warnings || [] };
|
|
18754
18991
|
}
|
|
18755
18992
|
function paragraphListProperties(paragraph) {
|
|
18756
|
-
const numPr =
|
|
18993
|
+
const numPr = directChild2(currentPPr(paragraph), "numPr");
|
|
18757
18994
|
if (!numPr) return null;
|
|
18758
|
-
const numId = attr2(
|
|
18995
|
+
const numId = attr2(directChild2(numPr, "numId"), "val");
|
|
18759
18996
|
if (!numId || numId === "0") return null;
|
|
18760
|
-
return { numId, level: Number.parseInt(attr2(
|
|
18997
|
+
return { numId, level: Number.parseInt(attr2(directChild2(numPr, "ilvl"), "val") || "0", 10) || 0 };
|
|
18761
18998
|
}
|
|
18762
18999
|
function parseNumbering(numberingDoc) {
|
|
18763
19000
|
const abstracts = /* @__PURE__ */ new Map();
|
|
@@ -18842,11 +19079,11 @@ function createNumberingResolver(numberingDoc) {
|
|
|
18842
19079
|
};
|
|
18843
19080
|
}
|
|
18844
19081
|
function headingLevel(paragraph) {
|
|
18845
|
-
const pPr =
|
|
18846
|
-
const style = attr2(
|
|
19082
|
+
const pPr = currentPPr(paragraph);
|
|
19083
|
+
const style = attr2(directChild2(pPr, "pStyle"), "val");
|
|
18847
19084
|
const match = style.match(/^heading\s*([1-9])$/i);
|
|
18848
19085
|
if (match) return Math.min(Number(match[1]), 6);
|
|
18849
|
-
const outline = Number.parseInt(attr2(
|
|
19086
|
+
const outline = Number.parseInt(attr2(directChild2(pPr, "outlineLvl"), "val"), 10);
|
|
18850
19087
|
return Number.isInteger(outline) ? Math.min(outline + 1, 6) : null;
|
|
18851
19088
|
}
|
|
18852
19089
|
function structuralContext(paragraph, text2) {
|
|
@@ -19025,7 +19262,7 @@ function inspectDocumentParts(parts, options = {}) {
|
|
|
19025
19262
|
const ids = [...new Set([...descendants(paragraph, "commentRangeStart"), ...descendants(paragraph, "commentReference")].map((node) => attr2(node, "id")).filter(Boolean))];
|
|
19026
19263
|
const authors = revisionAuthors(paragraph);
|
|
19027
19264
|
const list = resolveNumbering(paragraphListProperties(paragraph));
|
|
19028
|
-
const styleId = attr2(
|
|
19265
|
+
const styleId = attr2(directChild2(currentPPr(paragraph), "pStyle"), "val") || null;
|
|
19029
19266
|
const structure = structuralContext(paragraph, text2);
|
|
19030
19267
|
const index = zeroIndex + 1;
|
|
19031
19268
|
const provision = list?.label && list.format !== "bullet" ? list.label : null;
|
|
@@ -24426,7 +24663,9 @@ async function applyToParagraphByExactText(documentXml, targetText, modifiedText
|
|
|
24426
24663
|
paragraphText,
|
|
24427
24664
|
generateRedlines ? createRevisionMetadata(author, xmlDoc) : null,
|
|
24428
24665
|
author,
|
|
24429
|
-
|
|
24666
|
+
// A wholly inserted paragraph must track its own paragraph mark; otherwise Word's
|
|
24667
|
+
// Reject All removes the text but leaves an empty paragraph behind.
|
|
24668
|
+
{ generateRedlines, trackParagraphMark: true }
|
|
24430
24669
|
);
|
|
24431
24670
|
const imported = xmlDoc.importNode(plainParagraph, true);
|
|
24432
24671
|
ensureParagraphIdsOnImportedNode(imported, operationSession);
|
|
@@ -24557,6 +24796,14 @@ async function applyToParagraphByExactText(documentXml, targetText, modifiedText
|
|
|
24557
24796
|
const extracted = extractReplacementNodes(result.oxml);
|
|
24558
24797
|
let replacementNodes = removeListPackagingSentinel(extracted.replacementNodes, result.warnings);
|
|
24559
24798
|
let numberingXml = extracted.numberingXml;
|
|
24799
|
+
if (numberingXml && runtimeContext?.numberingIdState && !useTableScope) {
|
|
24800
|
+
const sourceParagraphs = useListScope ? listScopeEdit.paragraphs : explicitRangeParagraphs || [targetParagraph];
|
|
24801
|
+
const continued = reuseSourceListNumbering(numberingXml, replacementNodes, sourceParagraphs, runtimeContext.numberingIdState);
|
|
24802
|
+
if (continued) {
|
|
24803
|
+
replacementNodes = continued.replacementNodes;
|
|
24804
|
+
numberingXml = null;
|
|
24805
|
+
}
|
|
24806
|
+
}
|
|
24560
24807
|
if (numberingXml && runtimeContext?.numberingIdState) {
|
|
24561
24808
|
const normalizedNumbering = remapNumberingPayloadForDocument(numberingXml, replacementNodes, runtimeContext.numberingIdState);
|
|
24562
24809
|
replacementNodes = normalizedNumbering.replacementNodes;
|