@superdoc/mcp 1.2.1-next.1 → 1.2.1-next.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/dist/index.js +534 -108
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -31314,7 +31314,7 @@ var init_host = __esm(() => {
|
|
|
31314
31314
|
});
|
|
31315
31315
|
|
|
31316
31316
|
// ../../packages/sdk/langs/node/src/runtime/sdk-version.generated.ts
|
|
31317
|
-
var SDK_VERSION = "2.15.1-next.
|
|
31317
|
+
var SDK_VERSION = "2.15.1-next.3";
|
|
31318
31318
|
|
|
31319
31319
|
// ../../packages/sdk/langs/node/src/runtime/embedded-platform.ts
|
|
31320
31320
|
import { chmodSync, existsSync } from "node:fs";
|
|
@@ -140090,7 +140090,9 @@ function markFullParagraphInsertions(xml, fragments, structural, index, namespac
|
|
|
140090
140090
|
continue;
|
|
140091
140091
|
const structuralInParagraph = structuralByParagraph.get(`${paragraph.start}:${paragraph.end}`) ?? [];
|
|
140092
140092
|
const terminalDeletionOfPendingInsertion = marker.structuralKind === "paragraph-mark-insertion" && structuralInParagraph.length === 2 && structuralInParagraph[0] === marker && structuralInParagraph[1]?.structuralKind === "paragraph-mark-deletion";
|
|
140093
|
-
|
|
140093
|
+
const extraStructural = structuralInParagraph.filter((fragment2) => fragment2 !== marker);
|
|
140094
|
+
const extrasArePasteObjects = extraStructural.every((fragment2) => fragment2.structuralKind === "footnote-insertion" || fragment2.structuralKind === "endnote-insertion" || fragment2.structuralKind === "image-insertion" || fragment2.structuralKind === "field-insertion");
|
|
140095
|
+
if (structuralInParagraph.length !== 1 && !terminalDeletionOfPendingInsertion && !(extraStructural.length > 0 && extrasArePasteObjects))
|
|
140094
140096
|
continue;
|
|
140095
140097
|
const paragraphFragments = (fragmentsByParagraphStart.get(paragraph.start) ?? []).filter((candidate) => candidate.byteStart >= paragraph.openEnd && candidate.byteEnd <= paragraph.closeStart).sort((left, right) => left.byteStart - right.byteStart);
|
|
140096
140098
|
const markerIdentity = buildReviewIdentity({
|
|
@@ -162775,7 +162777,7 @@ var init_collapsed_inline_insertion_site = __esm(() => {
|
|
|
162775
162777
|
});
|
|
162776
162778
|
|
|
162777
162779
|
// ../../../v2/editor-core/dist/document/transactions/compile-edit-text-inline-plan.js
|
|
162778
|
-
function planDirectInlineEdit(paragraphBytes, startOffset, endOffset, newText, collapsedObjectBoundary, collapsedInlineAffinity, inheritedNamespaceBindings = {}) {
|
|
162780
|
+
function planDirectInlineEdit(paragraphBytes, startOffset, endOffset, newText, collapsedObjectBoundary, collapsedInlineAffinity, inheritedNamespaceBindings = {}, collapsedOutsideContentControl = false) {
|
|
162779
162781
|
const xml = TD21.decode(paragraphBytes);
|
|
162780
162782
|
const model = parseParagraphInlineMap(xml, inheritedNamespaceBindings);
|
|
162781
162783
|
const leaves = model.leaves();
|
|
@@ -162818,7 +162820,7 @@ function planDirectInlineEdit(paragraphBytes, startOffset, endOffset, newText, c
|
|
|
162818
162820
|
if (beside)
|
|
162819
162821
|
return beside;
|
|
162820
162822
|
}
|
|
162821
|
-
const scope = resolveEditScope(model.pieces, startOffset, endOffset, collapsedInlineAffinity);
|
|
162823
|
+
const scope = resolveEditScope(model.pieces, startOffset, endOffset, collapsedInlineAffinity, collapsedOutsideContentControl);
|
|
162822
162824
|
if (!scope.ok)
|
|
162823
162825
|
return { ok: false, reason: scope.reason };
|
|
162824
162826
|
const pieces = scope.pieces;
|
|
@@ -162830,7 +162832,7 @@ function planDirectInlineEdit(paragraphBytes, startOffset, endOffset, newText, c
|
|
|
162830
162832
|
return { ok: false, reason: "invalid-range" };
|
|
162831
162833
|
}
|
|
162832
162834
|
const hasEditableLeaf = pieces.some((piece) => isVisibleText(piece) || isLiveControl(piece) || startOffset !== endOffset && isLiveNoteReference(piece));
|
|
162833
|
-
if (!hasEditableLeaf) {
|
|
162835
|
+
if (!hasEditableLeaf && !(collapsedOutsideContentControl && startOffset === endOffset && newText.length > 0)) {
|
|
162834
162836
|
if (newText.length === 0 && scope.wrapperRemovalOps.length > 0) {
|
|
162835
162837
|
return {
|
|
162836
162838
|
ok: true,
|
|
@@ -162847,7 +162849,7 @@ function planDirectInlineEdit(paragraphBytes, startOffset, endOffset, newText, c
|
|
|
162847
162849
|
}
|
|
162848
162850
|
if (startOffset === endOffset) {
|
|
162849
162851
|
const plan2 = planCollapsedInsert(paragraphBytes, xml, pieces, leaves, startOffset, newText, visibleLength === 0, inlineContext, collapsedInlineAffinity);
|
|
162850
|
-
return plan2.ok && scope.requiresCollaborationSessionSync ? { ...plan2, requiresCollaborationSessionSync: true } : plan2;
|
|
162852
|
+
return plan2.ok && (scope.requiresCollaborationSessionSync || collapsedOutsideContentControl) ? { ...plan2, requiresCollaborationSessionSync: true } : plan2;
|
|
162851
162853
|
}
|
|
162852
162854
|
const plan = planReplace(paragraphBytes, pieces, leaves, startOffset, endOffset, newText, scope.wrapperRemovalOps);
|
|
162853
162855
|
return plan.ok && (scope.requiresCollaborationSessionSync || preservesCrossedBookmarks) ? { ...plan, requiresCollaborationSessionSync: true } : plan;
|
|
@@ -163439,13 +163441,13 @@ function hasNonWordMarkerAtCollapsedMoveBoundary(pieces, at, coordinateSpace = "
|
|
|
163439
163441
|
function firstNonFieldRangeStartMarker(markers) {
|
|
163440
163442
|
return markers.find((piece) => piece.role === "range-start" && !isFieldMarker(piece.markerKind)) ?? null;
|
|
163441
163443
|
}
|
|
163442
|
-
function resolveEditScope(pieces, start, end, collapsedInlineAffinity) {
|
|
163444
|
+
function resolveEditScope(pieces, start, end, collapsedInlineAffinity, collapsedOutsideContentControl = false) {
|
|
163443
163445
|
let current = pieces;
|
|
163444
163446
|
let descended = false;
|
|
163445
163447
|
let emptySdt;
|
|
163446
163448
|
let requiresCollaborationSessionSync = false;
|
|
163447
163449
|
for (;; ) {
|
|
163448
|
-
const container = current.find((piece) => piece.kind === "container" && containerContainsRange(piece, start, end)) ?? (start === end ? findCollapsedEdgeContainer(current, start, collapsedInlineAffinity
|
|
163450
|
+
const container = current.find((piece) => piece.kind === "container" && containerContainsRange(piece, start, end)) ?? (start === end ? findCollapsedEdgeContainer(current, start, collapsedInlineAffinity, collapsedOutsideContentControl) : undefined);
|
|
163449
163451
|
if (!container) {
|
|
163450
163452
|
if (start === end) {
|
|
163451
163453
|
return {
|
|
@@ -163548,9 +163550,24 @@ function containerContainsRange(piece, start, end) {
|
|
|
163548
163550
|
return piece.visibleStart < start && start < piece.visibleEnd;
|
|
163549
163551
|
return piece.visibleStart <= start && end <= piece.visibleEnd;
|
|
163550
163552
|
}
|
|
163551
|
-
function findCollapsedEdgeContainer(pieces, at,
|
|
163553
|
+
function findCollapsedEdgeContainer(pieces, at, collapsedInlineAffinity, collapsedOutsideContentControl = false) {
|
|
163552
163554
|
const emptySdtsAtPoint = pieces.filter((piece) => piece.kind === "container" && piece.containerKind === "sdt" && piece.visibleStart === at && piece.visibleEnd === at);
|
|
163553
|
-
return pieces.find((piece) =>
|
|
163555
|
+
return pieces.find((piece) => {
|
|
163556
|
+
if (piece.kind !== "container")
|
|
163557
|
+
return false;
|
|
163558
|
+
if (collapsedOutsideContentControl && piece.containerKind === "sdt")
|
|
163559
|
+
return false;
|
|
163560
|
+
if (piece.visibleStart === piece.visibleEnd) {
|
|
163561
|
+
return collapsedInlineAffinity == null && emptySdtsAtPoint.length === 1 && piece.containerKind === "sdt" && piece.visibleStart === at;
|
|
163562
|
+
}
|
|
163563
|
+
if (piece.visibleStart === at) {
|
|
163564
|
+
return piece.containerKind === "sdt" ? collapsedInlineAffinity !== "upstream" : !hasVisibleSiblingEndingAt(pieces, at);
|
|
163565
|
+
}
|
|
163566
|
+
if (piece.visibleEnd === at) {
|
|
163567
|
+
return piece.containerKind === "sdt" ? collapsedInlineAffinity !== "downstream" && !hasVisibleSiblingStartingAt(pieces, at, "sdt") : !hasVisibleSiblingStartingAt(pieces, at);
|
|
163568
|
+
}
|
|
163569
|
+
return false;
|
|
163570
|
+
});
|
|
163554
163571
|
}
|
|
163555
163572
|
function planEmptySdtInsert(paragraphBytes, piece, newText) {
|
|
163556
163573
|
const raw = piece.rawXml;
|
|
@@ -168023,10 +168040,13 @@ function projectWordLikeReviewGroupsWithLookupContext(lookupContext, input) {
|
|
|
168023
168040
|
const partXml = input.partXmlByUri.get(partUri);
|
|
168024
168041
|
if (!partXml)
|
|
168025
168042
|
continue;
|
|
168026
|
-
if (isBodyStoryId(storyId)) {
|
|
168043
|
+
if (isBodyStoryId(storyId) || isNotesStoryId(storyId)) {
|
|
168027
168044
|
projectStoryReviewGroups(lookupContext, storyId, partUri, partXml, entries, input);
|
|
168028
168045
|
}
|
|
168029
168046
|
projectFullParagraphInsertions(lookupContext, storyId, partUri, partXml, entries, input);
|
|
168047
|
+
if (isBodyStoryId(storyId) || isNotesStoryId(storyId)) {
|
|
168048
|
+
foldSameRsidPastedParagraphParents(storyId, partXml, input);
|
|
168049
|
+
}
|
|
168030
168050
|
}
|
|
168031
168051
|
}
|
|
168032
168052
|
function projectFullParagraphInsertions(lookupContext, storyId, partUri, partXml, entries, input) {
|
|
@@ -168190,6 +168210,230 @@ function materializeFullParagraphInsertion(lookupContext, args) {
|
|
|
168190
168210
|
for (const fragment2 of objectFragments)
|
|
168191
168211
|
input.structuralKeyToLogicalId.set(fragment2.entityKey, id);
|
|
168192
168212
|
}
|
|
168213
|
+
function foldSameRsidPastedParagraphParents(storyId, partXml, input) {
|
|
168214
|
+
const storyEntries = input.byStory.get(storyId);
|
|
168215
|
+
if (!storyEntries)
|
|
168216
|
+
return;
|
|
168217
|
+
const parents = storyEntries.filter((entry) => isFoldablePastedParagraphParent(entry)).sort((left, right) => left.documentOrderStart - right.documentOrderStart);
|
|
168218
|
+
if (parents.length < 2)
|
|
168219
|
+
return;
|
|
168220
|
+
const clusters = [];
|
|
168221
|
+
let current = [];
|
|
168222
|
+
const flush = () => {
|
|
168223
|
+
if (current.length >= 2)
|
|
168224
|
+
clusters.push(current);
|
|
168225
|
+
current = [];
|
|
168226
|
+
};
|
|
168227
|
+
for (const parent of parents) {
|
|
168228
|
+
const previous = current.at(-1);
|
|
168229
|
+
if (!previous) {
|
|
168230
|
+
current = [parent];
|
|
168231
|
+
continue;
|
|
168232
|
+
}
|
|
168233
|
+
if (canFoldPastedParagraphParents(partXml, previous, parent, storyEntries)) {
|
|
168234
|
+
current.push(parent);
|
|
168235
|
+
continue;
|
|
168236
|
+
}
|
|
168237
|
+
flush();
|
|
168238
|
+
current = [parent];
|
|
168239
|
+
}
|
|
168240
|
+
flush();
|
|
168241
|
+
for (const cluster of clusters) {
|
|
168242
|
+
mergePastedParagraphParents(storyId, partXml, cluster, input);
|
|
168243
|
+
}
|
|
168244
|
+
}
|
|
168245
|
+
function isFoldablePastedParagraphParent(entry) {
|
|
168246
|
+
const kind = entry.reviewGroup?.kind;
|
|
168247
|
+
return entry.reviewGroup?.role === "parent" && (kind === "word-full-paragraph-insertion" || kind === "word-inserted-paragraph-range") && entry.subtype !== "table-split" && entry.subtype !== "image-insertion" && entry.subtype !== "list-item-insertion" && entry.subtype !== "field-insertion" && !entry.reviewGroup?.members.some((member) => member.subtype === "field-insertion") && pastedParagraphParentRsid(entry) != null;
|
|
168248
|
+
}
|
|
168249
|
+
function pastedParagraphParentRsid(entry) {
|
|
168250
|
+
const mark = entry.structuralFragments.find((fragment2) => fragment2.structuralKind === "paragraph-mark-insertion" || fragment2.structuralKind === "paragraph-insertion");
|
|
168251
|
+
const rsid = mark?.enclosingParagraphRsid ?? entry.sourceIds.rsids[0];
|
|
168252
|
+
return rsid ? rsid.toUpperCase() : null;
|
|
168253
|
+
}
|
|
168254
|
+
function pastedParagraphParentBounds(entry) {
|
|
168255
|
+
const marks = entry.structuralFragments.filter((fragment2) => fragment2.structuralKind === "paragraph-mark-insertion" || fragment2.structuralKind === "paragraph-insertion");
|
|
168256
|
+
const starts = marks.map((fragment2) => fragment2.enclosingElementStart).filter((value) => value != null);
|
|
168257
|
+
const ends = marks.map((fragment2) => fragment2.enclosingElementEnd).filter((value) => value != null);
|
|
168258
|
+
if (starts.length === 0 || ends.length === 0)
|
|
168259
|
+
return null;
|
|
168260
|
+
return { start: Math.min(...starts), end: Math.max(...ends) };
|
|
168261
|
+
}
|
|
168262
|
+
function canFoldPastedParagraphParents(partXml, previous, next, storyEntries) {
|
|
168263
|
+
if (pastedParagraphParentRsid(previous) !== pastedParagraphParentRsid(next))
|
|
168264
|
+
return false;
|
|
168265
|
+
if (previous.subtype !== next.subtype)
|
|
168266
|
+
return false;
|
|
168267
|
+
if (!isSameReviewGroupIdentity(buildReviewIdentity({
|
|
168268
|
+
name: previous.author.name,
|
|
168269
|
+
email: previous.authorEmail,
|
|
168270
|
+
initials: previous.author.initials
|
|
168271
|
+
}), buildReviewIdentity({
|
|
168272
|
+
name: next.author.name,
|
|
168273
|
+
email: next.authorEmail,
|
|
168274
|
+
initials: next.author.initials
|
|
168275
|
+
}))) {
|
|
168276
|
+
return false;
|
|
168277
|
+
}
|
|
168278
|
+
const previousBounds = pastedParagraphParentBounds(previous);
|
|
168279
|
+
const nextBounds = pastedParagraphParentBounds(next);
|
|
168280
|
+
if (!previousBounds || !nextBounds || nextBounds.start < previousBounds.end)
|
|
168281
|
+
return false;
|
|
168282
|
+
const stripped = partXml.slice(previousBounds.end, nextBounds.start).replace(/<\/?[\w.-]+:(?:footnote|endnote)\b[^>]*>/g, "");
|
|
168283
|
+
if (!isCleanGapXml(stripped))
|
|
168284
|
+
return false;
|
|
168285
|
+
return !hasInterveningVisibleReviewable(previous, next, storyEntries);
|
|
168286
|
+
}
|
|
168287
|
+
function hasInterveningVisibleReviewable(previous, next, storyEntries) {
|
|
168288
|
+
const spanStart = Math.min(previous.documentOrderStart, next.documentOrderStart);
|
|
168289
|
+
const spanEnd = Math.max(previous.documentOrderEnd, next.documentOrderEnd);
|
|
168290
|
+
const ownedIds = new Set([
|
|
168291
|
+
previous.id,
|
|
168292
|
+
next.id,
|
|
168293
|
+
...previous.reviewGroup?.ownedChildIds ?? [],
|
|
168294
|
+
...next.reviewGroup?.ownedChildIds ?? []
|
|
168295
|
+
]);
|
|
168296
|
+
for (const entry of storyEntries) {
|
|
168297
|
+
if (ownedIds.has(entry.id))
|
|
168298
|
+
continue;
|
|
168299
|
+
if (entry.reviewGroup?.role === "child")
|
|
168300
|
+
continue;
|
|
168301
|
+
if (entry.subsumption?.role === "child")
|
|
168302
|
+
continue;
|
|
168303
|
+
if (entry.documentOrderStart > spanStart && entry.documentOrderStart < spanEnd) {
|
|
168304
|
+
return true;
|
|
168305
|
+
}
|
|
168306
|
+
}
|
|
168307
|
+
return false;
|
|
168308
|
+
}
|
|
168309
|
+
function mergePastedParagraphParents(storyId, partXml, cluster, input) {
|
|
168310
|
+
const head = cluster[0];
|
|
168311
|
+
const memberEntries = [];
|
|
168312
|
+
const seenMemberIds = new Set;
|
|
168313
|
+
const addMember = (entry) => {
|
|
168314
|
+
if (!entry || seenMemberIds.has(entry.id))
|
|
168315
|
+
return;
|
|
168316
|
+
seenMemberIds.add(entry.id);
|
|
168317
|
+
memberEntries.push(entry);
|
|
168318
|
+
};
|
|
168319
|
+
for (const parent2 of cluster) {
|
|
168320
|
+
for (const childId of parent2.reviewGroup?.ownedChildIds ?? []) {
|
|
168321
|
+
addMember(input.byId.get(childId));
|
|
168322
|
+
}
|
|
168323
|
+
}
|
|
168324
|
+
if (memberEntries.length === 0 || memberEntries.some((entry) => entry.reviewGroup?.role === "child" && cluster.every((parent2) => parent2.id !== entry.reviewGroup?.parentId))) {
|
|
168325
|
+
return;
|
|
168326
|
+
}
|
|
168327
|
+
const textFragments = uniqueFragments(cluster.flatMap((parent2) => parent2.fragments));
|
|
168328
|
+
const structuralFragments = uniqueStructuralFragments(cluster.flatMap((parent2) => parent2.structuralFragments)).sort((left, right) => left.byteStart - right.byteStart);
|
|
168329
|
+
const members = cluster.flatMap((parent2) => parent2.reviewGroup?.members ?? []);
|
|
168330
|
+
const rsids = uniqueNonEmptyStrings(cluster.flatMap((parent2) => parent2.sourceIds.rsids));
|
|
168331
|
+
const memberWordIds = uniqueNonEmptyStrings([
|
|
168332
|
+
...cluster.flatMap((parent2) => [
|
|
168333
|
+
parent2.sourceIds.wordIdInsert ?? "",
|
|
168334
|
+
...parent2.sourceIds.wordIdOther
|
|
168335
|
+
]),
|
|
168336
|
+
...members.map((member) => member.wordId ?? "")
|
|
168337
|
+
]);
|
|
168338
|
+
const wordIdInsert = head.sourceIds.wordIdInsert ?? memberWordIds[0];
|
|
168339
|
+
const wordIdOther = memberWordIds.filter((id) => id !== wordIdInsert);
|
|
168340
|
+
const canonicalText = cluster.map((parent2) => {
|
|
168341
|
+
const text = parent2.after.text ?? "";
|
|
168342
|
+
return text.endsWith(`
|
|
168343
|
+
`) ? text : `${text}
|
|
168344
|
+
`;
|
|
168345
|
+
}).join("");
|
|
168346
|
+
const markParagraphIds = cluster.map((parent2) => {
|
|
168347
|
+
const start = parent2.structuralFragments.find((fragment2) => fragment2.structuralKind === "paragraph-mark-insertion")?.enclosingElementStart;
|
|
168348
|
+
return start != null ? readParagraphIdAt(partXml, start) : null;
|
|
168349
|
+
});
|
|
168350
|
+
const markKey = markParagraphIds.every((paraId) => paraId != null) ? markParagraphIds.map((paraId) => `p:${paraId}`).join(",") : cluster.map((parent2) => parent2.id).join(",");
|
|
168351
|
+
const identityKey = buildGroupIdentityKey(buildReviewIdentity({
|
|
168352
|
+
name: head.author.name,
|
|
168353
|
+
email: head.authorEmail,
|
|
168354
|
+
initials: head.author.initials
|
|
168355
|
+
}));
|
|
168356
|
+
const groupHash = hashGroupKey(["word-inserted-paragraph-range", storyId, identityKey, `pm:${markKey}`, `tx:${textFragments.length}`].join("|"));
|
|
168357
|
+
const groupId = buildLogicalId(storyId, "ins", "word-paragraph-range", groupHash);
|
|
168358
|
+
const noteIds = uniqueNonEmptyStrings(cluster.flatMap((entry) => ownedNoteIds(entry)));
|
|
168359
|
+
const parent = {
|
|
168360
|
+
...head,
|
|
168361
|
+
id: groupId,
|
|
168362
|
+
type: "insertion",
|
|
168363
|
+
subtype: "text-insertion",
|
|
168364
|
+
documentOrderStart: Math.min(...cluster.map((entry) => entry.documentOrderStart)),
|
|
168365
|
+
documentOrderEnd: Math.max(...cluster.map((entry) => entry.documentOrderEnd)),
|
|
168366
|
+
noteId: noteIds[0] ?? cluster.find((entry) => entry.noteId != null)?.noteId ?? head.noteId,
|
|
168367
|
+
noteIds: noteIds.length > 0 ? noteIds : null,
|
|
168368
|
+
sourceIds: { wordIdInsert, wordIdOther, rsids },
|
|
168369
|
+
revisionGroupId: groupId,
|
|
168370
|
+
after: { text: canonicalText },
|
|
168371
|
+
contributingRsids: rsids,
|
|
168372
|
+
fragments: textFragments,
|
|
168373
|
+
structuralFragments,
|
|
168374
|
+
structuralDelta: null,
|
|
168375
|
+
excerpt: canonicalText,
|
|
168376
|
+
reviewGroup: {
|
|
168377
|
+
kind: "word-inserted-paragraph-range",
|
|
168378
|
+
role: "parent",
|
|
168379
|
+
parentId: null,
|
|
168380
|
+
ownedChildIds: memberEntries.map((entry) => entry.id),
|
|
168381
|
+
duplicateDisplayPolicy: "subsumed",
|
|
168382
|
+
members
|
|
168383
|
+
}
|
|
168384
|
+
};
|
|
168385
|
+
for (const entry of memberEntries) {
|
|
168386
|
+
const mutable = entry;
|
|
168387
|
+
mutable.reviewGroup = {
|
|
168388
|
+
kind: "word-inserted-paragraph-range",
|
|
168389
|
+
role: "child",
|
|
168390
|
+
parentId: groupId,
|
|
168391
|
+
ownedChildIds: [],
|
|
168392
|
+
duplicateDisplayPolicy: "subsumed",
|
|
168393
|
+
members: []
|
|
168394
|
+
};
|
|
168395
|
+
mutable.revisionGroupId = groupId;
|
|
168396
|
+
}
|
|
168397
|
+
const storyArr = input.byStory.get(storyId);
|
|
168398
|
+
if (!storyArr)
|
|
168399
|
+
return;
|
|
168400
|
+
for (const dissolved of cluster) {
|
|
168401
|
+
input.byId.delete(dissolved.id);
|
|
168402
|
+
const index = storyArr.indexOf(dissolved);
|
|
168403
|
+
if (index >= 0)
|
|
168404
|
+
storyArr.splice(index, 1);
|
|
168405
|
+
}
|
|
168406
|
+
input.byId.set(groupId, parent);
|
|
168407
|
+
storyArr.push(parent);
|
|
168408
|
+
for (const fragment2 of textFragments)
|
|
168409
|
+
input.rsidToLogicalId.set(fragment2.rsid, groupId);
|
|
168410
|
+
for (const fragment2 of structuralFragments)
|
|
168411
|
+
input.structuralKeyToLogicalId.set(fragment2.entityKey, groupId);
|
|
168412
|
+
}
|
|
168413
|
+
function uniqueFragments(fragments) {
|
|
168414
|
+
const seen = new Set;
|
|
168415
|
+
const out = [];
|
|
168416
|
+
for (const fragment2 of fragments) {
|
|
168417
|
+
const key2 = `${fragment2.byteStart}:${fragment2.byteEnd}:${fragment2.rsid}`;
|
|
168418
|
+
if (seen.has(key2))
|
|
168419
|
+
continue;
|
|
168420
|
+
seen.add(key2);
|
|
168421
|
+
out.push(fragment2);
|
|
168422
|
+
}
|
|
168423
|
+
return out;
|
|
168424
|
+
}
|
|
168425
|
+
function uniqueStructuralFragments(fragments) {
|
|
168426
|
+
const seen = new Set;
|
|
168427
|
+
const out = [];
|
|
168428
|
+
for (const fragment2 of fragments) {
|
|
168429
|
+
const key2 = fragment2.entityKey;
|
|
168430
|
+
if (seen.has(key2))
|
|
168431
|
+
continue;
|
|
168432
|
+
seen.add(key2);
|
|
168433
|
+
out.push(fragment2);
|
|
168434
|
+
}
|
|
168435
|
+
return out;
|
|
168436
|
+
}
|
|
168193
168437
|
function classifyFullParagraphInsertion(lookupContext, partXml, paragraphStart, paragraphEnd, paragraphXml) {
|
|
168194
168438
|
const parent = findImmediateParentElementAtPosition(partXml, paragraphStart, lookupContext);
|
|
168195
168439
|
if (parent) {
|
|
@@ -168385,14 +168629,19 @@ function buildTrackedFieldLocationKey(lookupContext, partXml, fragment2) {
|
|
|
168385
168629
|
function extractDeletionText(deletion, partXml) {
|
|
168386
168630
|
return deletion.fragments.map((fragment2) => extractVisibleTextFromXml(partXml.slice(fragment2.byteStart, fragment2.byteEnd), "del")).join("");
|
|
168387
168631
|
}
|
|
168632
|
+
function isAbsorbableInlineObjectInsertion(entry, fragment2) {
|
|
168633
|
+
const kind = entry.subtype;
|
|
168634
|
+
return (kind === "footnote-insertion" || kind === "endnote-insertion" || kind === "image-insertion" || kind === "field-insertion") && fragment2.structuralKind === kind && entry.reviewGroup == null && entry.subsumption == null;
|
|
168635
|
+
}
|
|
168388
168636
|
function projectStoryReviewGroups(lookupContext, storyId, partUri, partXml, entries, input) {
|
|
168389
168637
|
const markCandidates = collectMarkCandidates(storyId, partXml, entries);
|
|
168390
168638
|
if (markCandidates.candidatesByParagraphStart.size === 0)
|
|
168391
168639
|
return;
|
|
168392
|
-
const textCandidates = collectTextCandidates(lookupContext, partXml, entries);
|
|
168640
|
+
const textCandidates = collectTextCandidates(lookupContext, partXml, entries, storyId);
|
|
168393
168641
|
if (textCandidates.length === 0)
|
|
168394
168642
|
return;
|
|
168395
|
-
const
|
|
168643
|
+
const objectCandidates = collectObjectCandidates(lookupContext, partXml, entries);
|
|
168644
|
+
const paragraphs = buildParagraphInfos(lookupContext, partXml, markCandidates, textCandidates, objectCandidates);
|
|
168396
168645
|
if (paragraphs.length === 0)
|
|
168397
168646
|
return;
|
|
168398
168647
|
const atoms = buildAtomSequence(partXml, paragraphs);
|
|
@@ -168403,17 +168652,33 @@ function projectStoryReviewGroups(lookupContext, storyId, partUri, partXml, entr
|
|
|
168403
168652
|
}
|
|
168404
168653
|
}
|
|
168405
168654
|
}
|
|
168406
|
-
function
|
|
168407
|
-
|
|
168408
|
-
|
|
168655
|
+
function paragraphRunHasImageInsertion(paragraphRun) {
|
|
168656
|
+
return paragraphRun.some((atom) => atom.kind === "object" && atom.candidate.entry.subtype === "image-insertion");
|
|
168657
|
+
}
|
|
168658
|
+
function paragraphRunFullParagraphRsid(paragraphRun) {
|
|
168659
|
+
for (const atom of paragraphRun) {
|
|
168409
168660
|
if (atom.kind !== "mark" || atom.candidate.fragment.fullParagraphInsertion !== true)
|
|
168410
|
-
|
|
168661
|
+
continue;
|
|
168411
168662
|
const rsid = atom.candidate.fragment.enclosingParagraphRsid;
|
|
168412
|
-
return rsid ?
|
|
168413
|
-
}));
|
|
168414
|
-
if (fullParagraphRsidsByStart.size <= 1 || new Set(fullParagraphRsidsByStart.values()).size <= 1) {
|
|
168415
|
-
return [run];
|
|
168663
|
+
return rsid ? rsid.toUpperCase() : null;
|
|
168416
168664
|
}
|
|
168665
|
+
return null;
|
|
168666
|
+
}
|
|
168667
|
+
function paragraphRunIsFullParagraphInsertion(paragraphRun) {
|
|
168668
|
+
return paragraphRun.some((atom) => atom.kind === "mark" && atom.candidate.fragment.fullParagraphInsertion === true);
|
|
168669
|
+
}
|
|
168670
|
+
function canContinueFullParagraphRun(currentRun, nextParagraphRun, currentRsid, nextRsid, anyStampedFullParagraph) {
|
|
168671
|
+
if (paragraphRunHasImageInsertion(currentRun) !== paragraphRunHasImageInsertion(nextParagraphRun)) {
|
|
168672
|
+
return false;
|
|
168673
|
+
}
|
|
168674
|
+
if (!anyStampedFullParagraph)
|
|
168675
|
+
return true;
|
|
168676
|
+
if (currentRsid == null || nextRsid == null)
|
|
168677
|
+
return false;
|
|
168678
|
+
return currentRsid === nextRsid;
|
|
168679
|
+
}
|
|
168680
|
+
function splitDistinctFullParagraphRuns(run) {
|
|
168681
|
+
const members = run.filter((atom) => atom.kind !== "blocker");
|
|
168417
168682
|
const paragraphRuns = [];
|
|
168418
168683
|
for (const member of members) {
|
|
168419
168684
|
const current = paragraphRuns.at(-1);
|
|
@@ -168423,6 +168688,11 @@ function splitDistinctFullParagraphRuns(run) {
|
|
|
168423
168688
|
paragraphRuns.push([member]);
|
|
168424
168689
|
}
|
|
168425
168690
|
}
|
|
168691
|
+
const fullParagraphRuns = paragraphRuns.filter(paragraphRunIsFullParagraphInsertion);
|
|
168692
|
+
if (fullParagraphRuns.length <= 1) {
|
|
168693
|
+
return [run];
|
|
168694
|
+
}
|
|
168695
|
+
const anyStampedFullParagraph = fullParagraphRuns.some((paragraphRun) => paragraphRunFullParagraphRsid(paragraphRun) != null);
|
|
168426
168696
|
const projectedRuns = [];
|
|
168427
168697
|
let currentRun = [];
|
|
168428
168698
|
let currentRsid = null;
|
|
@@ -168434,9 +168704,7 @@ function splitDistinctFullParagraphRuns(run) {
|
|
|
168434
168704
|
currentRsid = null;
|
|
168435
168705
|
};
|
|
168436
168706
|
for (const paragraphRun of paragraphRuns) {
|
|
168437
|
-
|
|
168438
|
-
const paragraphRsid = fullParagraphRsidsByStart.get(paragraphStart) ?? null;
|
|
168439
|
-
if (paragraphRsid === null) {
|
|
168707
|
+
if (!paragraphRunIsFullParagraphInsertion(paragraphRun)) {
|
|
168440
168708
|
if (currentRsid !== null && paragraphRun.every((atom) => atom.kind === "text")) {
|
|
168441
168709
|
currentRun.push(...paragraphRun);
|
|
168442
168710
|
continue;
|
|
@@ -168445,14 +168713,19 @@ function splitDistinctFullParagraphRuns(run) {
|
|
|
168445
168713
|
currentRun = [...paragraphRun];
|
|
168446
168714
|
continue;
|
|
168447
168715
|
}
|
|
168448
|
-
|
|
168716
|
+
const paragraphRsid = paragraphRunFullParagraphRsid(paragraphRun);
|
|
168717
|
+
if (currentRun.length > 0 && canContinueFullParagraphRun(currentRun, paragraphRun, currentRsid, paragraphRsid, anyStampedFullParagraph)) {
|
|
168449
168718
|
currentRun.push(...paragraphRun);
|
|
168719
|
+
if (currentRsid == null)
|
|
168720
|
+
currentRsid = paragraphRsid;
|
|
168450
168721
|
continue;
|
|
168451
168722
|
}
|
|
168452
|
-
if (currentRsid === null && currentRun.every((atom) => atom.kind === "mark")) {
|
|
168453
|
-
|
|
168454
|
-
|
|
168455
|
-
|
|
168723
|
+
if (currentRsid === null && currentRun.length > 0 && currentRun.every((atom) => atom.kind === "mark")) {
|
|
168724
|
+
if (canContinueFullParagraphRun(currentRun, paragraphRun, paragraphRsid, paragraphRsid, anyStampedFullParagraph)) {
|
|
168725
|
+
currentRsid = paragraphRsid;
|
|
168726
|
+
currentRun = [...currentRun, ...paragraphRun];
|
|
168727
|
+
continue;
|
|
168728
|
+
}
|
|
168456
168729
|
}
|
|
168457
168730
|
flushCurrentRun();
|
|
168458
168731
|
currentRsid = paragraphRsid;
|
|
@@ -168473,10 +168746,10 @@ function collectMarkCandidates(storyId, partXml, entries) {
|
|
|
168473
168746
|
continue;
|
|
168474
168747
|
if (fragment2.enclosingElementStart === undefined || fragment2.enclosingElementEnd === undefined)
|
|
168475
168748
|
continue;
|
|
168476
|
-
const isCandidateShape = entry.subtype === "paragraph-mark-insertion" && fragment2.structuralKind === "paragraph-mark-insertion" && entry.structuralFragments.length === 1 && entry.noteId == null && entry.subsumption == null && entry.reviewGroup == null;
|
|
168749
|
+
const isCandidateShape = entry.subtype === "paragraph-mark-insertion" && fragment2.structuralKind === "paragraph-mark-insertion" && entry.structuralFragments.length === 1 && (entry.noteId == null || isNotesStoryId(storyId)) && entry.subsumption == null && entry.reviewGroup == null;
|
|
168477
168750
|
if (isCandidateShape) {
|
|
168478
168751
|
markFragments.push({ entry, fragment: fragment2 });
|
|
168479
|
-
} else if (isTerminalDeletionOfPendingFullParagraphInsertion(fragment2, entries)) {} else {
|
|
168752
|
+
} else if (isTerminalDeletionOfPendingFullParagraphInsertion(fragment2, entries)) {} else if (isAbsorbableInlineObjectInsertion(entry, fragment2)) {} else {
|
|
168480
168753
|
blockedParagraphStarts.add(fragment2.enclosingElementStart);
|
|
168481
168754
|
}
|
|
168482
168755
|
}
|
|
@@ -168517,12 +168790,12 @@ function isTerminalDeletionOfPendingFullParagraphInsertion(fragment2, entries) {
|
|
|
168517
168790
|
const markers = entries.flatMap((entry) => entry.structuralFragments).filter((candidate2) => candidate2.enclosingElementStart === paragraphStart && candidate2.enclosingElementEnd === paragraphEnd && (candidate2.structuralKind === "paragraph-mark-insertion" || candidate2.structuralKind === "paragraph-mark-deletion")).sort((left, right) => left.byteStart - right.byteStart);
|
|
168518
168791
|
return markers.length === 2 && markers[0]?.structuralKind === "paragraph-mark-insertion" && markers[0].fullParagraphInsertion === true && markers[1] === fragment2;
|
|
168519
168792
|
}
|
|
168520
|
-
function collectTextCandidates(lookupContext, partXml, entries) {
|
|
168793
|
+
function collectTextCandidates(lookupContext, partXml, entries, storyId) {
|
|
168521
168794
|
const out = [];
|
|
168522
168795
|
for (const entry of entries) {
|
|
168523
168796
|
if (entry.type !== "insertion" || entry.subtype !== "text-insertion")
|
|
168524
168797
|
continue;
|
|
168525
|
-
if (entry.noteId != null)
|
|
168798
|
+
if (entry.noteId != null && !isNotesStoryId(storyId))
|
|
168526
168799
|
continue;
|
|
168527
168800
|
if (entry.sides || entry.movePair)
|
|
168528
168801
|
continue;
|
|
@@ -168567,14 +168840,60 @@ function collectTextCandidates(lookupContext, partXml, entries) {
|
|
|
168567
168840
|
}
|
|
168568
168841
|
return out;
|
|
168569
168842
|
}
|
|
168843
|
+
function collectObjectCandidates(lookupContext, partXml, entries) {
|
|
168844
|
+
const out = [];
|
|
168845
|
+
for (const entry of entries) {
|
|
168846
|
+
if (entry.type !== "structural")
|
|
168847
|
+
continue;
|
|
168848
|
+
if (entry.sides || entry.movePair)
|
|
168849
|
+
continue;
|
|
168850
|
+
if (entry.subsumption || entry.reviewGroup)
|
|
168851
|
+
continue;
|
|
168852
|
+
if (entry.structuralFragments.length === 0)
|
|
168853
|
+
continue;
|
|
168854
|
+
if (!entry.structuralFragments.every((fragment2) => isAbsorbableInlineObjectInsertion(entry, fragment2))) {
|
|
168855
|
+
continue;
|
|
168856
|
+
}
|
|
168857
|
+
let paragraphStart = null;
|
|
168858
|
+
let eligible = true;
|
|
168859
|
+
for (const fragment2 of entry.structuralFragments) {
|
|
168860
|
+
const paragraph = findEnclosingElementAtPosition(partXml, fragment2.byteStart, "p", undefined, lookupContext);
|
|
168861
|
+
if (!paragraph) {
|
|
168862
|
+
eligible = false;
|
|
168863
|
+
break;
|
|
168864
|
+
}
|
|
168865
|
+
if (paragraphStart == null)
|
|
168866
|
+
paragraphStart = paragraph.start;
|
|
168867
|
+
if (paragraph.start !== paragraphStart) {
|
|
168868
|
+
eligible = false;
|
|
168869
|
+
break;
|
|
168870
|
+
}
|
|
168871
|
+
}
|
|
168872
|
+
if (!eligible || paragraphStart == null)
|
|
168873
|
+
continue;
|
|
168874
|
+
const headFragment = entry.structuralFragments[0];
|
|
168875
|
+
out.push({
|
|
168876
|
+
entry,
|
|
168877
|
+
fragments: [...entry.structuralFragments].sort((a, b) => a.byteStart - b.byteStart),
|
|
168878
|
+
paragraphStart,
|
|
168879
|
+
identity: buildReviewIdentity({
|
|
168880
|
+
name: entry.author.name,
|
|
168881
|
+
email: entry.authorEmail ?? headFragment.authorEmail,
|
|
168882
|
+
initials: entry.author.initials
|
|
168883
|
+
}),
|
|
168884
|
+
initials: entry.author.initials
|
|
168885
|
+
});
|
|
168886
|
+
}
|
|
168887
|
+
return out;
|
|
168888
|
+
}
|
|
168570
168889
|
function isSimpleInlineInsertionWrapper(wrapperXml) {
|
|
168571
168890
|
const innerMatch = /^<[\w.-]+:ins\b[^>]*>([\s\S]*)<\/[\w.-]+:ins>\s*$/.exec(wrapperXml);
|
|
168572
168891
|
if (!innerMatch)
|
|
168573
168892
|
return false;
|
|
168574
168893
|
const inner = innerMatch[1] ?? "";
|
|
168575
|
-
return !/<[\w.-]+:(?:ins|del|moveFrom|moveTo
|
|
168894
|
+
return !/<[\w.-]+:(?:ins|del|moveFrom|moveTo)\b/.test(inner);
|
|
168576
168895
|
}
|
|
168577
|
-
function buildParagraphInfos(lookupContext, partXml, marks, textCandidates) {
|
|
168896
|
+
function buildParagraphInfos(lookupContext, partXml, marks, textCandidates, objectCandidates = []) {
|
|
168578
168897
|
const byStart = new Map;
|
|
168579
168898
|
const ensure = (start, end) => {
|
|
168580
168899
|
let info = byStart.get(start);
|
|
@@ -168585,6 +168904,7 @@ function buildParagraphInfos(lookupContext, partXml, marks, textCandidates) {
|
|
|
168585
168904
|
mark: null,
|
|
168586
168905
|
markBlocked: marks.blockedParagraphStarts.has(start),
|
|
168587
168906
|
textFragments: [],
|
|
168907
|
+
objectFragments: [],
|
|
168588
168908
|
invalid: false
|
|
168589
168909
|
};
|
|
168590
168910
|
byStart.set(start, info);
|
|
@@ -168604,17 +168924,28 @@ function buildParagraphInfos(lookupContext, partXml, marks, textCandidates) {
|
|
|
168604
168924
|
info.textFragments.push({ candidate: candidate2, fragment: fragment2 });
|
|
168605
168925
|
}
|
|
168606
168926
|
}
|
|
168927
|
+
for (const candidate2 of objectCandidates) {
|
|
168928
|
+
const paragraph = findEnclosingElementAtPosition(partXml, candidate2.fragments[0].byteStart, "p", undefined, lookupContext);
|
|
168929
|
+
if (!paragraph)
|
|
168930
|
+
continue;
|
|
168931
|
+
const info = ensure(paragraph.start, paragraph.end);
|
|
168932
|
+
for (const fragment2 of candidate2.fragments) {
|
|
168933
|
+
info.objectFragments.push({ candidate: candidate2, fragment: fragment2 });
|
|
168934
|
+
}
|
|
168935
|
+
}
|
|
168607
168936
|
const paragraphs = Array.from(byStart.values()).sort((a, b) => a.start - b.start);
|
|
168608
168937
|
for (const paragraph of paragraphs) {
|
|
168609
168938
|
paragraph.textFragments.sort((a, b) => a.fragment.byteStart - b.fragment.byteStart);
|
|
168939
|
+
paragraph.objectFragments.sort((a, b) => a.fragment.byteStart - b.fragment.byteStart);
|
|
168610
168940
|
paragraph.invalid = !isEligibleGroupParagraph(lookupContext, partXml, paragraph);
|
|
168611
168941
|
}
|
|
168612
168942
|
return paragraphs;
|
|
168613
168943
|
}
|
|
168614
168944
|
function isEligibleGroupParagraph(lookupContext, partXml, paragraph) {
|
|
168615
168945
|
const parent = findImmediateParentElementAtPosition(partXml, paragraph.start, lookupContext);
|
|
168616
|
-
if (!parent || parent.localName !== "body")
|
|
168946
|
+
if (!parent || parent.localName !== "body" && parent.localName !== "footnote" && parent.localName !== "endnote") {
|
|
168617
168947
|
return false;
|
|
168948
|
+
}
|
|
168618
168949
|
const paragraphXml = partXml.slice(paragraph.start, paragraph.end);
|
|
168619
168950
|
const pPrXml = readLeadingParagraphPropertyBlock(paragraphXml)?.xml ?? "";
|
|
168620
168951
|
if (pPrXml && /<[\w.-]+:sectPr\b/.test(pPrXml))
|
|
@@ -168659,7 +168990,7 @@ function buildAtomSequence(partXml, paragraphs) {
|
|
|
168659
168990
|
for (const paragraph of paragraphs) {
|
|
168660
168991
|
if (previous) {
|
|
168661
168992
|
const between = partXml.slice(previous.end, paragraph.start);
|
|
168662
|
-
if (!
|
|
168993
|
+
if (!isCleanGroupingGap(between, previous, paragraph))
|
|
168663
168994
|
atoms.push({ kind: "blocker" });
|
|
168664
168995
|
}
|
|
168665
168996
|
previous = paragraph;
|
|
@@ -168729,17 +169060,21 @@ function appendParagraphAtoms(partXml, paragraph, atoms, hyperlinkTags) {
|
|
|
168729
169060
|
return isCleanGapXml(gap + partXml.slice(cursor2, end));
|
|
168730
169061
|
};
|
|
168731
169062
|
let cursor = contentStart;
|
|
168732
|
-
|
|
168733
|
-
|
|
169063
|
+
const contentAtoms = [
|
|
169064
|
+
...paragraph.textFragments.map(({ candidate: candidate2, fragment: fragment2 }) => ({ kind: "text", candidate: candidate2, fragment: fragment2 })),
|
|
169065
|
+
...paragraph.objectFragments.map(({ candidate: candidate2, fragment: fragment2 }) => ({ kind: "object", candidate: candidate2, fragment: fragment2 }))
|
|
169066
|
+
].sort((left, right) => left.fragment.byteStart - right.fragment.byteStart);
|
|
169067
|
+
for (const atom of contentAtoms) {
|
|
169068
|
+
if (atom.fragment.byteStart < cursor || atom.fragment.byteEnd > contentEnd) {
|
|
168734
169069
|
atoms.push({ kind: "blocker" });
|
|
168735
|
-
cursor = Math.max(cursor,
|
|
169070
|
+
cursor = Math.max(cursor, atom.fragment.byteEnd);
|
|
168736
169071
|
continue;
|
|
168737
169072
|
}
|
|
168738
|
-
if (!cleanGap(cursor,
|
|
169073
|
+
if (!cleanGap(cursor, atom.fragment.byteStart)) {
|
|
168739
169074
|
atoms.push({ kind: "blocker" });
|
|
168740
169075
|
}
|
|
168741
|
-
atoms.push(
|
|
168742
|
-
cursor =
|
|
169076
|
+
atoms.push(atom);
|
|
169077
|
+
cursor = atom.fragment.byteEnd;
|
|
168743
169078
|
}
|
|
168744
169079
|
if (!cleanGap(cursor, contentEnd)) {
|
|
168745
169080
|
atoms.push({ kind: "blocker" });
|
|
@@ -168757,6 +169092,16 @@ function isCleanGapXml(xml) {
|
|
|
168757
169092
|
return false;
|
|
168758
169093
|
return containsOnlyAllowedPairingMarkers(xml);
|
|
168759
169094
|
}
|
|
169095
|
+
function isCleanGroupingGap(between, previous, next) {
|
|
169096
|
+
const stripped = between.replace(/<\/?[\w.-]+:(?:footnote|endnote)\b[^>]*>/g, "");
|
|
169097
|
+
if (!isCleanGapXml(stripped))
|
|
169098
|
+
return false;
|
|
169099
|
+
if (stripped === between)
|
|
169100
|
+
return true;
|
|
169101
|
+
const left = previous.mark?.fragment.enclosingParagraphRsid;
|
|
169102
|
+
const right = next.mark?.fragment.enclosingParagraphRsid;
|
|
169103
|
+
return Boolean(left && right && left.toUpperCase() === right.toUpperCase());
|
|
169104
|
+
}
|
|
168760
169105
|
function collectSameIdentityRuns(atoms) {
|
|
168761
169106
|
const runs = [];
|
|
168762
169107
|
let current = [];
|
|
@@ -168791,17 +169136,17 @@ function isSameGroupIdentity(a, b) {
|
|
|
168791
169136
|
function materializeReviewGroup(lookupContext, storyId, partUri, partXml, run, input) {
|
|
168792
169137
|
const textAtoms = run.filter((atom) => atom.kind === "text");
|
|
168793
169138
|
const markAtoms = run.filter((atom) => atom.kind === "mark");
|
|
169139
|
+
const objectAtoms = run.filter((atom) => atom.kind === "object");
|
|
168794
169140
|
if (textAtoms.length === 0 || markAtoms.length === 0)
|
|
168795
169141
|
return;
|
|
168796
169142
|
const carrierParagraphStarts = new Set([
|
|
168797
169143
|
...textAtoms.map((atom) => atom.candidate.paragraphStart),
|
|
169144
|
+
...objectAtoms.map((atom) => atom.candidate.paragraphStart),
|
|
168798
169145
|
...markAtoms.map((atom) => atom.candidate.paragraphStart)
|
|
168799
169146
|
]);
|
|
168800
|
-
const fullParagraphStarts = new Set(markAtoms.filter((atom) => atom.candidate.fragment.fullParagraphInsertion === true
|
|
168801
|
-
let
|
|
168802
|
-
if ([...carrierParagraphStarts].every((paragraphStart) => fullParagraphStarts.has(paragraphStart))) {
|
|
168803
|
-
if (markAtoms.length !== 1)
|
|
168804
|
-
return;
|
|
169147
|
+
const fullParagraphStarts = new Set(markAtoms.filter((atom) => atom.candidate.fragment.fullParagraphInsertion === true).map((atom) => atom.candidate.paragraphStart));
|
|
169148
|
+
let fullParagraphOwner;
|
|
169149
|
+
if (markAtoms.length === 1 && [...carrierParagraphStarts].every((paragraphStart) => fullParagraphStarts.has(paragraphStart))) {
|
|
168805
169150
|
const marker = markAtoms[0].candidate.fragment;
|
|
168806
169151
|
const paragraphStart = marker.enclosingElementStart;
|
|
168807
169152
|
const paragraphEnd = marker.enclosingElementEnd;
|
|
@@ -168811,12 +169156,12 @@ function materializeReviewGroup(lookupContext, storyId, partUri, partXml, run, i
|
|
|
168811
169156
|
const subtype = classifyFullParagraphInsertion(lookupContext, partXml, paragraphStart, paragraphEnd, paragraphXml).subtype;
|
|
168812
169157
|
if (subtype === "table-split")
|
|
168813
169158
|
return;
|
|
168814
|
-
if (subtype === "list-item-insertion") {
|
|
169159
|
+
if (subtype === "list-item-insertion" || objectAtoms.length > 0) {
|
|
168815
169160
|
const candidate2 = markAtoms[0].candidate;
|
|
168816
|
-
const ownsStructuralContent = input.byStory.get(storyId)?.some((entry) => entry.type === "structural" && entry !== candidate2.entry && entry.structuralFragments.some((fragment2) => fragment2.byteStart >= paragraphStart && fragment2.byteEnd <= paragraphEnd));
|
|
169161
|
+
const ownsStructuralContent = input.byStory.get(storyId)?.some((entry) => entry.type === "structural" && entry !== candidate2.entry && !objectAtoms.some((atom) => atom.candidate.entry === entry) && entry.structuralFragments.some((fragment2) => fragment2.byteStart >= paragraphStart && fragment2.byteEnd <= paragraphEnd));
|
|
168817
169162
|
if (ownsStructuralContent)
|
|
168818
169163
|
return;
|
|
168819
|
-
|
|
169164
|
+
fullParagraphOwner = candidate2;
|
|
168820
169165
|
}
|
|
168821
169166
|
}
|
|
168822
169167
|
const memberEntries = [];
|
|
@@ -168839,15 +169184,15 @@ function materializeReviewGroup(lookupContext, storyId, partUri, partXml, run, i
|
|
|
168839
169184
|
const markKey = markParagraphIds.every((paraId) => paraId != null) ? markParagraphIds.map((paraId) => `p:${paraId}`).join(",") : markOrdinals.join(",");
|
|
168840
169185
|
const groupHash = hashGroupKey(["word-inserted-paragraph-range", storyId, identityKey, `pm:${markKey}`, `tx:${textAtoms.length}`].join("|"));
|
|
168841
169186
|
const groupId = buildLogicalId(storyId, "ins", "word-paragraph-range", groupHash);
|
|
168842
|
-
if (
|
|
169187
|
+
if (fullParagraphOwner) {
|
|
168843
169188
|
materializeFullParagraphInsertion(lookupContext, {
|
|
168844
169189
|
storyId,
|
|
168845
169190
|
partUri,
|
|
168846
169191
|
partXml,
|
|
168847
|
-
structuralEntry:
|
|
168848
|
-
marker:
|
|
169192
|
+
structuralEntry: fullParagraphOwner.entry,
|
|
169193
|
+
marker: fullParagraphOwner.fragment,
|
|
168849
169194
|
textEntries: uniqueEntries(textAtoms.map((atom) => atom.candidate.entry)),
|
|
168850
|
-
objectEntries:
|
|
169195
|
+
objectEntries: uniqueEntries(objectAtoms.map((atom) => atom.candidate.entry)),
|
|
168851
169196
|
logicalId: groupId,
|
|
168852
169197
|
input
|
|
168853
169198
|
});
|
|
@@ -168855,8 +169200,11 @@ function materializeReviewGroup(lookupContext, storyId, partUri, partXml, run, i
|
|
|
168855
169200
|
}
|
|
168856
169201
|
const canonicalText = buildCanonicalGroupText(partXml, run);
|
|
168857
169202
|
const fragments = textAtoms.map((atom) => atom.fragment);
|
|
168858
|
-
const structuralFragments =
|
|
168859
|
-
|
|
169203
|
+
const structuralFragments = [
|
|
169204
|
+
...objectAtoms.map((atom) => atom.fragment),
|
|
169205
|
+
...markAtoms.map((atom) => atom.candidate.fragment)
|
|
169206
|
+
].sort((left, right) => left.byteStart - right.byteStart);
|
|
169207
|
+
const semanticPositions = run.filter((atom) => atom.kind !== "blocker").map((atom) => atom.kind === "mark" ? { start: atom.candidate.paragraphEnd, end: atom.candidate.paragraphEnd } : { start: atom.fragment.byteStart, end: atom.fragment.byteEnd });
|
|
168860
169208
|
const documentOrderStart = Math.min(...semanticPositions.map((position) => position.start));
|
|
168861
169209
|
const documentOrderEnd = Math.max(...semanticPositions.map((position) => position.end));
|
|
168862
169210
|
const textEntries = uniqueEntries(textAtoms.map((atom) => atom.candidate.entry));
|
|
@@ -168872,26 +169220,45 @@ function materializeReviewGroup(lookupContext, storyId, partUri, partXml, run, i
|
|
|
168872
169220
|
...structuralFragments.map((fragment2) => fragment2.date)
|
|
168873
169221
|
]);
|
|
168874
169222
|
const headEntry = memberEntries[0];
|
|
168875
|
-
const
|
|
168876
|
-
|
|
168877
|
-
|
|
168878
|
-
|
|
168879
|
-
|
|
168880
|
-
|
|
168881
|
-
|
|
168882
|
-
|
|
168883
|
-
|
|
168884
|
-
|
|
168885
|
-
|
|
168886
|
-
|
|
168887
|
-
|
|
168888
|
-
|
|
168889
|
-
|
|
168890
|
-
|
|
168891
|
-
|
|
168892
|
-
|
|
168893
|
-
|
|
168894
|
-
|
|
169223
|
+
const ownedNotes = uniqueNonEmptyStrings(memberEntries.flatMap((entry) => ownedNoteIds(entry)));
|
|
169224
|
+
const members = run.filter((atom) => atom.kind !== "blocker").map((atom) => {
|
|
169225
|
+
if (atom.kind === "text") {
|
|
169226
|
+
return {
|
|
169227
|
+
logicalId: atom.candidate.entry.id,
|
|
169228
|
+
carrier: "text",
|
|
169229
|
+
partUri,
|
|
169230
|
+
storyId,
|
|
169231
|
+
rsid: atom.fragment.rsid,
|
|
169232
|
+
...atom.fragment.wId ? { wordId: atom.fragment.wId } : {},
|
|
169233
|
+
subtype: "text-insertion",
|
|
169234
|
+
byteStart: atom.fragment.byteStart,
|
|
169235
|
+
byteEnd: atom.fragment.byteEnd
|
|
169236
|
+
};
|
|
169237
|
+
}
|
|
169238
|
+
if (atom.kind === "object") {
|
|
169239
|
+
return {
|
|
169240
|
+
logicalId: atom.candidate.entry.id,
|
|
169241
|
+
carrier: "structural",
|
|
169242
|
+
partUri,
|
|
169243
|
+
storyId,
|
|
169244
|
+
entityKey: atom.fragment.entityKey,
|
|
169245
|
+
...atom.fragment.wId ? { wordId: atom.fragment.wId } : {},
|
|
169246
|
+
subtype: atom.fragment.structuralKind,
|
|
169247
|
+
byteStart: atom.fragment.byteStart,
|
|
169248
|
+
byteEnd: atom.fragment.byteEnd
|
|
169249
|
+
};
|
|
169250
|
+
}
|
|
169251
|
+
return {
|
|
169252
|
+
logicalId: atom.candidate.entry.id,
|
|
169253
|
+
carrier: "structural",
|
|
169254
|
+
partUri,
|
|
169255
|
+
storyId,
|
|
169256
|
+
entityKey: atom.candidate.fragment.entityKey,
|
|
169257
|
+
...atom.candidate.fragment.wId ? { wordId: atom.candidate.fragment.wId } : {},
|
|
169258
|
+
subtype: "paragraph-mark-insertion",
|
|
169259
|
+
byteStart: atom.candidate.fragment.byteStart,
|
|
169260
|
+
byteEnd: atom.candidate.fragment.byteEnd
|
|
169261
|
+
};
|
|
168895
169262
|
});
|
|
168896
169263
|
const parent = {
|
|
168897
169264
|
id: groupId,
|
|
@@ -168900,7 +169267,8 @@ function materializeReviewGroup(lookupContext, storyId, partUri, partXml, run, i
|
|
|
168900
169267
|
state: "open",
|
|
168901
169268
|
storyId,
|
|
168902
169269
|
partUri,
|
|
168903
|
-
noteId: null,
|
|
169270
|
+
noteId: ownedNotes[0] ?? memberEntries.find((entry) => entry.noteId != null)?.noteId ?? null,
|
|
169271
|
+
noteIds: ownedNotes.length > 0 ? ownedNotes : null,
|
|
168904
169272
|
documentOrderStart,
|
|
168905
169273
|
documentOrderEnd,
|
|
168906
169274
|
author: { name: headEntry.author.name, initials: headEntry.author.initials },
|
|
@@ -169014,9 +169382,17 @@ function uniqueNonEmptyStrings(values) {
|
|
|
169014
169382
|
}
|
|
169015
169383
|
return out;
|
|
169016
169384
|
}
|
|
169385
|
+
function ownedNoteIds(entry) {
|
|
169386
|
+
if (entry.noteIds && entry.noteIds.length > 0)
|
|
169387
|
+
return [...entry.noteIds];
|
|
169388
|
+
return entry.noteId != null ? [entry.noteId] : [];
|
|
169389
|
+
}
|
|
169017
169390
|
function isBodyStoryId(storyId) {
|
|
169018
169391
|
return storyId.startsWith("main:") || storyId.endsWith(":/word/document.xml");
|
|
169019
169392
|
}
|
|
169393
|
+
function isNotesStoryId(storyId) {
|
|
169394
|
+
return storyId.startsWith("footnotes:") || storyId.startsWith("endnotes:");
|
|
169395
|
+
}
|
|
169020
169396
|
function buildBodyParagraphOrdinalIndexWithLookupContext(lookupContext, partXml) {
|
|
169021
169397
|
const bodyOpen = /<([\w.-]+):body\b[^>]*>/.exec(partXml);
|
|
169022
169398
|
if (!bodyOpen) {
|
|
@@ -169997,13 +170373,14 @@ function materializeDeletionGroup(storyId, partUri, partXml, run, carrierOrdinal
|
|
|
169997
170373
|
].filter((ordinal) => ordinal !== undefined).sort((a, b) => a - b);
|
|
169998
170374
|
const memberParagraphTokens = run.filter((atom) => atom.kind !== "blocker").map((atom) => {
|
|
169999
170375
|
const paraId = readParagraphIdAt(partXml, atom.candidate.paragraphStart);
|
|
170000
|
-
|
|
170376
|
+
const kindToken = atom.kind === "mark" ? "m" : atom.kind === "object" ? "o" : "t";
|
|
170377
|
+
return paraId != null ? `${kindToken}@p:${paraId}` : null;
|
|
170001
170378
|
});
|
|
170002
170379
|
const memberKey = memberParagraphTokens.every((token) => token != null) ? memberParagraphTokens.join(",") : carrierOrdinals.join(",");
|
|
170003
170380
|
const groupHash = hashGroupKey(["word-deleted-paragraph-range", storyId, partUri, `co:${memberKey}`].join("|"));
|
|
170004
170381
|
const groupId = buildLogicalId(storyId, "del", "word-deleted-paragraph-range", groupHash);
|
|
170005
170382
|
const canonicalText = buildCanonicalDeletionGroupText(partXml, run);
|
|
170006
|
-
const semanticPositions = run.filter((atom) => atom.kind !== "blocker").map((atom) => atom.kind === "
|
|
170383
|
+
const semanticPositions = run.filter((atom) => atom.kind !== "blocker").map((atom) => atom.kind === "mark" ? { start: atom.candidate.paragraphEnd, end: atom.candidate.paragraphEnd } : { start: atom.fragment.byteStart, end: atom.fragment.byteEnd });
|
|
170007
170384
|
const documentOrderStart = Math.min(...semanticPositions.map((position) => position.start));
|
|
170008
170385
|
const documentOrderEnd = Math.max(...semanticPositions.map((position) => position.end));
|
|
170009
170386
|
const textEntries = uniqueEntries(textAtoms.map((atom) => atom.candidate.entry));
|
|
@@ -170021,7 +170398,7 @@ function materializeDeletionGroup(storyId, partUri, partXml, run, carrierOrdinal
|
|
|
170021
170398
|
const headEntry = memberEntries[0];
|
|
170022
170399
|
const hasDeletedText = textAtoms.length > 0;
|
|
170023
170400
|
const structuralDelta = hasDeletedText ? null : buildDeletedParagraphMarkRangeStructuralDelta(partXml, structuralFragments);
|
|
170024
|
-
const members = run.filter((atom) => atom.kind
|
|
170401
|
+
const members = run.filter((atom) => atom.kind === "text" || atom.kind === "mark").map((atom) => atom.kind === "text" ? {
|
|
170025
170402
|
logicalId: atom.candidate.entry.id,
|
|
170026
170403
|
carrier: "text",
|
|
170027
170404
|
partUri,
|
|
@@ -174115,6 +174492,7 @@ function buildStructuralLogical(lookupContext, entityKey, group, noteId, partXml
|
|
|
174115
174492
|
documentOrderStart,
|
|
174116
174493
|
documentOrderEnd,
|
|
174117
174494
|
author: { name: head.author.name, initials: head.author.initials },
|
|
174495
|
+
authorEmail: head.authorEmail ?? null,
|
|
174118
174496
|
date: head.date,
|
|
174119
174497
|
sourceIds,
|
|
174120
174498
|
revisionGroupId: id,
|
|
@@ -180832,7 +181210,7 @@ function reserveRevisionWIdBlock(state, count) {
|
|
|
180832
181210
|
}
|
|
180833
181211
|
return base2;
|
|
180834
181212
|
}
|
|
180835
|
-
function planRevisionWIdBlock(state, count) {
|
|
181213
|
+
function planRevisionWIdBlock(state, count, options) {
|
|
180836
181214
|
let max2 = state.idReservations.revisionWIds.max;
|
|
180837
181215
|
if (!state.idReservations.revisionWIds.seeded) {
|
|
180838
181216
|
for (const [, bytes] of state.packageBytes.entries()) {
|
|
@@ -180841,6 +181219,9 @@ function planRevisionWIdBlock(state, count) {
|
|
|
180841
181219
|
max2 = value;
|
|
180842
181220
|
}
|
|
180843
181221
|
}
|
|
181222
|
+
if (options?.afterMax != null && options.afterMax > max2) {
|
|
181223
|
+
max2 = options.afterMax;
|
|
181224
|
+
}
|
|
180844
181225
|
const size = Math.max(1, Math.floor(count));
|
|
180845
181226
|
return Array.from({ length: size }, (_, index) => max2 + index + 1);
|
|
180846
181227
|
}
|
|
@@ -195828,7 +196209,7 @@ function rewriteLocalizedDirect(bytes, window2, op, inheritedNamespaceBindings =
|
|
|
195828
196209
|
return rewritten;
|
|
195829
196210
|
return { ok: true, bytes: TE16.encode(rewritten.xml), runPropertiesXml: "" };
|
|
195830
196211
|
}
|
|
195831
|
-
const plan = planDirectInlineEdit(paragraphBytes, op.on.startOffset, op.on.endOffset, op.newText, op.on.collapsedObjectBoundary, op.on.collapsedInlineAffinity, inheritedNamespaceBindings);
|
|
196212
|
+
const plan = planDirectInlineEdit(paragraphBytes, op.on.startOffset, op.on.endOffset, op.newText, op.on.collapsedObjectBoundary, op.on.collapsedInlineAffinity, inheritedNamespaceBindings, op.on.collapsedOutsideContentControl);
|
|
195832
196213
|
if (plan.ok) {
|
|
195833
196214
|
return {
|
|
195834
196215
|
ok: true,
|
|
@@ -216733,7 +217114,8 @@ function compilePastedNotesMetadata(input) {
|
|
|
216733
217114
|
paragraph,
|
|
216734
217115
|
type,
|
|
216735
217116
|
includeMarker: index === 0,
|
|
216736
|
-
paraSalt: paraSalt += 1
|
|
217117
|
+
paraSalt: paraSalt += 1,
|
|
217118
|
+
trackedStamp: input.trackedStamp ?? null
|
|
216737
217119
|
})).join("");
|
|
216738
217120
|
fragments.push(`<w:${type} w:id="${escapeXmlAttribute(destinationId)}">${bodyXml}</w:${type}>`);
|
|
216739
217121
|
}
|
|
@@ -216837,7 +217219,18 @@ function renderNoteParagraphXml(input) {
|
|
|
216837
217219
|
const markerStyle = input.type === "footnote" ? "FootnoteReference" : "EndnoteReference";
|
|
216838
217220
|
const markerLocal = input.type === "footnote" ? "footnoteRef" : "endnoteRef";
|
|
216839
217221
|
const marker = input.includeMarker ? `<w:r><w:rPr><w:rStyle w:val="${markerStyle}"/></w:rPr><w:${markerLocal}/></w:r>` : "";
|
|
216840
|
-
|
|
217222
|
+
const runs = noteBodyRuns(input.paragraph);
|
|
217223
|
+
const inner = `${marker}${renderPasteRuns(runs)}`;
|
|
217224
|
+
const pPrXml = `<w:pPr><w:pStyle w:val="${escapeXmlAttribute(style)}"/></w:pPr>`;
|
|
217225
|
+
const stamp = input.trackedStamp;
|
|
217226
|
+
const pPr = stamp ? renderTrackedParagraphMarkProperties(pPrXml, stamp) : pPrXml;
|
|
217227
|
+
const body = stamp && inner ? wrapNoteTrackedInsertion(inner, stamp) : inner;
|
|
217228
|
+
const rsid = stamp ? ` w:rsidR="${escapeXmlAttribute(stamp.rsid)}"` : "";
|
|
217229
|
+
return `<w:p w14:paraId="${escapeXmlAttribute(paraId)}"${rsid}>` + `${pPr}${body}</w:p>`;
|
|
217230
|
+
}
|
|
217231
|
+
function wrapNoteTrackedInsertion(inner, stamp) {
|
|
217232
|
+
const id = stamp.allocateWId();
|
|
217233
|
+
return `${renderTrackedChangeOpen("ins", id, stamp, true)}${inner}</w:ins>`;
|
|
216841
217234
|
}
|
|
216842
217235
|
function noteBodyRuns(paragraph) {
|
|
216843
217236
|
if (!paragraph.inlines)
|
|
@@ -232266,12 +232659,19 @@ function preparePasteFragmentMutation(input) {
|
|
|
232266
232659
|
if (!review.ok)
|
|
232267
232660
|
return rejected18(txId, review.reason);
|
|
232268
232661
|
const mergedSidecarPerPart = { ...listExtras.perPart, ...imageExtras.value.perPart, ...review.perPart };
|
|
232662
|
+
const pastedNotes = op.fragment.notes ?? [];
|
|
232663
|
+
const noteParagraphs = pastedNotes.flatMap((note) => note.paragraphs);
|
|
232664
|
+
const notesStamp = changeMode === "tracked" && pastedNotes.length > 0 ? pickTrackedStamp(input, trackedFragmentCarrierBudget(noteParagraphs) + noteParagraphs.length) : null;
|
|
232665
|
+
if (changeMode === "tracked" && pastedNotes.length > 0 && !notesStamp) {
|
|
232666
|
+
return rejected18(txId, "no-author-configured");
|
|
232667
|
+
}
|
|
232269
232668
|
const notes = compilePastedNotesMetadata({
|
|
232270
232669
|
state,
|
|
232271
232670
|
blocks: resolvedBlocks,
|
|
232272
|
-
notes:
|
|
232671
|
+
notes: pastedNotes,
|
|
232273
232672
|
documentRelsBytes: plannedPackagePartBytes(state, mergedSidecarPerPart, DOCUMENT_RELS_PART_URI9),
|
|
232274
|
-
contentTypesBytes: plannedPackagePartBytes(state, mergedSidecarPerPart, CONTENT_TYPES_PART_URI11)
|
|
232673
|
+
contentTypesBytes: plannedPackagePartBytes(state, mergedSidecarPerPart, CONTENT_TYPES_PART_URI11),
|
|
232674
|
+
trackedStamp: notesStamp
|
|
232275
232675
|
});
|
|
232276
232676
|
if (!notes.ok)
|
|
232277
232677
|
return rejected18(txId, notes.reason);
|
|
@@ -232287,7 +232687,8 @@ function preparePasteFragmentMutation(input) {
|
|
|
232287
232687
|
patchMaps: { ...listExtras.patchMaps, ...imageExtras.value.patchMaps, ...review.patchMaps, ...notes.patchMaps },
|
|
232288
232688
|
createdRefs: review.createdRefs,
|
|
232289
232689
|
commentIdMap: review.commentIdMap,
|
|
232290
|
-
noteIdMap: notes.noteIdMap
|
|
232690
|
+
noteIdMap: notes.noteIdMap,
|
|
232691
|
+
revisionWIds: usedTrackedWIds(notesStamp)
|
|
232291
232692
|
};
|
|
232292
232693
|
if (isStoryTarget(pasteTarget)) {
|
|
232293
232694
|
if (preflight.plan.target.kind !== "story")
|
|
@@ -232495,7 +232896,9 @@ function runTrackedWholeStoryReplaceCommit(input, target, rendered, blocks, extr
|
|
|
232495
232896
|
const preview = prepare();
|
|
232496
232897
|
if (!preview)
|
|
232497
232898
|
return rejected18(txId, "paste-tracked-structural-unsupported");
|
|
232498
|
-
const revisionWIds = planRevisionWIdBlock(state, preview.wordIds.length
|
|
232899
|
+
const revisionWIds = planRevisionWIdBlock(state, preview.wordIds.length, {
|
|
232900
|
+
afterMax: afterMaxFromPlannedRevisionWIds(extras.revisionWIds)
|
|
232901
|
+
});
|
|
232499
232902
|
const replacement = prepare(revisionWIds);
|
|
232500
232903
|
if (!replacement)
|
|
232501
232904
|
return rejected18(txId, "paste-tracked-structural-unsupported");
|
|
@@ -232525,7 +232928,7 @@ function runTrackedWholeStoryReplaceCommit(input, target, rendered, blocks, extr
|
|
|
232525
232928
|
extraPatchMaps: extras.patchMaps,
|
|
232526
232929
|
packagePartUris: inlineExtras.partUris,
|
|
232527
232930
|
storyWideProjection: true,
|
|
232528
|
-
revisionWIds,
|
|
232931
|
+
revisionWIds: [...revisionWIds, ...extras.revisionWIds ?? []],
|
|
232529
232932
|
indexRefreshScope: { perPart: { [target.partUri]: {
|
|
232530
232933
|
beforeWindow: { startByte: target.byteStart, endByte: target.byteEnd },
|
|
232531
232934
|
kind: "wide-rewrite",
|
|
@@ -232611,7 +233014,7 @@ function runParagraphBlockPasteCommit(input, target, blocks, extras, inlineExtra
|
|
|
232611
233014
|
return rejected18(txId, "paste-target-unsupported");
|
|
232612
233015
|
const changeMode = op.changeMode ?? "direct";
|
|
232613
233016
|
const anchorXml = TD64.decode(bytes.subarray(anchor.byteStart, anchor.byteEnd));
|
|
232614
|
-
const trackedStamp = changeMode === "tracked" ? pickTrackedStamp(input, trackedFragmentCarrierBudget(blocks) + (target.placement === "replace" ? trackedBlockDeletionCarrierBudget(anchorXml) : 2)) : null;
|
|
233017
|
+
const trackedStamp = changeMode === "tracked" ? pickTrackedStamp(input, trackedFragmentCarrierBudget(blocks) + (target.placement === "replace" ? trackedBlockDeletionCarrierBudget(anchorXml) : 2), { afterMax: afterMaxFromPlannedRevisionWIds(extras.revisionWIds) }) : null;
|
|
232615
233018
|
if (changeMode === "tracked" && !trackedStamp)
|
|
232616
233019
|
return rejected18(txId, "no-author-configured");
|
|
232617
233020
|
const trackedDeletedAnchor = trackedStamp && target.placement === "replace" ? renderTrackedBlockDeletion({
|
|
@@ -232763,7 +233166,7 @@ function runParagraphBlockPasteCommit(input, target, blocks, extras, inlineExtra
|
|
|
232763
233166
|
extraPatchMaps: { ...extras.patchMaps, ...commentCascade.patchMaps, ...resourceCleanup.patchMaps },
|
|
232764
233167
|
packagePartUris: [...inlineExtras.partUris, ...resourceCleanup.packagePartUris],
|
|
232765
233168
|
storyWideProjection: target.placement === "replace" || blocks.some((block) => block.kind === "table"),
|
|
232766
|
-
revisionWIds: usedTrackedWIds(trackedStamp),
|
|
233169
|
+
revisionWIds: usedTrackedWIds(trackedStamp, extras.revisionWIds),
|
|
232767
233170
|
...target.placement === "replace" ? {
|
|
232768
233171
|
indexRefreshScope: {
|
|
232769
233172
|
perPart: {
|
|
@@ -232788,7 +233191,7 @@ function runWholeTableReplaceCommit(input, target, blocks, extras, inlineExtras)
|
|
|
232788
233191
|
return rejected18(txId, "paste-target-unsupported");
|
|
232789
233192
|
}
|
|
232790
233193
|
const replacedParagraphs = index.entries.filter((entry) => entry.byteStart >= target.byteStart && entry.byteEnd <= target.byteEnd);
|
|
232791
|
-
const trackedStamp = changeMode === "tracked" ? pickTrackedStamp(input, trackedFragmentCarrierBudget(blocks) + table.rows.length + 2) : null;
|
|
233194
|
+
const trackedStamp = changeMode === "tracked" ? pickTrackedStamp(input, trackedFragmentCarrierBudget(blocks) + table.rows.length + 2, { afterMax: afterMaxFromPlannedRevisionWIds(extras.revisionWIds) }) : null;
|
|
232792
233195
|
if (changeMode === "tracked" && !trackedStamp)
|
|
232793
233196
|
return rejected18(txId, "no-author-configured");
|
|
232794
233197
|
const replacedXml = TD64.decode(bytes.subarray(target.byteStart, target.byteEnd));
|
|
@@ -232893,7 +233296,7 @@ function runWholeTableReplaceCommit(input, target, blocks, extras, inlineExtras)
|
|
|
232893
233296
|
extraPatchMaps: { ...extras.patchMaps, ...commentCascade.patchMaps },
|
|
232894
233297
|
packagePartUris: inlineExtras.partUris,
|
|
232895
233298
|
storyWideProjection: true,
|
|
232896
|
-
revisionWIds: usedTrackedWIds(trackedStamp),
|
|
233299
|
+
revisionWIds: usedTrackedWIds(trackedStamp, extras.revisionWIds),
|
|
232897
233300
|
indexRefreshScope: {
|
|
232898
233301
|
perPart: {
|
|
232899
233302
|
[target.partUri]: {
|
|
@@ -232928,7 +233331,7 @@ function runCrossParagraphTrackedPasteCommit(input, target, blocks, extras, inli
|
|
|
232928
233331
|
if (!rangeIntegrity.ok)
|
|
232929
233332
|
return rejected18(txId, "invalid-range");
|
|
232930
233333
|
const coveredEntries = index.entries.filter((entry) => entry.ordinal >= start.ordinal && entry.ordinal <= end.ordinal);
|
|
232931
|
-
const stamp = pickTrackedStamp(input, trackedFragmentCarrierBudget(blocks) + coveredEntries.length * 3 + 4);
|
|
233334
|
+
const stamp = pickTrackedStamp(input, trackedFragmentCarrierBudget(blocks) + coveredEntries.length * 3 + 4, { afterMax: afterMaxFromPlannedRevisionWIds(extras.revisionWIds) });
|
|
232932
233335
|
if (!stamp)
|
|
232933
233336
|
return rejected18(txId, "no-author-configured");
|
|
232934
233337
|
const patches = [];
|
|
@@ -233030,7 +233433,7 @@ function runCrossParagraphTrackedPasteCommit(input, target, blocks, extras, inli
|
|
|
233030
233433
|
extraPatchMaps: extras.patchMaps,
|
|
233031
233434
|
packagePartUris: inlineExtras.partUris,
|
|
233032
233435
|
storyWideProjection: true,
|
|
233033
|
-
revisionWIds: usedTrackedWIds(stamp),
|
|
233436
|
+
revisionWIds: usedTrackedWIds(stamp, extras.revisionWIds),
|
|
233034
233437
|
indexRefreshScope: {
|
|
233035
233438
|
perPart: {
|
|
233036
233439
|
[target.partUri]: {
|
|
@@ -233070,7 +233473,9 @@ function runCrossParagraphPasteCommit(input, target, blocks, extras, inlineExtra
|
|
|
233070
233473
|
return rejected18(txId, "invalid-range");
|
|
233071
233474
|
const endpointXml = TD64.decode(bytes.subarray(start.byteStart, start.byteEnd)) + TD64.decode(bytes.subarray(end.byteStart, end.byteEnd));
|
|
233072
233475
|
const wrapperCount = [...endpointXml.matchAll(/<(?:[\w.-]+:)?(?:ins|del|moveFrom|moveTo)\b/g)].length;
|
|
233073
|
-
const plannedWIds = planRevisionWIdBlock(state, Math.max(1, wrapperCount * 2 + 4)
|
|
233476
|
+
const plannedWIds = planRevisionWIdBlock(state, Math.max(1, wrapperCount * 2 + 4), {
|
|
233477
|
+
afterMax: afterMaxFromPlannedRevisionWIds(extras.revisionWIds)
|
|
233478
|
+
});
|
|
233074
233479
|
let usedWIds = 0;
|
|
233075
233480
|
let splicePlan;
|
|
233076
233481
|
let mintSalt = 0;
|
|
@@ -233147,7 +233552,7 @@ function runCrossParagraphPasteCommit(input, target, blocks, extras, inlineExtra
|
|
|
233147
233552
|
packagePartUris: inlineExtras.partUris,
|
|
233148
233553
|
storyWideProjection: true,
|
|
233149
233554
|
indexRefreshScope: contribution.indexRefreshScope,
|
|
233150
|
-
revisionWIds: plannedWIds.slice(0, usedWIds)
|
|
233555
|
+
revisionWIds: [...plannedWIds.slice(0, usedWIds), ...extras.revisionWIds ?? []]
|
|
233151
233556
|
});
|
|
233152
233557
|
}
|
|
233153
233558
|
function collectRemovedBookmarkRefs(ownerXml, removedXml, storyId) {
|
|
@@ -233223,7 +233628,7 @@ function tryRunTableRowPasteCommit(input, pasteTarget, pastedBlocks, additionalP
|
|
|
233223
233628
|
scopeHintOpenTag: matchParagraphOpenTag(targetParagraphXml) ?? ""
|
|
233224
233629
|
});
|
|
233225
233630
|
const createdParagraphIds = [];
|
|
233226
|
-
const trackedStamp = (input.op.changeMode ?? "direct") === "tracked" ? pickTrackedStamp(input, trackedFragmentCarrierBudget(pastedBlocks) + 2) : null;
|
|
233631
|
+
const trackedStamp = (input.op.changeMode ?? "direct") === "tracked" ? pickTrackedStamp(input, trackedFragmentCarrierBudget(pastedBlocks) + 2, { afterMax: afterMaxFromPlannedRevisionWIds(additionalPatches.revisionWIds) }) : null;
|
|
233227
233632
|
if ((input.op.changeMode ?? "direct") === "tracked" && !trackedStamp) {
|
|
233228
233633
|
return rejected18(transactionId, "no-author-configured");
|
|
233229
233634
|
}
|
|
@@ -233310,7 +233715,7 @@ function tryRunTableRowPasteCommit(input, pasteTarget, pastedBlocks, additionalP
|
|
|
233310
233715
|
provisionalToFinal: Object.fromEntries(createdParagraphIds.map((paragraphId, index) => [`${transactionId}:paste:${index}`, paragraphId])),
|
|
233311
233716
|
extraPatchMaps: additionalPatches.patchMaps,
|
|
233312
233717
|
storyWideProjection: true,
|
|
233313
|
-
revisionWIds: usedTrackedWIds(trackedStamp)
|
|
233718
|
+
revisionWIds: usedTrackedWIds(trackedStamp, additionalPatches.revisionWIds)
|
|
233314
233719
|
});
|
|
233315
233720
|
}
|
|
233316
233721
|
function findContainingTableCell(tableCatalog, targetParagraph) {
|
|
@@ -233710,7 +234115,7 @@ function runPasteSpliceCommit(input, target, resolvedBlocks, listExtras, imageEx
|
|
|
233710
234115
|
const changeMode = input.op.changeMode ?? "direct";
|
|
233711
234116
|
const wrapAllTracked = changeMode === "tracked";
|
|
233712
234117
|
const fragmentTracked = fragmentHasTrackedInsertion(resolvedBlocks);
|
|
233713
|
-
const trackedStamp = wrapAllTracked || fragmentTracked ? pickTrackedStamp(input, trackedFragmentCarrierBudget(resolvedBlocks) + 4) : null;
|
|
234118
|
+
const trackedStamp = wrapAllTracked || fragmentTracked ? pickTrackedStamp(input, trackedFragmentCarrierBudget(resolvedBlocks) + 4, { afterMax: afterMaxFromPlannedRevisionWIds(listExtras.revisionWIds) }) : null;
|
|
233714
234119
|
if ((wrapAllTracked || fragmentTracked) && !trackedStamp)
|
|
233715
234120
|
return rejected18(txId, "no-author-configured");
|
|
233716
234121
|
let mintSalt = 0;
|
|
@@ -233840,7 +234245,7 @@ function runPasteSpliceCommit(input, target, resolvedBlocks, listExtras, imageEx
|
|
|
233840
234245
|
extraPatchMaps: listExtras.patchMaps,
|
|
233841
234246
|
storyWideProjection: resolvedBlocks.some((block) => block.kind === "table"),
|
|
233842
234247
|
packagePartUris: imageExtras.partUris,
|
|
233843
|
-
revisionWIds: usedTrackedWIds(trackedStamp),
|
|
234248
|
+
revisionWIds: usedTrackedWIds(trackedStamp, listExtras.revisionWIds),
|
|
233844
234249
|
indexRefreshScope: {
|
|
233845
234250
|
perPart: {
|
|
233846
234251
|
[partUri]: {
|
|
@@ -234860,11 +235265,11 @@ function injectTrackedMarkIntoLastParagraph(xml, stamp, kind) {
|
|
|
234860
235265
|
const replacement = injectTrackedParagraphMarkIntoXml(match[0], stamp, kind);
|
|
234861
235266
|
return xml.slice(0, match.index) + replacement + xml.slice(match.index + match[0].length);
|
|
234862
235267
|
}
|
|
234863
|
-
function pickTrackedStamp(input, capacity) {
|
|
235268
|
+
function pickTrackedStamp(input, capacity, options) {
|
|
234864
235269
|
const author = input.authorOverride ?? input.author;
|
|
234865
235270
|
if (!author)
|
|
234866
235271
|
return null;
|
|
234867
|
-
const plannedWIds = planRevisionWIdBlock(input.state, Math.max(1, capacity));
|
|
235272
|
+
const plannedWIds = planRevisionWIdBlock(input.state, Math.max(1, capacity), options);
|
|
234868
235273
|
const stamp = {
|
|
234869
235274
|
rsid: allocateTxRsid(input.txId),
|
|
234870
235275
|
plannedWIds,
|
|
@@ -234881,8 +235286,17 @@ function pickTrackedStamp(input, capacity) {
|
|
|
234881
235286
|
};
|
|
234882
235287
|
return stamp;
|
|
234883
235288
|
}
|
|
234884
|
-
function
|
|
234885
|
-
|
|
235289
|
+
function afterMaxFromPlannedRevisionWIds(revisionWIds) {
|
|
235290
|
+
if (!revisionWIds || revisionWIds.length === 0)
|
|
235291
|
+
return;
|
|
235292
|
+
return Math.max(...revisionWIds);
|
|
235293
|
+
}
|
|
235294
|
+
function usedTrackedWIds(stamp, extra) {
|
|
235295
|
+
const ids = [
|
|
235296
|
+
...stamp ? stamp.plannedWIds.slice(0, stamp.usedWIdCount) : [],
|
|
235297
|
+
...extra ?? []
|
|
235298
|
+
];
|
|
235299
|
+
return ids.length > 0 ? ids : undefined;
|
|
234886
235300
|
}
|
|
234887
235301
|
function replayTrackedStamp(source) {
|
|
234888
235302
|
const replay = {
|
|
@@ -291804,8 +292218,13 @@ class V2SelectionMutationAdapter {
|
|
|
291804
292218
|
const tx = begun.tx;
|
|
291805
292219
|
const editTextStartedAt = nowMs6();
|
|
291806
292220
|
const collapsedInlineAffinity = selectionCollapsedInlineAffinity(options);
|
|
292221
|
+
const collapsedOutsideContentControl = options?.collapsedOutsideContentControl === true;
|
|
291807
292222
|
const kernelEdits = edits.map((edit, index2) => ({
|
|
291808
|
-
on:
|
|
292223
|
+
on: edit.on.startOffset === edit.on.endOffset ? {
|
|
292224
|
+
...edit.on,
|
|
292225
|
+
...collapsedInlineAffinity ? { collapsedInlineAffinity } : {},
|
|
292226
|
+
...collapsedOutsideContentControl ? { collapsedOutsideContentControl: true } : {}
|
|
292227
|
+
} : edit.on,
|
|
291809
292228
|
newText: edit.newText,
|
|
291810
292229
|
...options?.changeMode === "tracked" && (isRewrite || edits.length > 1) && !typingHistoryMetadata(options) && story.storyKind !== "textbox" ? {
|
|
291811
292230
|
rewriteGroupId: `${tx.txId}:0`,
|
|
@@ -357366,7 +357785,14 @@ function logicalEntryMatchesStoryFilter(entry, filter) {
|
|
|
357366
357785
|
return isBodyStoryId2(entry.storyId);
|
|
357367
357786
|
if (!filter.storyIds?.has(entry.storyId))
|
|
357368
357787
|
return false;
|
|
357369
|
-
|
|
357788
|
+
if (!filter.noteId)
|
|
357789
|
+
return true;
|
|
357790
|
+
return ownedLogicalNoteIds(entry).includes(filter.noteId);
|
|
357791
|
+
}
|
|
357792
|
+
function ownedLogicalNoteIds(entry) {
|
|
357793
|
+
if (entry.noteIds && entry.noteIds.length > 0)
|
|
357794
|
+
return entry.noteIds;
|
|
357795
|
+
return entry.noteId != null ? [entry.noteId] : [];
|
|
357370
357796
|
}
|
|
357371
357797
|
function isVisibleLogicalChange(entry) {
|
|
357372
357798
|
return isVisibleLogicalTrackedChange(entry);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@superdoc/mcp",
|
|
3
|
-
"version": "1.2.1-next.
|
|
3
|
+
"version": "1.2.1-next.3",
|
|
4
4
|
"description": "Model Context Protocol server for SuperDoc, giving an AI agent tools to read and edit .docx files.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "AGPL-3.0",
|
|
@@ -24,13 +24,13 @@
|
|
|
24
24
|
],
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
27
|
-
"@superdoc/sdk": "2.15.1-next.
|
|
27
|
+
"@superdoc/sdk": "2.15.1-next.3",
|
|
28
28
|
"debug": "^4.4.3",
|
|
29
29
|
"zod": "^4.3.6"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"superdoc": "2.18.1-next.
|
|
33
|
-
"@superdoc/docx-engine": "0.17.1-next.
|
|
32
|
+
"superdoc": "2.18.1-next.3",
|
|
33
|
+
"@superdoc/docx-engine": "0.17.1-next.3",
|
|
34
34
|
"@superdoc/document-api": "0.1.0-alpha.0",
|
|
35
35
|
"@types/bun": "^1.3.8",
|
|
36
36
|
"@types/node": "22.19.2",
|