@superdoc/mcp 1.4.0-next.8 → 1.4.0-next.9
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 +466 -41
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -31330,7 +31330,7 @@ var init_host = __esm(() => {
|
|
|
31330
31330
|
});
|
|
31331
31331
|
|
|
31332
31332
|
// ../../packages/sdk/langs/node/src/runtime/sdk-version.generated.ts
|
|
31333
|
-
var SDK_VERSION = "2.17.0-next.
|
|
31333
|
+
var SDK_VERSION = "2.17.0-next.9";
|
|
31334
31334
|
|
|
31335
31335
|
// ../../packages/sdk/langs/node/src/runtime/embedded-platform.ts
|
|
31336
31336
|
import { accessSync, chmodSync, constants, existsSync, statSync } from "node:fs";
|
|
@@ -135279,7 +135279,28 @@ function control(xml, element) {
|
|
|
135279
135279
|
const locks = children.filter((child) => is(child, "lock"));
|
|
135280
135280
|
const deletable = locks.every((lock) => attr(lock, "val") === "unlocked" || attr(lock, "val") === "contentLocked");
|
|
135281
135281
|
const supportedProperties = children.every((child) => child.tag.uri === W3 ? ["id", "tag", "alias", "text", "richText", "lock", "rPr", "placeholder", "showingPlcHdr", "temporary"].includes(child.tag.local) : child.tag.uri === "http://schemas.microsoft.com/office/word/2012/wordml" && child.tag.local === "appearance");
|
|
135282
|
-
|
|
135282
|
+
const contentXml = xml.slice(content[0].start, content[0].end);
|
|
135283
|
+
const contentOpenEnd = contentXml.indexOf(">") + 1;
|
|
135284
|
+
const contentCloseStart = contentXml.lastIndexOf("</");
|
|
135285
|
+
const contentRuns = contentCloseStart < contentOpenEnd ? "" : contentXml.slice(contentOpenEnd, contentCloseStart);
|
|
135286
|
+
const offset = content[0].start - element.start;
|
|
135287
|
+
const itemXml = fragment2(xml, element);
|
|
135288
|
+
const head = itemXml.slice(0, offset + contentOpenEnd);
|
|
135289
|
+
const tail = itemXml.slice(offset + Math.max(contentOpenEnd, contentCloseStart));
|
|
135290
|
+
const unlocked = locks.every((lock) => attr(lock, "val") === "unlocked");
|
|
135291
|
+
const editable = locks.every((lock) => attr(lock, "val") === "unlocked" || attr(lock, "val") === "sdtLocked");
|
|
135292
|
+
return {
|
|
135293
|
+
id,
|
|
135294
|
+
key: `sdt:${attr(key2, "val")}`,
|
|
135295
|
+
xml: itemXml,
|
|
135296
|
+
contentXml: contentRuns,
|
|
135297
|
+
head,
|
|
135298
|
+
tail,
|
|
135299
|
+
deletable: deletable && supportedProperties,
|
|
135300
|
+
insertable: unlocked && supportedProperties,
|
|
135301
|
+
editable: editable && supportedProperties,
|
|
135302
|
+
supportedProperties
|
|
135303
|
+
};
|
|
135283
135304
|
}
|
|
135284
135305
|
function inspectInlineControlRemoval(beforeXml, afterXml, namespaces = {}) {
|
|
135285
135306
|
const before = elements(beforeXml, namespaces);
|
|
@@ -135366,6 +135387,137 @@ function bodyOperationsCoverInlineControlRemoval(base2, target, operations, matc
|
|
|
135366
135387
|
}
|
|
135367
135388
|
return removed.size === changes.length && changes.every((entry) => entry.baseId !== null && removed.has(entry.baseId));
|
|
135368
135389
|
}
|
|
135390
|
+
function inspectInlineControlReplay(beforeXml, afterXml, namespaces = {}) {
|
|
135391
|
+
const before = elements(beforeXml, namespaces);
|
|
135392
|
+
const after = elements(afterXml, namespaces);
|
|
135393
|
+
if (!before || !after)
|
|
135394
|
+
return null;
|
|
135395
|
+
const xmlns = "http://www.w3.org/2000/xmlns/";
|
|
135396
|
+
const attributes = (root, allowed) => Object.values(root.tag.attributes).every((attribute) => attribute.uri === xmlns || allowed(attribute.uri, attribute.local));
|
|
135397
|
+
const runProperties = (root) => is(root, "rPr") && attributes(root, () => false) && root.children.every((child) => child.tag.uri === W3 && RUN_PROPERTIES.has(child.tag.local) && !child.children.length && attributes(child, (uri) => uri === W3));
|
|
135398
|
+
const simpleRun = (root) => safeRun(root) && attributes(root, (uri, local) => uri === W3 && ["rsidR", "rsidRPr", "rsidDel"].includes(local)) && root.children.filter((child) => is(child, "t")).length === 1 && root.children.every((child) => runProperties(child) || is(child, "t") && !child.tag.isSelfClosing && attributes(child, (uri, local) => uri === "http://www.w3.org/XML/1998/namespace" && local === "space"));
|
|
135399
|
+
const safeControlProperties = (root) => {
|
|
135400
|
+
if (!attributes(root, (uri, local) => uri === W3 && ["rsidR", "rsidRPr", "rsidDel"].includes(local)))
|
|
135401
|
+
return false;
|
|
135402
|
+
const properties = root.children.find((child) => is(child, "sdtPr"));
|
|
135403
|
+
const content = root.children.find((child) => is(child, "sdtContent"));
|
|
135404
|
+
if (!attributes(properties, () => false) || !attributes(content, () => false) || content.tag.isSelfClosing)
|
|
135405
|
+
return false;
|
|
135406
|
+
if (properties.children.filter((child) => is(child, "text") || is(child, "richText")).length > 1)
|
|
135407
|
+
return false;
|
|
135408
|
+
const seen = new Set;
|
|
135409
|
+
for (const child of properties.children) {
|
|
135410
|
+
if (seen.has(child.tag.name))
|
|
135411
|
+
return false;
|
|
135412
|
+
seen.add(child.tag.name);
|
|
135413
|
+
if (!attributes(child, (uri) => uri === W3 || uri === child.tag.uri))
|
|
135414
|
+
return false;
|
|
135415
|
+
if (is(child, "rPr")) {
|
|
135416
|
+
if (!runProperties(child))
|
|
135417
|
+
return false;
|
|
135418
|
+
} else if (is(child, "placeholder")) {
|
|
135419
|
+
if (child.children.some((item) => !is(item, "docPart") || item.children.length || !attributes(item, (uri) => uri === W3)))
|
|
135420
|
+
return false;
|
|
135421
|
+
} else if (child.children.length)
|
|
135422
|
+
return false;
|
|
135423
|
+
}
|
|
135424
|
+
return root.children.filter((child) => is(child, "sdtEndPr")).every((child) => attributes(child, () => false) && child.children.every(runProperties));
|
|
135425
|
+
};
|
|
135426
|
+
const inspect = (xml, roots) => {
|
|
135427
|
+
const result = [];
|
|
135428
|
+
for (const [index, root] of roots.entries()) {
|
|
135429
|
+
if (simpleRun(root))
|
|
135430
|
+
continue;
|
|
135431
|
+
const item = control(xml, root);
|
|
135432
|
+
if (!item || !item.supportedProperties || !safeControlProperties(root) || !root.children.find((child) => is(child, "sdtContent"))?.children.every(simpleRun) || result.some((other) => other.id === item.id || other.key === item.key))
|
|
135433
|
+
return null;
|
|
135434
|
+
result.push({ ...item, index });
|
|
135435
|
+
}
|
|
135436
|
+
return result;
|
|
135437
|
+
};
|
|
135438
|
+
const previous = inspect(beforeXml, before);
|
|
135439
|
+
const next = inspect(afterXml, after);
|
|
135440
|
+
if (!previous || !next || !previous.length && !next.length)
|
|
135441
|
+
return null;
|
|
135442
|
+
const normalized = (xml) => signature(`<scope ${Object.entries(namespaces).filter(([prefix]) => prefix && prefix !== "xml").map(([prefix, uri]) => `xmlns:${prefix}=${JSON.stringify(uri)}`).join(" ")}>${xml}</scope>`);
|
|
135443
|
+
const anchors = [];
|
|
135444
|
+
for (const old of previous) {
|
|
135445
|
+
const current = next.find((item) => item.id === old.id);
|
|
135446
|
+
if (!current || old.key !== current.key || normalized(old.head + old.tail) !== normalized(current.head + current.tail))
|
|
135447
|
+
return null;
|
|
135448
|
+
const changed = normalized(old.xml) !== normalized(current.xml);
|
|
135449
|
+
if (changed && !old.editable)
|
|
135450
|
+
return null;
|
|
135451
|
+
anchors.push({ beforeIndex: old.index, afterIndex: current.index, before: old, after: current, changed });
|
|
135452
|
+
}
|
|
135453
|
+
if (anchors.some((anchor, index) => index > 0 && anchor.afterIndex <= anchors[index - 1].afterIndex))
|
|
135454
|
+
return null;
|
|
135455
|
+
const inserted = next.filter((item) => !previous.some((old) => old.id === item.id));
|
|
135456
|
+
if (inserted.some((item) => !item.insertable))
|
|
135457
|
+
return null;
|
|
135458
|
+
return {
|
|
135459
|
+
anchors,
|
|
135460
|
+
inserted,
|
|
135461
|
+
updated: anchors.filter((anchor) => anchor.changed),
|
|
135462
|
+
beforeRoots: before.map((root) => fragment2(beforeXml, root)),
|
|
135463
|
+
afterRoots: after.map((root) => fragment2(afterXml, root))
|
|
135464
|
+
};
|
|
135465
|
+
}
|
|
135466
|
+
function bodyOperationsCoverInlineControlReplay(base2, target, operations, match) {
|
|
135467
|
+
const family = match.families.find((item) => item.family === "content-controls");
|
|
135468
|
+
const changes = family?.entityMatch?.entries.filter((entry) => entry.disposition !== "matched" || entry.changed || entry.moved);
|
|
135469
|
+
if (!changes?.length || family?.hasAmbiguity || changes.some((entry) => entry.disposition !== "inserted" && entry.disposition !== "matched" || entry.moved))
|
|
135470
|
+
return false;
|
|
135471
|
+
const counts = (snapshot2) => {
|
|
135472
|
+
const result = new Map;
|
|
135473
|
+
const visit = (root) => {
|
|
135474
|
+
if (is(root, "sdtPr"))
|
|
135475
|
+
for (const child of root.children.filter((item) => is(item, "id"))) {
|
|
135476
|
+
const id = numericIdentity(attr(child, "val"));
|
|
135477
|
+
if (id !== null)
|
|
135478
|
+
result.set(id, (result.get(id) ?? 0) + 1);
|
|
135479
|
+
}
|
|
135480
|
+
root.children.forEach(visit);
|
|
135481
|
+
};
|
|
135482
|
+
for (const entry of [...snapshot2.body, ...(snapshot2.stories ?? []).flatMap((story) => story.entries)]) {
|
|
135483
|
+
const roots = elements(entry.runXml ?? "", {}, true);
|
|
135484
|
+
if (!roots)
|
|
135485
|
+
return null;
|
|
135486
|
+
roots.forEach(visit);
|
|
135487
|
+
}
|
|
135488
|
+
return result;
|
|
135489
|
+
};
|
|
135490
|
+
const oldCounts = counts(base2), newCounts = counts(target);
|
|
135491
|
+
if (!oldCounts || !newCounts)
|
|
135492
|
+
return false;
|
|
135493
|
+
const covered = new Map;
|
|
135494
|
+
for (const operation of operations) {
|
|
135495
|
+
if (operation.kind !== "edit" && operation.kind !== "formatEdit")
|
|
135496
|
+
continue;
|
|
135497
|
+
const previous = base2.body.filter((entry) => entry.blockId === operation.blockId);
|
|
135498
|
+
const next = target.body.filter((entry) => entry.blockId === operation.blockId);
|
|
135499
|
+
if (previous.length !== 1 || next.length !== 1)
|
|
135500
|
+
continue;
|
|
135501
|
+
const before = previous[0], after = next[0];
|
|
135502
|
+
const proof = inspectInlineControlReplay(before.runXml ?? "", after.runXml ?? "");
|
|
135503
|
+
if (!proof)
|
|
135504
|
+
continue;
|
|
135505
|
+
if (!/^[0-9A-Fa-f]{8}$/.test(before.blockId) || (before.structuralScope ?? "body") !== "body" || (after.structuralScope ?? "body") !== "body" || before.trackedChangeAnnotationKeys?.length || before.structuralChangeAnnotationKeys?.length || after.trackedChangeAnnotationKeys?.length || after.structuralChangeAnnotationKeys?.length || operation.targetRunXml !== after.runXml)
|
|
135506
|
+
return false;
|
|
135507
|
+
for (const item of proof.inserted) {
|
|
135508
|
+
if (covered.has(item.key) || oldCounts.has(item.id) || newCounts.get(item.id) !== 1)
|
|
135509
|
+
return false;
|
|
135510
|
+
covered.set(item.key, "inserted");
|
|
135511
|
+
}
|
|
135512
|
+
for (const anchor of proof.updated) {
|
|
135513
|
+
const item = anchor.after;
|
|
135514
|
+
if (covered.has(item.key) || oldCounts.get(item.id) !== 1 || newCounts.get(item.id) !== 1)
|
|
135515
|
+
return false;
|
|
135516
|
+
covered.set(item.key, "matched");
|
|
135517
|
+
}
|
|
135518
|
+
}
|
|
135519
|
+
return covered.size === changes.length && changes.every((entry) => entry.targetId !== null && covered.get(entry.targetId) === entry.disposition);
|
|
135520
|
+
}
|
|
135369
135521
|
var import_saxes3, W3 = "http://schemas.openxmlformats.org/wordprocessingml/2006/main", attr = (element, name) => Object.values(element.tag.attributes).find((attribute) => attribute.uri === W3 && attribute.local === name)?.value, is = (element, name) => element.tag.uri === W3 && element.tag.local === name, fragment2 = (xml, element) => xml.slice(element.start, element.end), signature = (xml) => canonicalizeXmlForSignature(xml), RUN_PROPERTIES;
|
|
135370
135522
|
var init_inline_control_removal = __esm(() => {
|
|
135371
135523
|
init_run_signature();
|
|
@@ -136241,7 +136393,7 @@ function parseXmlStartTag(rawTag) {
|
|
|
136241
136393
|
return null;
|
|
136242
136394
|
}
|
|
136243
136395
|
function validateRunContents(xml, options) {
|
|
136244
|
-
if (options.baseRunXml !== undefined && inspectInlineControlRemoval(options.baseRunXml, xml)) {
|
|
136396
|
+
if (options.baseRunXml !== undefined && (inspectInlineControlRemoval(options.baseRunXml, xml) || inspectInlineControlReplay(options.baseRunXml, xml))) {
|
|
136245
136397
|
return { ok: true };
|
|
136246
136398
|
}
|
|
136247
136399
|
const baseHasNoteMarker = options.baseRunXml !== undefined && /<(?:[A-Za-z_][\w.-]*:)?(?:footnoteRef|endnoteRef)\b/.test(options.baseRunXml);
|
|
@@ -140072,7 +140224,7 @@ function planCompare(base2, target) {
|
|
|
140072
140224
|
const trackedRevisionSetChanged = semanticAnalysis.familyDeltas.find((delta) => delta.family === "tracked-changes")?.detectedChange === true;
|
|
140073
140225
|
const revisionReplay = deriveCompareBodyOperationsWithRevisionReplay(base2, target, matchResult);
|
|
140074
140226
|
const bodyOperations = revisionReplay.operations;
|
|
140075
|
-
if (bodyOperationsCoverInlineControlRemoval(base2, target, bodyOperations, matchResult)) {
|
|
140227
|
+
if (bodyOperationsCoverInlineControlRemoval(base2, target, bodyOperations, matchResult) || bodyOperationsCoverInlineControlReplay(base2, target, bodyOperations, matchResult)) {
|
|
140076
140228
|
semanticAnalysis = markFamilySupported(semanticAnalysis, "content-controls");
|
|
140077
140229
|
}
|
|
140078
140230
|
const computedStoryOperations = buildStoryOperations(base2, target, semanticAnalysis);
|
|
@@ -164393,6 +164545,9 @@ function planDirectInlineEdit(paragraphBytes, startOffset, endOffset, newText, c
|
|
|
164393
164545
|
...enclosingSdts.length > 0 ? { requiresCollaborationSessionSync: true } : {}
|
|
164394
164546
|
};
|
|
164395
164547
|
}
|
|
164548
|
+
const sdtProtection = validateSelectedSdtProtection(model.pieces, startOffset, endOffset);
|
|
164549
|
+
if (sdtProtection)
|
|
164550
|
+
return { ok: false, reason: sdtProtection };
|
|
164396
164551
|
const tocPlan = planTocEntryEdit(paragraphBytes, xml, model, leaves, startOffset, endOffset, newText, inlineContext, authoredTocEntry);
|
|
164397
164552
|
if (tocPlan)
|
|
164398
164553
|
return tocPlan;
|
|
@@ -164445,7 +164600,13 @@ function planDirectInlineEdits(paragraphBytes, edits, inheritedNamespaceBindings
|
|
|
164445
164600
|
return { ok: false, reason: "invalid-range" };
|
|
164446
164601
|
}
|
|
164447
164602
|
}
|
|
164448
|
-
const
|
|
164603
|
+
const batchModel = parseParagraphInlineMap(TD22.decode(paragraphBytes), inheritedNamespaceBindings);
|
|
164604
|
+
for (const edit of ordered) {
|
|
164605
|
+
const blocked = validateSelectedSdtProtection(batchModel.pieces, edit.startOffset, edit.endOffset);
|
|
164606
|
+
if (blocked)
|
|
164607
|
+
return { ok: false, reason: blocked };
|
|
164608
|
+
}
|
|
164609
|
+
const batchLeaves = batchModel.leaves();
|
|
164449
164610
|
if (batchLeaves.some((piece) => piece.kind === "noteReference" && !piece.deleted && ordered.some((edit) => edit.startOffset < piece.visibleEnd && edit.endOffset > piece.visibleStart))) {
|
|
164450
164611
|
return { ok: false, reason: "unsupported-context" };
|
|
164451
164612
|
}
|
|
@@ -165022,6 +165183,27 @@ function hasNonWordMarkerAtCollapsedMoveBoundary(pieces, at, coordinateSpace = "
|
|
|
165022
165183
|
function firstNonFieldRangeStartMarker(markers) {
|
|
165023
165184
|
return markers.find((piece) => piece.role === "range-start" && !isFieldMarker(piece.markerKind)) ?? null;
|
|
165024
165185
|
}
|
|
165186
|
+
function validateSelectedSdtProtection(pieces, start, end) {
|
|
165187
|
+
if (start === end)
|
|
165188
|
+
return null;
|
|
165189
|
+
for (const piece of pieces) {
|
|
165190
|
+
if (piece.kind !== "container" && piece.kind !== "tracked")
|
|
165191
|
+
continue;
|
|
165192
|
+
if (piece.kind === "container" && piece.containerKind === "sdt" && rangeCrossesContainer(piece, start, end)) {
|
|
165193
|
+
const policy = classifySdtMutationPolicyInternal(piece, true);
|
|
165194
|
+
if (!policy.ok)
|
|
165195
|
+
return policy.reason;
|
|
165196
|
+
const contentOnly = containerContainsRange(piece, start, end);
|
|
165197
|
+
const wholeWrapper = start <= piece.visibleStart && piece.visibleEnd <= end;
|
|
165198
|
+
if (contentOnly && !policy.contentEditable || !contentOnly && !policy.wrapperDeletable || !contentOnly && !wholeWrapper && !policy.contentEditable)
|
|
165199
|
+
return "text-range-in-sdt";
|
|
165200
|
+
}
|
|
165201
|
+
const blocked = validateSelectedSdtProtection(piece.children, start, end);
|
|
165202
|
+
if (blocked)
|
|
165203
|
+
return blocked;
|
|
165204
|
+
}
|
|
165205
|
+
return null;
|
|
165206
|
+
}
|
|
165025
165207
|
function resolveEditScope(pieces, start, end, collapsedInlineAffinity, collapsedOutsideContentControl = false) {
|
|
165026
165208
|
let current = pieces;
|
|
165027
165209
|
let descended = false;
|
|
@@ -165076,11 +165258,11 @@ function planCrossBoundarySdts(pieces, start, end) {
|
|
|
165076
165258
|
const policy = classifySdtMutationPolicy(piece);
|
|
165077
165259
|
if (!policy.ok)
|
|
165078
165260
|
return policy;
|
|
165261
|
+
if (!policy.wrapperDeletable)
|
|
165262
|
+
return { ok: false, reason: "text-range-in-sdt" };
|
|
165079
165263
|
requiresCollaborationSessionSync = true;
|
|
165080
165264
|
const wholeWrapper = start <= piece.visibleStart && piece.visibleEnd <= end;
|
|
165081
165265
|
if (wholeWrapper) {
|
|
165082
|
-
if (!policy.wrapperDeletable)
|
|
165083
|
-
return { ok: false, reason: "text-range-in-sdt" };
|
|
165084
165266
|
const blocked = findBlockingSdtChild(piece.children);
|
|
165085
165267
|
if (blocked)
|
|
165086
165268
|
return { ok: false, reason: blocked };
|
|
@@ -192934,7 +193116,7 @@ function tryRangeReplacementAcrossTokens(input, allTokens, touched) {
|
|
|
192934
193116
|
if (!firstSelected)
|
|
192935
193117
|
return null;
|
|
192936
193118
|
const touchedInsertions = touched.filter((entry) => entry.token.kind === "ins");
|
|
192937
|
-
if (touchedInsertions.some(({ token }) => token.innerRuns && token.innerRuns.length > 1 || token.nestedDeletions && token.nestedDeletions.length > 0)) {
|
|
193119
|
+
if (touchedInsertions.some(({ token }) => token.innerRuns && token.innerRuns.length > 1 && (token !== firstSelected.token || token.commentedBoundary != null) || token.nestedDeletions && token.nestedDeletions.length > 0)) {
|
|
192938
193120
|
return null;
|
|
192939
193121
|
}
|
|
192940
193122
|
const result = input.changeMode === "tracked" ? authorTrackedPureDelete(input, allTokens, touched) : authorDirectPureDelete(input, allTokens, touched);
|
|
@@ -193038,7 +193220,7 @@ function authorTrackedPureDelete(input, allTokens, touched, touchedBreaks = [])
|
|
|
193038
193220
|
continue;
|
|
193039
193221
|
}
|
|
193040
193222
|
const head2 = token.text.slice(0, localStart2);
|
|
193041
|
-
const
|
|
193223
|
+
const removed = token.text.slice(localStart2, localEnd2);
|
|
193042
193224
|
const tail2 = token.text.slice(localEnd2);
|
|
193043
193225
|
const headXml = head2.length > 0 ? renderPlainRun(head2, token.runOpen, token.runClose, token.rPr) : "";
|
|
193044
193226
|
const delXml = buildDelWrapperXml({
|
|
@@ -193047,7 +193229,7 @@ function authorTrackedPureDelete(input, allTokens, touched, touchedBreaks = [])
|
|
|
193047
193229
|
author: currentAuthor,
|
|
193048
193230
|
date: input.txTimestamp,
|
|
193049
193231
|
rsidDel: input.rsid,
|
|
193050
|
-
inner: { runOpen: token.runOpen, runClose: token.runClose, rPr: token.rPr, text:
|
|
193232
|
+
inner: { runOpen: token.runOpen, runClose: token.runClose, rPr: token.rPr, text: removed }
|
|
193051
193233
|
});
|
|
193052
193234
|
const insertXml = !replacementInserted && input.newText.length > 0 ? buildInsWrapperXml({
|
|
193053
193235
|
nsPrefix,
|
|
@@ -193080,7 +193262,6 @@ function authorTrackedPureDelete(input, allTokens, touched, touchedBreaks = [])
|
|
|
193080
193262
|
continue;
|
|
193081
193263
|
}
|
|
193082
193264
|
const head = token.inner.text.slice(0, localStart);
|
|
193083
|
-
const removed = token.inner.text.slice(localStart, localEnd);
|
|
193084
193265
|
const tail = token.inner.text.slice(localEnd);
|
|
193085
193266
|
const classification = token._classification;
|
|
193086
193267
|
removedAnything = true;
|
|
@@ -193109,8 +193290,13 @@ function authorTrackedPureDelete(input, allTokens, touched, touchedBreaks = [])
|
|
|
193109
193290
|
updatedRsids.push(rsid);
|
|
193110
193291
|
continue;
|
|
193111
193292
|
}
|
|
193112
|
-
const
|
|
193113
|
-
const
|
|
193293
|
+
const runs = token.innerRuns ?? [token.inner];
|
|
193294
|
+
const headRuns = sliceWrappedRuns(runs, 0, localStart);
|
|
193295
|
+
const removedRuns = sliceWrappedRuns(runs, localStart, localEnd);
|
|
193296
|
+
const tailRuns = sliceWrappedRuns(runs, localEnd, token.inner.text.length);
|
|
193297
|
+
const nestedHead = buildInsInnerXmlFromRuns(headRuns);
|
|
193298
|
+
const nestedTail = buildInsInnerXmlFromRuns(tailRuns);
|
|
193299
|
+
const insertMeta = runMetaAtInsertionPoint(token, localStart, true);
|
|
193114
193300
|
const childIns = !replacementInserted && input.newText.length > 0 && input.rangeStart >= token.visibleStart && input.rangeStart < token.visibleEnd && input.rangeEnd > token.visibleEnd ? buildInsWrapperXml({
|
|
193115
193301
|
namespaceReferenceOpenTag: token.openTag,
|
|
193116
193302
|
nsPrefix: token.nsPrefix,
|
|
@@ -193119,9 +193305,9 @@ function authorTrackedPureDelete(input, allTokens, touched, touchedBreaks = [])
|
|
|
193119
193305
|
date: input.txTimestamp,
|
|
193120
193306
|
rsidR: input.insRsid,
|
|
193121
193307
|
inner: {
|
|
193122
|
-
runOpen:
|
|
193123
|
-
runClose:
|
|
193124
|
-
rPr: token
|
|
193308
|
+
runOpen: insertMeta.runOpen,
|
|
193309
|
+
runClose: insertMeta.runClose,
|
|
193310
|
+
rPr: rPrAtInsertionPoint(token, localStart, true),
|
|
193125
193311
|
text: input.newText
|
|
193126
193312
|
}
|
|
193127
193313
|
}) : "";
|
|
@@ -193132,10 +193318,8 @@ function authorTrackedPureDelete(input, allTokens, touched, touchedBreaks = [])
|
|
|
193132
193318
|
author: currentAuthor,
|
|
193133
193319
|
date: input.txTimestamp,
|
|
193134
193320
|
rsidDel: input.rsid,
|
|
193135
|
-
inner:
|
|
193136
|
-
|
|
193137
|
-
innerXml: renderDelRun(removed, token.inner.runOpen, token.inner.runClose, token.inner.rPr) + token.commentedBoundary.endXml + token.commentedBoundary.referenceRunXml
|
|
193138
|
-
} : {}
|
|
193321
|
+
inner: removedRuns[0],
|
|
193322
|
+
innerXml: buildDelInnerXmlFromRuns(removedRuns) + (token.commentedBoundary?.endXml ?? "") + (token.commentedBoundary?.referenceRunXml ?? "")
|
|
193139
193323
|
});
|
|
193140
193324
|
if (token.commentedBoundary) {
|
|
193141
193325
|
if (!childIns || tail.length > 0)
|
|
@@ -193156,7 +193340,8 @@ function authorTrackedPureDelete(input, allTokens, touched, touchedBreaks = [])
|
|
|
193156
193340
|
author: token.author,
|
|
193157
193341
|
date: token.date,
|
|
193158
193342
|
rsidR: token.rsidR,
|
|
193159
|
-
inner:
|
|
193343
|
+
inner: headRuns[0],
|
|
193344
|
+
innerXml: nestedHead
|
|
193160
193345
|
}) : "";
|
|
193161
193346
|
const tailIns = buildInsWrapperXml({
|
|
193162
193347
|
openTag: token.openTag,
|
|
@@ -193523,6 +193708,20 @@ function foldInsideOwnInsertion(input, allTokens, parent) {
|
|
|
193523
193708
|
const rebuilt = rebuildParagraph(allTokens, parent, newInsXml);
|
|
193524
193709
|
return rebuilt.ok ? markTextInsertionRefined(markExistingRevisionUpdated(rebuilt, input, parent), input, parent, false) : rebuilt;
|
|
193525
193710
|
}
|
|
193711
|
+
function sliceWrappedRuns(runs, start, end) {
|
|
193712
|
+
const result = [];
|
|
193713
|
+
let offset = 0;
|
|
193714
|
+
for (const run of runs) {
|
|
193715
|
+
const runEnd = offset + run.text.length;
|
|
193716
|
+
if (start < runEnd && end > offset) {
|
|
193717
|
+
result.push({ ...run, text: run.text.slice(Math.max(0, start - offset), Math.min(run.text.length, end - offset)) });
|
|
193718
|
+
}
|
|
193719
|
+
offset = runEnd;
|
|
193720
|
+
if (offset >= end)
|
|
193721
|
+
break;
|
|
193722
|
+
}
|
|
193723
|
+
return result;
|
|
193724
|
+
}
|
|
193526
193725
|
function flattenWrappedRuns(runs) {
|
|
193527
193726
|
const out = [];
|
|
193528
193727
|
for (const run of runs) {
|
|
@@ -193743,8 +193942,10 @@ function splitInsertionAroundChildChange(input, allTokens, parent) {
|
|
|
193743
193942
|
detail: "overlap compiler: edit range straddles an existing nested tracked deletion."
|
|
193744
193943
|
};
|
|
193745
193944
|
}
|
|
193746
|
-
const
|
|
193747
|
-
const
|
|
193945
|
+
const precedesBoundaryDeletion = input.changeMode === "tracked" && input.newText.length > 0 && input.rangeStart === input.rangeEnd && (input.coordinateSpace ?? "visible") === "visible" && input.collapsedInlineAffinity === "upstream";
|
|
193946
|
+
const belongsToHead = (n) => n.localOffset < localStart || n.localOffset === localStart && !precedesBoundaryDeletion;
|
|
193947
|
+
const headOwnedNested = nestedDeletions.filter(belongsToHead);
|
|
193948
|
+
const tailOwnedNested = nestedDeletions.filter((n) => !belongsToHead(n));
|
|
193748
193949
|
const flat = flattenWrappedRuns(parent.innerRuns ?? [parent.inner]);
|
|
193749
193950
|
const headRuns = coalesceWrappedRuns(flat.slice(0, localStart));
|
|
193750
193951
|
const removedRuns = coalesceWrappedRuns(flat.slice(localStart, localEnd));
|
|
@@ -193874,7 +194075,7 @@ function splitInsertionAroundChildChange(input, allTokens, parent) {
|
|
|
193874
194075
|
ok: true,
|
|
193875
194076
|
xml,
|
|
193876
194077
|
emittedRsids,
|
|
193877
|
-
...removedText.length > 0 || tailParentWId !== parent.wId || liftComment ? { requiresCollaborationSessionSync: true } : {}
|
|
194078
|
+
...removedText.length > 0 || tailParentWId !== parent.wId || liftComment || precedesBoundaryDeletion && tailOwnedNested.some((n) => n.localOffset === localStart) ? { requiresCollaborationSessionSync: true } : {}
|
|
193878
194079
|
};
|
|
193879
194080
|
}
|
|
193880
194081
|
function insertAtForeignDeletion(input, allTokens, parent, sameUser, side = "after") {
|
|
@@ -198958,6 +199159,15 @@ function rewriteTrackedPartialSdtSelection(paragraphXml, startOffset, endOffset,
|
|
|
198958
199159
|
const sdts = [...intersectingSdts].sort((left, right) => left.visibleStart - right.visibleStart);
|
|
198959
199160
|
if (sdts.some((sdt, index) => index > 0 && sdt.visibleStart < sdts[index - 1].visibleEnd))
|
|
198960
199161
|
return null;
|
|
199162
|
+
for (const sdt of sdts) {
|
|
199163
|
+
if (sdt.visibleStart <= startOffset && endOffset <= sdt.visibleEnd)
|
|
199164
|
+
continue;
|
|
199165
|
+
const policy = classifySdtMutationPolicy(sdt);
|
|
199166
|
+
if (!policy.ok)
|
|
199167
|
+
return policy;
|
|
199168
|
+
if (!policy.wrapperDeletable)
|
|
199169
|
+
return { ok: false, reason: "text-range-in-sdt" };
|
|
199170
|
+
}
|
|
198961
199171
|
const segments = [];
|
|
198962
199172
|
let cursor = startOffset;
|
|
198963
199173
|
for (const sdt of sdts) {
|
|
@@ -216135,7 +216345,10 @@ function runParagraphRangeCollapseCommit(input) {
|
|
|
216135
216345
|
if (startOffsetMap.charToByte(op.on.startOffset) !== op.on.startByte || endOffsetMap.charToByte(op.on.endOffset) !== op.on.endByte) {
|
|
216136
216346
|
return rejected8(input.txId, "base-revision-drift");
|
|
216137
216347
|
}
|
|
216138
|
-
const structuralFailure = validateRangeCollapseStructure(bytes, index.entries, start, end, changeMode, op.startObjectBoundary, op.endObjectBoundary, {
|
|
216348
|
+
const structuralFailure = validateRangeCollapseStructure(bytes, index.entries, start, end, changeMode, op.startObjectBoundary, op.endObjectBoundary, {
|
|
216349
|
+
allowSectionBoundary: changeMode === "direct" && op.replacementText === undefined && !deleteFullBlocks,
|
|
216350
|
+
inlineRange: { startOffset: op.on.startOffset, endOffset: op.on.endOffset, deleteFullBlocks: op.deleteFinalParagraphMark === true }
|
|
216351
|
+
});
|
|
216139
216352
|
if (structuralFailure)
|
|
216140
216353
|
return rejected8(input.txId, structuralFailure);
|
|
216141
216354
|
let replacementBlockId;
|
|
@@ -216192,7 +216405,7 @@ function runParagraphRangeCollapseCommit(input) {
|
|
|
216192
216405
|
op = expanded.op;
|
|
216193
216406
|
start = expanded.start;
|
|
216194
216407
|
end = expanded.end;
|
|
216195
|
-
const expandedStructure = validateRangeCollapseStructure(bytes, index.entries, start, end, changeMode, undefined, undefined, { allowSectionBoundary: true });
|
|
216408
|
+
const expandedStructure = validateRangeCollapseStructure(bytes, index.entries, start, end, changeMode, undefined, undefined, { allowSectionBoundary: true, inlineRange: { startOffset: op.on.startOffset, endOffset: op.on.endOffset } });
|
|
216196
216409
|
if (expandedStructure)
|
|
216197
216410
|
return rejected8(input.txId, expandedStructure);
|
|
216198
216411
|
rangeIntegrity = validateParagraphRangeIntegrity({
|
|
@@ -217942,6 +218155,11 @@ function validateRangeCollapseStructure(bytes, entries, start, end, changeMode,
|
|
|
217942
218155
|
if (!options.structuralMap && directBodyRangeIsStructurallyPlain(bytes, entries, start, end, changeMode)) {
|
|
217943
218156
|
return null;
|
|
217944
218157
|
}
|
|
218158
|
+
if (options.inlineRange) {
|
|
218159
|
+
const failure2 = validateRangeInlineSdtProtection(bytes, entries, start, end, options.inlineRange);
|
|
218160
|
+
if (failure2)
|
|
218161
|
+
return failure2;
|
|
218162
|
+
}
|
|
217945
218163
|
if (!options.structuralMap)
|
|
217946
218164
|
recordSDTxPerf("rangeCollapseStructuralFullScans", 1);
|
|
217947
218165
|
const map3 = options.structuralMap ?? buildStructuralBoundaryMap(bytes);
|
|
@@ -218013,6 +218231,46 @@ function validateRangeCollapseStructure(bytes, entries, start, end, changeMode,
|
|
|
218013
218231
|
}
|
|
218014
218232
|
return null;
|
|
218015
218233
|
}
|
|
218234
|
+
function validateRangeInlineSdtProtection(bytes, entries, start, end, range) {
|
|
218235
|
+
for (const entry of entries) {
|
|
218236
|
+
if (entry.ordinal < start.ordinal || entry.ordinal > end.ordinal)
|
|
218237
|
+
continue;
|
|
218238
|
+
const xml = decodeByteRange(bytes, entry.byteStart, entry.byteEnd);
|
|
218239
|
+
if (!/<\s*(?:[\w.-]+:)?sdt\b/.test(xml))
|
|
218240
|
+
continue;
|
|
218241
|
+
const namespaces = namespaceBindingsAtPosition(bytes, entry.byteStart, matchParagraphOpenTag(xml) ?? "");
|
|
218242
|
+
const selectedStart = entry.blockId === start.blockId ? range.startOffset : 0;
|
|
218243
|
+
const selectedEnd = entry.blockId === end.blockId ? range.endOffset : entry.textLength;
|
|
218244
|
+
const wholeParagraph = range.deleteFullBlocks === true || entry.ordinal > start.ordinal && entry.ordinal < end.ordinal;
|
|
218245
|
+
const visit = (pieces) => {
|
|
218246
|
+
for (const piece of pieces) {
|
|
218247
|
+
if (piece.kind !== "container" && piece.kind !== "tracked")
|
|
218248
|
+
continue;
|
|
218249
|
+
if (piece.kind === "container" && piece.containerKind === "sdt") {
|
|
218250
|
+
const touched = wholeParagraph || (piece.visibleStart === piece.visibleEnd ? (entry.blockId !== start.blockId || selectedStart < piece.visibleStart) && piece.visibleEnd <= selectedEnd : selectedStart < piece.visibleEnd && piece.visibleStart < selectedEnd);
|
|
218251
|
+
if (!touched)
|
|
218252
|
+
continue;
|
|
218253
|
+
const policy = classifySdtMutationPolicy(piece);
|
|
218254
|
+
if (!policy.ok)
|
|
218255
|
+
return policy.reason;
|
|
218256
|
+
if (!policy.wrapperDeletable)
|
|
218257
|
+
return "text-range-in-sdt";
|
|
218258
|
+
const wholeWrapper = wholeParagraph || selectedStart <= piece.visibleStart && piece.visibleEnd <= selectedEnd;
|
|
218259
|
+
if (!wholeWrapper && !policy.contentEditable)
|
|
218260
|
+
return "text-range-in-sdt";
|
|
218261
|
+
}
|
|
218262
|
+
const failure3 = visit(piece.children);
|
|
218263
|
+
if (failure3)
|
|
218264
|
+
return failure3;
|
|
218265
|
+
}
|
|
218266
|
+
return null;
|
|
218267
|
+
};
|
|
218268
|
+
const failure2 = visit(parseParagraphInlineMap(xml, namespaces).pieces);
|
|
218269
|
+
if (failure2)
|
|
218270
|
+
return failure2;
|
|
218271
|
+
}
|
|
218272
|
+
return null;
|
|
218273
|
+
}
|
|
218016
218274
|
function directBodyRangeIsStructurallyPlain(bytes, entries, start, end, changeMode) {
|
|
218017
218275
|
if (!Number.isSafeInteger(start.ordinal) || !Number.isSafeInteger(end.ordinal) || start.ordinal < 0 || end.ordinal <= start.ordinal || end.ordinal >= entries.length || entries[start.ordinal]?.blockId !== start.blockId || entries[start.ordinal]?.byteStart !== start.byteStart || entries[start.ordinal]?.byteEnd !== start.byteEnd || entries[end.ordinal]?.blockId !== end.blockId || entries[end.ordinal]?.byteStart !== end.byteStart || entries[end.ordinal]?.byteEnd !== end.byteEnd || !Number.isSafeInteger(start.byteStart) || !Number.isSafeInteger(end.byteEnd) || start.byteStart < 0 || end.byteEnd <= start.byteStart || end.byteEnd > bytes.byteLength)
|
|
218018
218276
|
return false;
|
|
@@ -224330,7 +224588,7 @@ function runBodyStep(input, storyId, noteId, step2, changeMode, options, pushHis
|
|
|
224330
224588
|
if ((step2.kind === "edit" || step2.kind === "formatEdit") && step2.targetRunXml !== undefined) {
|
|
224331
224589
|
const before = liveCompareBodyRunXml(state, storyId, step2.blockId);
|
|
224332
224590
|
const partBytes = state.packageBytes.get(storyPartUriFromStoryId2(storyId));
|
|
224333
|
-
if (before !== undefined && partBytes && inspectInlineControlRemoval(before, step2.targetRunXml, textboxNamespaceBindingsFromPartBytes(partBytes))) {
|
|
224591
|
+
if (before !== undefined && partBytes && (inspectInlineControlRemoval(before, step2.targetRunXml, textboxNamespaceBindingsFromPartBytes(partBytes)) || inspectInlineControlReplay(before, step2.targetRunXml, textboxNamespaceBindingsFromPartBytes(partBytes)))) {
|
|
224334
224592
|
return runInlineControlRemovalCommit(input, storyId, step2, changeMode, options, pushHistory);
|
|
224335
224593
|
}
|
|
224336
224594
|
}
|
|
@@ -225091,6 +225349,134 @@ function retainedNoteMarkerRuns(oldRuns, targetRuns, storyId) {
|
|
|
225091
225349
|
targetRuns: targetMarker.remainingRunXml
|
|
225092
225350
|
};
|
|
225093
225351
|
}
|
|
225352
|
+
function equivalentSimpleRunContent(before, after) {
|
|
225353
|
+
const previous = parseSimpleRunTokens(before), next = parseSimpleRunTokens(after);
|
|
225354
|
+
if (!previous || !next)
|
|
225355
|
+
return false;
|
|
225356
|
+
const spans = (tokens) => tokens.flatMap((token) => Array.from(token.text, (char) => `${canonicalizeXmlForSignature(token.openTag)}:${char}`));
|
|
225357
|
+
const old = spans(previous), target = spans(next);
|
|
225358
|
+
return old.length === target.length && old.every((value, index) => value === target[index]);
|
|
225359
|
+
}
|
|
225360
|
+
function inlineComparePieces(proof) {
|
|
225361
|
+
const pieces = [];
|
|
225362
|
+
const gap = (before, roots, rootOffset) => {
|
|
225363
|
+
const tokens = parseSimpleRunTokens(before);
|
|
225364
|
+
if (!tokens)
|
|
225365
|
+
return false;
|
|
225366
|
+
const oldText = tokens.map((token) => token.text).join("");
|
|
225367
|
+
const targets = roots.map((xml, index) => {
|
|
225368
|
+
const control2 = proof.inserted.find((item) => item.index === index + rootOffset);
|
|
225369
|
+
const text = projectCompareReplayCurrentText(control2?.contentXml ?? xml);
|
|
225370
|
+
return text === null ? null : { xml, control: control2, text };
|
|
225371
|
+
});
|
|
225372
|
+
if (targets.some((item) => item === null))
|
|
225373
|
+
return false;
|
|
225374
|
+
const nextText = targets.map((item) => item.text).join("");
|
|
225375
|
+
const operations = getWordChanges(oldText, nextText);
|
|
225376
|
+
const mapOffset = (offset) => {
|
|
225377
|
+
let oldCursor3 = 0, nextCursor3 = 0;
|
|
225378
|
+
for (const op of operations) {
|
|
225379
|
+
const start = op.type === "insert" ? op.insertAt : op.oldFrom;
|
|
225380
|
+
const equalEnd = nextCursor3 + start - oldCursor3;
|
|
225381
|
+
if (offset < equalEnd)
|
|
225382
|
+
return oldCursor3 + offset - nextCursor3;
|
|
225383
|
+
const oldEnd = op.type === "insert" ? start : op.oldTo;
|
|
225384
|
+
const nextEnd = equalEnd + (op.type === "delete" ? 0 : op.newText.length);
|
|
225385
|
+
if (offset < nextEnd)
|
|
225386
|
+
return start;
|
|
225387
|
+
oldCursor3 = oldEnd;
|
|
225388
|
+
nextCursor3 = nextEnd;
|
|
225389
|
+
}
|
|
225390
|
+
return oldCursor3 + offset - nextCursor3;
|
|
225391
|
+
};
|
|
225392
|
+
let oldCursor2 = 0, nextCursor2 = 0;
|
|
225393
|
+
let ordinaryTarget = "";
|
|
225394
|
+
const appendOrdinary = (end) => {
|
|
225395
|
+
pieces.push({
|
|
225396
|
+
beforeXml: renderCompareRunRange(tokens, oldCursor2, end, "passthrough"),
|
|
225397
|
+
afterXml: ordinaryTarget,
|
|
225398
|
+
ordinary: true
|
|
225399
|
+
});
|
|
225400
|
+
ordinaryTarget = "";
|
|
225401
|
+
oldCursor2 = end;
|
|
225402
|
+
};
|
|
225403
|
+
for (const target of targets) {
|
|
225404
|
+
if (!target)
|
|
225405
|
+
return false;
|
|
225406
|
+
if (!target.control) {
|
|
225407
|
+
ordinaryTarget += target.xml;
|
|
225408
|
+
nextCursor2 += target.text.length;
|
|
225409
|
+
continue;
|
|
225410
|
+
}
|
|
225411
|
+
const start = mapOffset(nextCursor2), end = mapOffset(nextCursor2 + target.text.length);
|
|
225412
|
+
if (start < oldCursor2 || end < start || end > oldText.length)
|
|
225413
|
+
return false;
|
|
225414
|
+
appendOrdinary(start);
|
|
225415
|
+
const selected = renderCompareRunRange(tokens, start, end, "passthrough");
|
|
225416
|
+
if (equivalentSimpleRunContent(selected, target.control.contentXml)) {
|
|
225417
|
+
pieces.push({ beforeXml: target.control.contentXml, afterXml: target.xml });
|
|
225418
|
+
} else {
|
|
225419
|
+
pieces.push({ beforeXml: selected, afterXml: "", ordinary: true });
|
|
225420
|
+
pieces.push({ beforeXml: "", afterXml: target.xml });
|
|
225421
|
+
}
|
|
225422
|
+
oldCursor2 = end;
|
|
225423
|
+
nextCursor2 += target.text.length;
|
|
225424
|
+
}
|
|
225425
|
+
appendOrdinary(oldText.length);
|
|
225426
|
+
return true;
|
|
225427
|
+
};
|
|
225428
|
+
let oldCursor = 0, nextCursor = 0;
|
|
225429
|
+
for (const anchor of proof.anchors) {
|
|
225430
|
+
if (!gap(proof.beforeRoots.slice(oldCursor, anchor.beforeIndex).join(""), proof.afterRoots.slice(nextCursor, anchor.afterIndex), nextCursor))
|
|
225431
|
+
return null;
|
|
225432
|
+
if (anchor.changed) {
|
|
225433
|
+
pieces.push({ beforeXml: anchor.before.xml, afterXml: anchor.after.xml });
|
|
225434
|
+
} else
|
|
225435
|
+
pieces.push({ beforeXml: anchor.before.xml, afterXml: anchor.before.xml });
|
|
225436
|
+
oldCursor = anchor.beforeIndex + 1;
|
|
225437
|
+
nextCursor = anchor.afterIndex + 1;
|
|
225438
|
+
}
|
|
225439
|
+
if (!gap(proof.beforeRoots.slice(oldCursor).join(""), proof.afterRoots.slice(nextCursor), nextCursor))
|
|
225440
|
+
return null;
|
|
225441
|
+
return pieces;
|
|
225442
|
+
}
|
|
225443
|
+
function inspectInlineControlCompareBodyReplay(bytes, startByte, endByte, targetRunXml) {
|
|
225444
|
+
const xml = TD60.decode(bytes);
|
|
225445
|
+
const start = TD60.decode(bytes.subarray(0, startByte)).length;
|
|
225446
|
+
const end = start + TD60.decode(bytes.subarray(startByte, endByte)).length;
|
|
225447
|
+
const parsed = collectXmlElementRanges(xml);
|
|
225448
|
+
if (parsed.errors.length)
|
|
225449
|
+
return null;
|
|
225450
|
+
const body = parsed.ranges.find((range) => range.tag.namespaceUri === NS_W && range.tag.localName === "body");
|
|
225451
|
+
if (!body || !directXmlChildRanges(parsed.ranges, body).some((range) => range.start === start && range.end === end && range.tag.namespaceUri === NS_W && range.tag.localName === "p"))
|
|
225452
|
+
return null;
|
|
225453
|
+
const proof = inspectInlineControlReplay(extractCompareParagraphRunXml(xml.slice(start, end)), targetRunXml, textboxNamespaceBindingsFromPartBytes(bytes));
|
|
225454
|
+
if (!proof)
|
|
225455
|
+
return null;
|
|
225456
|
+
const counts = new Map;
|
|
225457
|
+
for (const range of parsed.ranges) {
|
|
225458
|
+
if (range.tag.namespaceUri !== NS_W || range.tag.localName !== "sdtPr")
|
|
225459
|
+
continue;
|
|
225460
|
+
for (const id of directXmlChildRanges(parsed.ranges, range).filter((child) => child.tag.namespaceUri === NS_W && child.tag.localName === "id")) {
|
|
225461
|
+
const raw = readXmlAttribute(id.tag, NS_W, "val")?.value;
|
|
225462
|
+
if (raw !== undefined && /^-?\d+$/.test(raw) && Number.isSafeInteger(Number(raw))) {
|
|
225463
|
+
const key2 = String(Number(raw));
|
|
225464
|
+
counts.set(key2, (counts.get(key2) ?? 0) + 1);
|
|
225465
|
+
}
|
|
225466
|
+
}
|
|
225467
|
+
}
|
|
225468
|
+
if (proof.anchors.some((anchor) => counts.get(anchor.before.id) !== 1) || proof.inserted.some((control2) => counts.has(control2.id)))
|
|
225469
|
+
return null;
|
|
225470
|
+
return proof;
|
|
225471
|
+
}
|
|
225472
|
+
function directlyOwnedBodyParagraph(bytes, startByte, endByte) {
|
|
225473
|
+
const xml = TD60.decode(bytes);
|
|
225474
|
+
const start = TD60.decode(bytes.subarray(0, startByte)).length;
|
|
225475
|
+
const end = start + TD60.decode(bytes.subarray(startByte, endByte)).length;
|
|
225476
|
+
const parsed = collectXmlElementRanges(xml);
|
|
225477
|
+
const body = parsed.ranges.find((range) => range.tag.namespaceUri === NS_W && range.tag.localName === "body");
|
|
225478
|
+
return !parsed.errors.length && !!body && directXmlChildRanges(parsed.ranges, body).some((range) => range.start === start && range.end === end && range.tag.namespaceUri === NS_W && range.tag.localName === "p");
|
|
225479
|
+
}
|
|
225094
225480
|
function runInlineControlRemovalCommit(input, storyId, step2, changeMode, options, pushHistory) {
|
|
225095
225481
|
const { state, txId } = input;
|
|
225096
225482
|
const partUri = storyPartUriFromStoryId2(storyId);
|
|
@@ -225106,7 +225492,10 @@ function runInlineControlRemovalCommit(input, storyId, step2, changeMode, option
|
|
|
225106
225492
|
const before = extractCompareParagraphRunXml(paragraph);
|
|
225107
225493
|
const namespaces = textboxNamespaceBindingsFromPartBytes(bytes);
|
|
225108
225494
|
const proof = inspectInlineControlRemoval(before, step2.targetRunXml, namespaces);
|
|
225109
|
-
|
|
225495
|
+
const replay = inspectInlineControlCompareBodyReplay(bytes, entry.byteStart, entry.byteEnd, step2.targetRunXml);
|
|
225496
|
+
if (replay && !/^[0-9A-Fa-f]{8}$/.test(step2.blockId))
|
|
225497
|
+
return rejected14(txId, "unsupported-context");
|
|
225498
|
+
if (!proof && !replay || !directlyOwnedBodyParagraph(bytes, entry.byteStart, entry.byteEnd) || /<(?:[\w.-]+:)?\w+Change\b/.test(properties))
|
|
225110
225499
|
return rejected14(txId, "unsupported-context");
|
|
225111
225500
|
const targetProperties = step2.targetParagraphPropertiesXml === undefined ? properties : rewriteCanonicalWordprocessingPrefix(step2.targetParagraphPropertiesXml, wrapper.wordprocessingPrefix);
|
|
225112
225501
|
if (!equivalentParagraphProperties(properties, targetProperties))
|
|
@@ -225119,7 +225508,9 @@ function runInlineControlRemovalCommit(input, storyId, step2, changeMode, option
|
|
|
225119
225508
|
return rejected14(txId, "no-author-configured");
|
|
225120
225509
|
const namespaceBindings = new Map(Object.entries(namespaces));
|
|
225121
225510
|
namespaceBindings.set(wrapper.wordprocessingPrefix, W_NS4);
|
|
225122
|
-
const pieces = [];
|
|
225511
|
+
const pieces = replay ? inlineComparePieces(replay) ?? [] : [];
|
|
225512
|
+
if (replay && !pieces.length)
|
|
225513
|
+
return rejected14(txId, "unsupported-context");
|
|
225123
225514
|
const appendGap = (old, next) => {
|
|
225124
225515
|
let head = 0;
|
|
225125
225516
|
while (head < old.length && head < next.length && old[head] === next[head])
|
|
@@ -225136,7 +225527,7 @@ function runInlineControlRemovalCommit(input, storyId, step2, changeMode, option
|
|
|
225136
225527
|
};
|
|
225137
225528
|
let oldCursor = 0;
|
|
225138
225529
|
let nextCursor = 0;
|
|
225139
|
-
for (let index = 0;index < proof.afterRoots.length; index++) {
|
|
225530
|
+
for (let index = 0;proof && !replay && index < proof.afterRoots.length; index++) {
|
|
225140
225531
|
const root = proof.afterRoots[index];
|
|
225141
225532
|
if (!/<(?:[\w.-]+:)?sdt\b/.test(root))
|
|
225142
225533
|
continue;
|
|
@@ -225148,12 +225539,33 @@ function runInlineControlRemovalCommit(input, storyId, step2, changeMode, option
|
|
|
225148
225539
|
oldCursor = oldIndex + 1;
|
|
225149
225540
|
nextCursor = index + 1;
|
|
225150
225541
|
}
|
|
225151
|
-
|
|
225542
|
+
if (proof && !replay)
|
|
225543
|
+
appendGap(proof.beforeRoots.slice(oldCursor), proof.afterRoots.slice(nextCursor));
|
|
225152
225544
|
const stamp = { revisionId: 0, author: serializedSessionAuthor(sourceAuthor), date: input.txTimestamp };
|
|
225153
225545
|
const prepare = (revisionIds) => {
|
|
225154
225546
|
let xml = "";
|
|
225155
225547
|
const wordIds = [];
|
|
225156
225548
|
for (const piece of pieces) {
|
|
225549
|
+
if (piece.beforeXml === piece.afterXml) {
|
|
225550
|
+
xml += piece.beforeXml;
|
|
225551
|
+
continue;
|
|
225552
|
+
}
|
|
225553
|
+
if (piece.ordinary && !/<(?:[\w.-]+:)?sdt\b/.test(piece.beforeXml + piece.afterXml)) {
|
|
225554
|
+
const result2 = renderWordLevelTrackedRunSegment(piece.beforeXml, piece.afterXml, () => {
|
|
225555
|
+
const delId = revisionIds?.[wordIds.length] ?? wordIds.length;
|
|
225556
|
+
wordIds.push(String(delId));
|
|
225557
|
+
const insId = revisionIds?.[wordIds.length] ?? wordIds.length;
|
|
225558
|
+
wordIds.push(String(insId));
|
|
225559
|
+
return {
|
|
225560
|
+
del: { rsid: delId.toString(16).padStart(8, "0"), wId: delId, author: stamp.author, date: stamp.date },
|
|
225561
|
+
ins: { rsid: delId.toString(16).padStart(8, "0"), wId: insId, author: stamp.author, date: stamp.date }
|
|
225562
|
+
};
|
|
225563
|
+
}, wrapper.wordprocessingPrefix);
|
|
225564
|
+
if (result2) {
|
|
225565
|
+
xml += result2.xml;
|
|
225566
|
+
continue;
|
|
225567
|
+
}
|
|
225568
|
+
}
|
|
225157
225569
|
const result = prepareTrackedSdtXmlReplacement({
|
|
225158
225570
|
beforeXml: piece.beforeXml,
|
|
225159
225571
|
afterXml: piece.afterXml,
|
|
@@ -236511,7 +236923,7 @@ function resolveFragmentApplyTarget(state, op) {
|
|
|
236511
236923
|
const index2 = paragraphIndexForPasteStory(state, target.storyId);
|
|
236512
236924
|
if (!index2)
|
|
236513
236925
|
return { ok: false, reason: "unsupported-context" };
|
|
236514
|
-
const structuralFailure = validateRangeCollapseStructure(bytes, index2.entries, anchor.entry, anchor.entry, op.changeMode ?? "direct", undefined, undefined, { allowWholeParagraphReplacement: true });
|
|
236926
|
+
const structuralFailure = validateRangeCollapseStructure(bytes, index2.entries, anchor.entry, anchor.entry, op.changeMode ?? "direct", undefined, undefined, { allowWholeParagraphReplacement: true, inlineRange: { startOffset: 0, endOffset: anchor.entry.textLength, deleteFullBlocks: true } });
|
|
236515
236927
|
if (structuralFailure)
|
|
236516
236928
|
return { ok: false, reason: structuralFailure };
|
|
236517
236929
|
const integrityFailure = validateFragmentRangeIntegrity({
|
|
@@ -236587,7 +236999,7 @@ function resolveFragmentApplyTarget(state, op) {
|
|
|
236587
236999
|
const crossParagraph = startAnchor.ordinal !== endAnchor.ordinal;
|
|
236588
237000
|
const replacesContent = crossParagraph || target.charOffset !== explicitEnd.charOffset;
|
|
236589
237001
|
if (crossParagraph) {
|
|
236590
|
-
const structuralFailure = validateRangeCollapseStructure(residentBytes, index.entries, startAnchor.entry, endAnchor.entry, op.changeMode ?? "direct", target.collapsedObjectBoundary, explicitEnd.objectBoundary, { allowTrackedSdtContent: true });
|
|
237002
|
+
const structuralFailure = validateRangeCollapseStructure(residentBytes, index.entries, startAnchor.entry, endAnchor.entry, op.changeMode ?? "direct", target.collapsedObjectBoundary, explicitEnd.objectBoundary, { allowTrackedSdtContent: true, inlineRange: { startOffset: target.charOffset, endOffset: explicitEnd.charOffset } });
|
|
236591
237003
|
if (structuralFailure)
|
|
236592
237004
|
return { ok: false, reason: structuralFailure };
|
|
236593
237005
|
} else if (replacesContent && residentBytes) {
|
|
@@ -255970,6 +256382,7 @@ var init_sd_document_session_internal = __esm(() => {
|
|
|
255970
256382
|
init_section_property_references();
|
|
255971
256383
|
init_bibliography_style();
|
|
255972
256384
|
init_bibliography_review_resources();
|
|
256385
|
+
init_compile_compare_apply();
|
|
255973
256386
|
});
|
|
255974
256387
|
|
|
255975
256388
|
// ../../../v2/document-api-v2-adapter/dist/address/story-identity.js
|
|
@@ -437273,8 +437686,8 @@ function applyPreflightedTrackedTextDecisionsToStory(input) {
|
|
|
437273
437686
|
tx.meta.set(ACTOR_ATTRIBUTION_META_KEY, input.actorType);
|
|
437274
437687
|
scope.meta.set(STORY_META_KEY.lastEditActorType, input.actorType);
|
|
437275
437688
|
const { decision, doc: doc2, removedCommentCarrierIds, resolved, work } = input.plan;
|
|
437276
|
-
for (const {
|
|
437277
|
-
removeTrackedTextCarriers(block, span, decision === "reject" &&
|
|
437689
|
+
for (const { span, block } of work) {
|
|
437690
|
+
removeTrackedTextCarriers(block, span, decision === "reject" && span.trackedKind === "ins");
|
|
437278
437691
|
removeCommentCarriersByIds(block, removedCommentCarrierIds);
|
|
437279
437692
|
}
|
|
437280
437693
|
const sorted = [...work].sort((left, right) => {
|
|
@@ -437291,12 +437704,12 @@ function applyPreflightedTrackedTextDecisionsToStory(input) {
|
|
|
437291
437704
|
if (span.trackedKind === "ins" && decision === "reject") {
|
|
437292
437705
|
const length3 = span.endOffset - span.startOffset;
|
|
437293
437706
|
if (length3 > 0) {
|
|
437294
|
-
|
|
437295
|
-
|
|
437296
|
-
blockId: span.blockId,
|
|
437707
|
+
deleteTextAtResolvedTarget({
|
|
437708
|
+
target: resolveStoryTextMutationTarget(doc2, span.blockId),
|
|
437297
437709
|
offset: span.startOffset,
|
|
437298
437710
|
length: length3,
|
|
437299
|
-
origin: STORY_SURFACE_BACKEND_ORIGIN
|
|
437711
|
+
origin: STORY_SURFACE_BACKEND_ORIGIN,
|
|
437712
|
+
preserveZeroLengthAtStart: true
|
|
437300
437713
|
});
|
|
437301
437714
|
}
|
|
437302
437715
|
}
|
|
@@ -437664,8 +438077,19 @@ function validateCompareApplySessionSync(prepared, extension2, options) {
|
|
|
437664
438077
|
if (!extension2.storyLocal || prepared.resolvedTargets.stories.length !== 1 || String(prepared.resolvedTargets.stories[0]) !== storyId || ownership.length !== 1 || String(ownership[0]?.storyId) !== storyId || prepared.resolvedTargets.partUris.length !== 1 || String(prepared.resolvedTargets.partUris[0]) !== String(ownership[0]?.partUri)) {
|
|
437665
438078
|
return { ok: false, message: "compareApply collaboration requires one owned story part" };
|
|
437666
438079
|
}
|
|
437667
|
-
if (source.bodySteps.length === 0 || source.bodySteps.some((step3) =>
|
|
437668
|
-
|
|
438080
|
+
if (source.bodySteps.length === 0 || source.bodySteps.some((step3) => {
|
|
438081
|
+
if (step3.kind === "edit")
|
|
438082
|
+
return false;
|
|
438083
|
+
if (step3.kind !== "formatEdit" || step3.targetRunXml === undefined)
|
|
438084
|
+
return true;
|
|
438085
|
+
if (extension2.historyReplay)
|
|
438086
|
+
return false;
|
|
438087
|
+
const bytes = getSDDocumentSessionInternalPartBytes(options.session, String(ownership[0].partUri));
|
|
438088
|
+
const entry = getSDDocumentSessionInternalStoryParagraphIndex(options.session, source.storyId)?.byParaId(step3.blockId);
|
|
438089
|
+
const proof = bytes && entry && inspectInlineControlCompareBodyReplay(bytes, entry.byteStart, entry.byteEnd, step3.targetRunXml);
|
|
438090
|
+
return !proof || proof.inserted.length === 0;
|
|
438091
|
+
}) || source.storyGroups?.length || source.storyPackageOperations?.length || source.commentSteps?.length || source.packageRewrites?.length || source.relationshipBackedBodyRewrites?.length || source.headerFooterLifecycle || source.headerFooterSlotSteps?.length || source.tableTopologySteps?.length || source.tableBlockSteps?.length || source.tablePropertySteps?.length || source.sectionReplaySteps?.length || source.referenceReplaySteps?.length) {
|
|
438092
|
+
return { ok: false, message: "compareApply collaboration supports paragraph text edits and proved inline control wrapping only" };
|
|
437669
438093
|
}
|
|
437670
438094
|
const targetBlockIds2 = [...new Set(source.bodySteps.map((step3) => step3.blockId))];
|
|
437671
438095
|
if (targetBlockIds2.length !== extension2.targetBlockIds.length || targetBlockIds2.some((blockId) => !extension2.targetBlockIds.includes(blockId))) {
|
|
@@ -438977,6 +439401,7 @@ function atomOverlapsRange(atomOffset, atomLength, rangeStart, rangeEnd) {
|
|
|
438977
439401
|
var STORY_SURFACE_TRACE, TRACKED_CHANGE_DECISIONS_LEDGER_KEY = "trackedChangeDecisions", CLEARED_RUN_ATTRIBUTES;
|
|
438978
439402
|
var init_story_surface_execution_backend = __esm(() => {
|
|
438979
439403
|
init_yjs();
|
|
439404
|
+
init_sd_document_session_internal();
|
|
438980
439405
|
init_scope3();
|
|
438981
439406
|
init_content_control_groups();
|
|
438982
439407
|
init_story_surface_session_sync();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@superdoc/mcp",
|
|
3
|
-
"version": "1.4.0-next.
|
|
3
|
+
"version": "1.4.0-next.9",
|
|
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.17.0-next.
|
|
27
|
+
"@superdoc/sdk": "2.17.0-next.9",
|
|
28
28
|
"debug": "^4.4.3",
|
|
29
29
|
"zod": "^4.3.6"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"superdoc": "2.20.0-next.
|
|
33
|
-
"@superdoc/docx-engine": "0.19.0-next.
|
|
32
|
+
"superdoc": "2.20.0-next.11",
|
|
33
|
+
"@superdoc/docx-engine": "0.19.0-next.12",
|
|
34
34
|
"@superdoc/document-api": "0.1.0-alpha.0",
|
|
35
35
|
"@types/bun": "^1.3.8",
|
|
36
36
|
"@types/node": "22.19.2",
|