@beyondwork/docx-react-component 1.0.106 → 1.0.109
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/package.json +19 -5
- package/src/api/geometry-overlay-rects.ts +5 -0
- package/src/api/package-version.ts +1 -1
- package/src/api/page-anchor-id.ts +5 -0
- package/src/api/public-types.ts +16 -9
- package/src/api/table-node-specs.ts +6 -0
- package/src/api/v3/_create.ts +2 -1
- package/src/api/v3/_page-anchor-id.ts +52 -0
- package/src/api/v3/_runtime-handle.ts +92 -1
- package/src/api/v3/ai/_audit-time.ts +5 -0
- package/src/api/v3/ai/_pe2-evidence.ts +38 -0
- package/src/api/v3/ai/attach.ts +7 -2
- package/src/api/v3/ai/replacement.ts +101 -18
- package/src/api/v3/ai/resolve.ts +2 -2
- package/src/api/v3/ai/review.ts +177 -3
- package/src/api/v3/index.ts +1 -0
- package/src/api/v3/runtime/collab.ts +462 -0
- package/src/api/v3/runtime/document.ts +503 -20
- package/src/api/v3/runtime/geometry.ts +97 -0
- package/src/api/v3/runtime/layout.ts +744 -0
- package/src/api/v3/runtime/perf-probe.ts +14 -0
- package/src/api/v3/runtime/viewport.ts +9 -8
- package/src/api/v3/ui/_types.ts +149 -55
- package/src/api/v3/ui/chrome-preset-model.ts +5 -5
- package/src/api/v3/ui/debug.ts +115 -2
- package/src/api/v3/ui/index.ts +13 -0
- package/src/api/v3/ui/overlays.ts +0 -8
- package/src/api/v3/ui/surface.ts +56 -0
- package/src/api/v3/ui/viewport.ts +22 -9
- package/src/core/commands/image-commands.ts +1 -0
- package/src/core/commands/index.ts +6 -0
- package/src/core/schema/text-schema.ts +43 -5
- package/src/core/selection/mapping.ts +8 -1
- package/src/core/selection/review-anchors.ts +5 -1
- package/src/core/state/text-transaction.ts +8 -2
- package/src/io/export/serialize-revisions.ts +149 -1
- package/src/io/normalize/normalize-text.ts +6 -0
- package/src/io/ooxml/parse-bookmark-references.ts +55 -0
- package/src/io/ooxml/parse-fields.ts +24 -2
- package/src/io/ooxml/parse-headers-footers.ts +38 -5
- package/src/io/ooxml/parse-main-document.ts +153 -9
- package/src/io/ooxml/parse-numbering.ts +20 -0
- package/src/io/ooxml/parse-revisions.ts +19 -8
- package/src/io/opc/package-reader.ts +98 -8
- package/src/model/anchor.ts +4 -3
- package/src/model/canonical-document.ts +220 -2
- package/src/model/canonical-hash.ts +221 -0
- package/src/model/canonical-layout-inputs.ts +245 -6
- package/src/model/layout/index.ts +1 -0
- package/src/model/layout/page-graph-types.ts +118 -1
- package/src/model/review/revision-types.ts +14 -3
- package/src/preservation/store.ts +20 -4
- package/src/review/README.md +1 -1
- package/src/review/store/revision-actions.ts +14 -2
- package/src/runtime/collab/event-types.ts +67 -1
- package/src/runtime/collab/runtime-collab-sync.ts +177 -5
- package/src/runtime/diagnostics/layout-guard-warning.ts +18 -0
- package/src/runtime/document-heading-outline.ts +147 -0
- package/src/runtime/document-navigation.ts +8 -243
- package/src/runtime/document-runtime.ts +240 -97
- package/src/runtime/edit-dispatch/dispatch-text-command.ts +11 -0
- package/src/runtime/formatting/layout-inputs.ts +38 -5
- package/src/runtime/formatting/numbering/geometry.ts +28 -2
- package/src/runtime/geometry/adjacent-geometry-intake.ts +835 -0
- package/src/runtime/geometry/caret-geometry.ts +5 -6
- package/src/runtime/geometry/geometry-facet.ts +60 -10
- package/src/runtime/geometry/geometry-index.ts +591 -20
- package/src/runtime/geometry/geometry-types.ts +59 -0
- package/src/runtime/geometry/hit-test.ts +11 -1
- package/src/runtime/geometry/overlay-rects.ts +5 -3
- package/src/runtime/geometry/project-anchors.ts +1 -1
- package/src/runtime/geometry/word-layout-v2-line-intake.ts +323 -0
- package/src/runtime/layout/index.ts +6 -0
- package/src/runtime/layout/layout-engine-instance.ts +6 -1
- package/src/runtime/layout/layout-engine-version.ts +181 -16
- package/src/runtime/layout/layout-facet-types.ts +6 -0
- package/src/runtime/layout/page-graph.ts +21 -4
- package/src/runtime/layout/paginated-layout-engine.ts +139 -15
- package/src/runtime/layout/project-block-fragments.ts +265 -7
- package/src/runtime/layout/public-facet.ts +78 -24
- package/src/runtime/layout/table-row-continuation-contract.ts +107 -0
- package/src/runtime/layout/table-row-split.ts +92 -35
- package/src/runtime/prerender/cache-envelope.ts +2 -2
- package/src/runtime/prerender/cache-key.ts +5 -4
- package/src/runtime/prerender/customxml-cache.ts +0 -1
- package/src/runtime/render/render-kernel.ts +1 -1
- package/src/runtime/revision-runtime.ts +112 -10
- package/src/runtime/scopes/_scope-dependencies.ts +1 -0
- package/src/runtime/scopes/action-validation.ts +22 -2
- package/src/runtime/scopes/capabilities.ts +316 -0
- package/src/runtime/scopes/compile-scope-bundle.ts +14 -0
- package/src/runtime/scopes/compiler-service.ts +108 -4
- package/src/runtime/scopes/content-control-evidence.ts +79 -0
- package/src/runtime/scopes/create-issue.ts +5 -5
- package/src/runtime/scopes/evidence.ts +91 -0
- package/src/runtime/scopes/formatting/apply.ts +2 -0
- package/src/runtime/scopes/geometry-evidence.ts +130 -0
- package/src/runtime/scopes/index.ts +54 -0
- package/src/runtime/scopes/issue-lifecycle.ts +224 -0
- package/src/runtime/scopes/layout-evidence.ts +374 -0
- package/src/runtime/scopes/multi-paragraph-refusal.ts +37 -0
- package/src/runtime/scopes/preservation-boundary.ts +7 -1
- package/src/runtime/scopes/replacement/apply.ts +97 -34
- package/src/runtime/scopes/scope-kinds/paragraph.ts +108 -12
- package/src/runtime/scopes/semantic-scope-types.ts +242 -3
- package/src/runtime/scopes/visualization.ts +28 -0
- package/src/runtime/surface-projection.ts +44 -5
- package/src/runtime/telemetry/perf-probe.ts +216 -0
- package/src/runtime/virtualized-rendering.ts +36 -1
- package/src/runtime/workflow/ai-issue-lifecycle.ts +253 -0
- package/src/runtime/workflow/coordinator.ts +39 -11
- package/src/runtime/workflow/derived-scope-resolver.ts +63 -9
- package/src/runtime/workflow/index.ts +3 -0
- package/src/runtime/workflow/overlay-lane-types.ts +58 -0
- package/src/runtime/workflow/overlay-lanes.ts +168 -10
- package/src/runtime/workflow/overlay-store.ts +2 -2
- package/src/runtime/workflow/redline-posture-calibration.ts +257 -0
- package/src/runtime/workflow/word-field-matrix-calibration.ts +231 -0
- package/src/session/_sync-legacy.ts +17 -27
- package/src/session/import/loader.ts +6 -4
- package/src/session/import/source-package-evidence.ts +186 -2
- package/src/session/index.ts +5 -6
- package/src/session/session.ts +30 -56
- package/src/session/types.ts +8 -13
- package/src/shell/session-bootstrap.ts +155 -81
- package/src/ui/WordReviewEditor.tsx +520 -12
- package/src/ui/editor-shell-view.tsx +14 -4
- package/src/ui/editor-surface-controller.tsx +5 -3
- package/src/ui/headless/selection-tool-resolver.ts +1 -2
- package/src/ui/presence-overlay-lane.ts +0 -1
- package/src/ui/ui-controller-factory.ts +7 -0
- package/src/ui-tailwind/chrome/build-context-menu-entries.ts +5 -1
- package/src/ui-tailwind/chrome/editor-action-registry.ts +105 -5
- package/src/ui-tailwind/chrome/editor-actions-to-palette.ts +7 -0
- package/src/ui-tailwind/chrome/layer-debug-contracts.ts +208 -0
- package/src/ui-tailwind/chrome/resolve-target-kind.ts +13 -0
- package/src/ui-tailwind/chrome/tw-alert-banner.tsx +11 -3
- package/src/ui-tailwind/chrome/tw-command-palette.tsx +36 -6
- package/src/ui-tailwind/chrome/tw-context-menu.tsx +6 -1
- package/src/ui-tailwind/chrome/tw-display-mode-selector.tsx +42 -109
- package/src/ui-tailwind/chrome/tw-inline-find-bar.tsx +26 -6
- package/src/ui-tailwind/chrome/tw-navigation-command-bar.tsx +328 -0
- package/src/ui-tailwind/chrome/tw-object-context-toolbar.tsx +8 -4
- package/src/ui-tailwind/chrome/tw-runtime-repl-dialog.tsx +129 -1
- package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +19 -5
- package/src/ui-tailwind/chrome/tw-selection-tool-structure.tsx +5 -1
- package/src/ui-tailwind/chrome/tw-workspace-chrome-host.tsx +28 -12
- package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +30 -3
- package/src/ui-tailwind/chrome-overlay/tw-object-selection-overlay.tsx +116 -10
- package/src/ui-tailwind/chrome-overlay/tw-page-stack-overlay-layer.tsx +223 -94
- package/src/ui-tailwind/chrome-overlay/tw-presence-overlay-lane.tsx +157 -0
- package/src/ui-tailwind/chrome-overlay/tw-review-overlay-lane-markers.tsx +259 -0
- package/src/ui-tailwind/chrome-overlay/tw-scope-card-layer.tsx +5 -2
- package/src/ui-tailwind/chrome-overlay/tw-substrate-overlay-lanes.tsx +314 -0
- package/src/ui-tailwind/debug/README.md +4 -1
- package/src/ui-tailwind/debug/layer11-consumer-readiness.ts +272 -0
- package/src/ui-tailwind/debug/layer11-word-field-matrix-evidence.ts +160 -0
- package/src/ui-tailwind/editor-surface/perf-probe.ts +14 -215
- package/src/ui-tailwind/editor-surface/pm-decorations.ts +42 -0
- package/src/ui-tailwind/editor-surface/pm-position-map.ts +38 -2
- package/src/ui-tailwind/editor-surface/pm-schema.ts +14 -4
- package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +34 -5
- package/src/ui-tailwind/editor-surface/runtime-decoration-plugin.ts +9 -19
- package/src/ui-tailwind/editor-surface/surface-build-keys.ts +2 -2
- package/src/ui-tailwind/editor-surface/tw-page-block-view.helpers.ts +145 -0
- package/src/ui-tailwind/editor-surface/tw-page-block-view.tsx +16 -11
- package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +8 -10
- package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +3 -0
- package/src/ui-tailwind/page-stack/tw-page-chrome-entry.tsx +4 -2
- package/src/ui-tailwind/page-stack/tw-page-stack-chrome-layer.tsx +60 -20
- package/src/ui-tailwind/page-stack/tw-region-block-renderer.tsx +16 -11
- package/src/ui-tailwind/review/tw-health-panel.tsx +36 -17
- package/src/ui-tailwind/review/tw-review-rail.tsx +7 -4
- package/src/ui-tailwind/review-workspace/diagnostics-visibility.ts +44 -0
- package/src/ui-tailwind/review-workspace/page-shell-metrics.ts +11 -0
- package/src/ui-tailwind/review-workspace/tw-review-workspace-rail.tsx +16 -1
- package/src/ui-tailwind/review-workspace/types.ts +26 -12
- package/src/ui-tailwind/review-workspace/use-diagnostics-signal.ts +40 -11
- package/src/ui-tailwind/review-workspace/use-layout-facet-render-signal.ts +2 -1
- package/src/ui-tailwind/review-workspace/use-page-markers.ts +15 -26
- package/src/ui-tailwind/review-workspace/use-scope-card-state.ts +35 -18
- package/src/ui-tailwind/review-workspace/use-selection-toolbar-placement.ts +41 -32
- package/src/ui-tailwind/review-workspace/use-status-bar-page-facts.ts +2 -1
- package/src/ui-tailwind/review-workspace/use-workspace-side-effects.ts +2 -1
- package/src/ui-tailwind/status/tw-status-bar.tsx +6 -5
- package/src/ui-tailwind/toolbar/tw-role-action-region.tsx +52 -80
- package/src/ui-tailwind/toolbar/tw-shell-header.tsx +12 -48
- package/src/ui-tailwind/toolbar/tw-toolbar-icon-button.tsx +9 -4
- package/src/ui-tailwind/toolbar/tw-toolbar.tsx +328 -361
- package/src/ui-tailwind/tw-review-workspace.tsx +152 -286
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
TableRowNode,
|
|
13
13
|
TextMark,
|
|
14
14
|
Mutable,
|
|
15
|
+
CanonicalSourceRef,
|
|
15
16
|
} from "../../model/canonical-document.ts";
|
|
16
17
|
import type { LegacyFormFieldNode } from "../../model/canonical-document.ts";
|
|
17
18
|
import { resolveHighlightColor } from "./highlight-colors.ts";
|
|
@@ -58,6 +59,7 @@ import { parseShapeXml, parseVmlXml } from "./parse-shapes.ts";
|
|
|
58
59
|
|
|
59
60
|
const TAB_ALIGN_VOCAB = new Set<TabStop["align"]>(["left", "center", "right", "decimal", "num", "bar", "clear"]);
|
|
60
61
|
const TAB_LEADER_VOCAB = new Set<TabStop["leader"]>(["none", "dot", "hyphen", "underscore", "heavy", "middleDot"]);
|
|
62
|
+
let activeHeaderFooterFieldSequenceOrdinal = 0;
|
|
61
63
|
|
|
62
64
|
// ---- Public types ----
|
|
63
65
|
|
|
@@ -229,6 +231,7 @@ function parseHdrFtrXml(
|
|
|
229
231
|
opts: ParseHeaderFooterOpts = { relationships: [] },
|
|
230
232
|
): ParsedHeaderFooterDocument {
|
|
231
233
|
currentSourceXml = xml;
|
|
234
|
+
activeHeaderFooterFieldSequenceOrdinal = 0;
|
|
232
235
|
let root: XmlElementNode;
|
|
233
236
|
try {
|
|
234
237
|
root = parseXml(xml) as XmlElementNode;
|
|
@@ -326,11 +329,12 @@ function parseParagraphElement(
|
|
|
326
329
|
"complex",
|
|
327
330
|
activeComplexField.children,
|
|
328
331
|
activeComplexField.legacyFormField,
|
|
332
|
+
activeComplexField.sourceRef,
|
|
329
333
|
),
|
|
330
334
|
);
|
|
331
335
|
activeComplexField = null;
|
|
332
336
|
}
|
|
333
|
-
pushFieldNode(children, child, "simple");
|
|
337
|
+
pushFieldNode(children, child, "simple", opts.sourcePartPath);
|
|
334
338
|
} else if (name === "sdt") {
|
|
335
339
|
// coord-11 §22 — structured-document-tag wrapping run-level content
|
|
336
340
|
// inside a header/footer paragraph. Word commonly uses these to
|
|
@@ -355,7 +359,7 @@ function parseParagraphElement(
|
|
|
355
359
|
} else if (gname === "bookmarkStart" || gname === "bookmarkEnd") {
|
|
356
360
|
children.push(parseBookmarkElement(grandchild));
|
|
357
361
|
} else if (gname === "fldSimple") {
|
|
358
|
-
pushFieldNode(children, grandchild, "simple");
|
|
362
|
+
pushFieldNode(children, grandchild, "simple", opts.sourcePartPath);
|
|
359
363
|
}
|
|
360
364
|
// Nested sdt / other elements ignored — deeper nesting is rare
|
|
361
365
|
// enough that opaque round-trip via the block-level sdt parser
|
|
@@ -372,6 +376,7 @@ function parseParagraphElement(
|
|
|
372
376
|
"complex",
|
|
373
377
|
activeComplexField.children,
|
|
374
378
|
activeComplexField.legacyFormField,
|
|
379
|
+
activeComplexField.sourceRef,
|
|
375
380
|
),
|
|
376
381
|
);
|
|
377
382
|
}
|
|
@@ -391,6 +396,7 @@ interface ActiveComplexField {
|
|
|
391
396
|
instruction: string;
|
|
392
397
|
children: Array<Extract<InlineNode, { type: "text" | "hard_break" | "tab" }>>;
|
|
393
398
|
mode: "instruction" | "result";
|
|
399
|
+
sourceRef?: CanonicalSourceRef;
|
|
394
400
|
legacyFormField?: LegacyFormFieldNode;
|
|
395
401
|
}
|
|
396
402
|
|
|
@@ -419,6 +425,7 @@ function appendRunNodes(
|
|
|
419
425
|
instruction: "",
|
|
420
426
|
children: [],
|
|
421
427
|
mode: "instruction",
|
|
428
|
+
sourceRef: createFieldSequenceSourceRef(opts.sourcePartPath ?? "/word/document.xml", rElement),
|
|
422
429
|
...(legacyFormField ? { legacyFormField } : {}),
|
|
423
430
|
};
|
|
424
431
|
} else if (fldType === "separate" && activeComplexField) {
|
|
@@ -431,6 +438,7 @@ function appendRunNodes(
|
|
|
431
438
|
"complex",
|
|
432
439
|
activeComplexField.children,
|
|
433
440
|
activeComplexField.legacyFormField,
|
|
441
|
+
activeComplexField.sourceRef,
|
|
434
442
|
),
|
|
435
443
|
);
|
|
436
444
|
}
|
|
@@ -443,7 +451,7 @@ function appendRunNodes(
|
|
|
443
451
|
if (activeComplexField) {
|
|
444
452
|
activeComplexField.instruction += extractTextContent(child);
|
|
445
453
|
} else {
|
|
446
|
-
pushFieldNode(nodes, child, "complex");
|
|
454
|
+
pushFieldNode(nodes, child, "complex", opts.sourcePartPath);
|
|
447
455
|
}
|
|
448
456
|
continue;
|
|
449
457
|
}
|
|
@@ -522,7 +530,7 @@ function parseRunElement(
|
|
|
522
530
|
} else if (name === "bookmarkStart" || name === "bookmarkEnd") {
|
|
523
531
|
nodes.push(parseBookmarkElement(child));
|
|
524
532
|
} else if (name === "instrText") {
|
|
525
|
-
pushFieldNode(nodes, child, "complex");
|
|
533
|
+
pushFieldNode(nodes, child, "complex", opts.sourcePartPath);
|
|
526
534
|
} else if (name === "drawing") {
|
|
527
535
|
const drawingXml = currentSourceXml.slice(child.start, child.end);
|
|
528
536
|
const drawingResult = parseDrawingInlineNode(drawingXml, opts);
|
|
@@ -824,6 +832,7 @@ function pushFieldNode(
|
|
|
824
832
|
nodes: InlineNode[],
|
|
825
833
|
element: XmlElementNode,
|
|
826
834
|
fieldType: "simple" | "complex",
|
|
835
|
+
sourcePartPath = "/word/document.xml",
|
|
827
836
|
): void {
|
|
828
837
|
const instruction = readFieldInstruction(element);
|
|
829
838
|
if (!instruction) {
|
|
@@ -832,7 +841,13 @@ function pushFieldNode(
|
|
|
832
841
|
|
|
833
842
|
const classification = classifyFieldInstruction(instruction);
|
|
834
843
|
|
|
835
|
-
nodes.push(createFieldNode(
|
|
844
|
+
nodes.push(createFieldNode(
|
|
845
|
+
instruction,
|
|
846
|
+
fieldType,
|
|
847
|
+
[],
|
|
848
|
+
undefined,
|
|
849
|
+
createFieldSequenceSourceRef(sourcePartPath, element),
|
|
850
|
+
));
|
|
836
851
|
}
|
|
837
852
|
|
|
838
853
|
function createFieldNode(
|
|
@@ -840,6 +855,7 @@ function createFieldNode(
|
|
|
840
855
|
fieldType: "simple" | "complex",
|
|
841
856
|
children: InlineNode[] = [],
|
|
842
857
|
legacyFormField?: LegacyFormFieldNode,
|
|
858
|
+
sourceRef?: CanonicalSourceRef,
|
|
843
859
|
): Extract<InlineNode, { type: "field" }> {
|
|
844
860
|
const classification = classifyFieldInstruction(instruction);
|
|
845
861
|
return {
|
|
@@ -850,10 +866,27 @@ function createFieldNode(
|
|
|
850
866
|
fieldFamily: classification.family,
|
|
851
867
|
...(classification.target ? { fieldTarget: classification.target } : {}),
|
|
852
868
|
refreshStatus: classification.supported ? "stale" : "preserve-only",
|
|
869
|
+
...(sourceRef ? { sourceRef } : {}),
|
|
853
870
|
...(legacyFormField ? { legacyFormField } : {}),
|
|
854
871
|
};
|
|
855
872
|
}
|
|
856
873
|
|
|
874
|
+
function createFieldSequenceSourceRef(
|
|
875
|
+
partPath: string,
|
|
876
|
+
node: XmlElementNode,
|
|
877
|
+
): CanonicalSourceRef {
|
|
878
|
+
activeHeaderFooterFieldSequenceOrdinal += 1;
|
|
879
|
+
return {
|
|
880
|
+
sourceId: `part:${partPath}#fieldSequence:${activeHeaderFooterFieldSequenceOrdinal}`,
|
|
881
|
+
partPath,
|
|
882
|
+
storyKind: /\/footer\d+\.xml$/i.test(partPath) ? "footer" : "header",
|
|
883
|
+
element: "fieldSequence",
|
|
884
|
+
ordinal: activeHeaderFooterFieldSequenceOrdinal,
|
|
885
|
+
startOffset: node.start,
|
|
886
|
+
endOffset: node.end,
|
|
887
|
+
};
|
|
888
|
+
}
|
|
889
|
+
|
|
857
890
|
function readFieldInstruction(element: XmlElementNode): string | undefined {
|
|
858
891
|
const instruction =
|
|
859
892
|
readStringAttr(element, "w:instr") ??
|
|
@@ -20,6 +20,7 @@ import type {
|
|
|
20
20
|
PageSize,
|
|
21
21
|
PageMargins,
|
|
22
22
|
ColumnProperties,
|
|
23
|
+
CanonicalSourceRef,
|
|
23
24
|
PageNumbering,
|
|
24
25
|
SectionDocumentGrid,
|
|
25
26
|
SectionLineNumbering,
|
|
@@ -28,6 +29,7 @@ import type {
|
|
|
28
29
|
UnknownPropertyChild,
|
|
29
30
|
Mutable,
|
|
30
31
|
} from "../../model/canonical-document.ts";
|
|
32
|
+
import { sha256TextHex } from "../../model/canonical-hash.ts";
|
|
31
33
|
import type { OpcRelationship } from "./part-manifest.ts";
|
|
32
34
|
import { SCOPE_MARKER_BOOKMARK_PREFIX } from "./parse-scope-markers.ts";
|
|
33
35
|
import {
|
|
@@ -313,8 +315,10 @@ export interface ParsedParagraphNode {
|
|
|
313
315
|
styleId?: string;
|
|
314
316
|
numbering?: {
|
|
315
317
|
numberingInstanceId: string;
|
|
318
|
+
sourceRef?: CanonicalSourceRef;
|
|
316
319
|
level: number;
|
|
317
320
|
};
|
|
321
|
+
sourceRef?: CanonicalSourceRef;
|
|
318
322
|
alignment?: "left" | "center" | "right" | "both" | "distribute";
|
|
319
323
|
spacing?: ParagraphSpacing;
|
|
320
324
|
contextualSpacing?: boolean;
|
|
@@ -438,6 +442,16 @@ export interface ParsedImageNode {
|
|
|
438
442
|
export interface ParsedHyperlinkNode {
|
|
439
443
|
type: "hyperlink";
|
|
440
444
|
href: string;
|
|
445
|
+
sourceRef?: CanonicalSourceRef;
|
|
446
|
+
fieldCarrier?: {
|
|
447
|
+
sourceRef?: CanonicalSourceRef;
|
|
448
|
+
fieldFamily?: ReturnType<typeof classifyFieldInstruction>["family"];
|
|
449
|
+
refreshStatus?: "current" | "stale" | "unresolvable" | "preserve-only";
|
|
450
|
+
locked?: boolean;
|
|
451
|
+
dirty?: boolean;
|
|
452
|
+
instructionHash?: string;
|
|
453
|
+
resultHash?: string;
|
|
454
|
+
};
|
|
441
455
|
children: Array<ParsedTextNode | ParsedBreakNode | ParsedColumnBreakNode | ParsedPageBreakNode | ParsedTabNode | ParsedSymbolNode>;
|
|
442
456
|
rawXml: string;
|
|
443
457
|
}
|
|
@@ -545,6 +559,7 @@ export interface ParsedFieldInlineNode {
|
|
|
545
559
|
contentXml?: string;
|
|
546
560
|
children?: Array<ParsedTextNode | ParsedBreakNode | ParsedTabNode>;
|
|
547
561
|
rawXml: string;
|
|
562
|
+
sourceRef?: CanonicalSourceRef;
|
|
548
563
|
legacyFormField?: import("../../model/canonical-document.ts").LegacyFormFieldNode;
|
|
549
564
|
}
|
|
550
565
|
|
|
@@ -724,6 +739,7 @@ const HYPERLINK_RELATIONSHIP_TYPE =
|
|
|
724
739
|
* not exist; `parseSdtXml` is only callable externally via `parsePictureSdt`.
|
|
725
740
|
*/
|
|
726
741
|
let activeChartPartLookup: ChartPartLookup | undefined;
|
|
742
|
+
let activeFieldSequenceOrdinal = 0;
|
|
727
743
|
|
|
728
744
|
/**
|
|
729
745
|
* Phase 1 telemetry — optional bus installed by the runtime before a load.
|
|
@@ -838,6 +854,7 @@ export function parseMainDocumentXml(
|
|
|
838
854
|
activeCosmeticStripContext = stripContext;
|
|
839
855
|
const bus = activeParseTelemetryBus;
|
|
840
856
|
const started = bus?.isEnabled("parse") ? performanceNow() : 0;
|
|
857
|
+
activeFieldSequenceOrdinal = 0;
|
|
841
858
|
try {
|
|
842
859
|
const result = parseMainDocumentXmlInner(xml, relationships, mediaParts, sourcePartPath);
|
|
843
860
|
if (Object.keys(stripContext.counts).length > 0) {
|
|
@@ -850,6 +867,7 @@ export function parseMainDocumentXml(
|
|
|
850
867
|
} finally {
|
|
851
868
|
activeChartPartLookup = undefined;
|
|
852
869
|
activeCosmeticStripContext = null;
|
|
870
|
+
activeFieldSequenceOrdinal = 0;
|
|
853
871
|
}
|
|
854
872
|
}
|
|
855
873
|
|
|
@@ -1266,7 +1284,7 @@ function parseBodyChild(
|
|
|
1266
1284
|
switch (localName(child.name)) {
|
|
1267
1285
|
case "pPr":
|
|
1268
1286
|
styleId = readParagraphStyleId(child);
|
|
1269
|
-
numbering = readParagraphNumbering(child);
|
|
1287
|
+
numbering = readParagraphNumbering(child, sourcePartPath);
|
|
1270
1288
|
alignment = readParagraphAlignment(child);
|
|
1271
1289
|
spacing = readParagraphSpacing(child);
|
|
1272
1290
|
contextualSpacing = readOptionalOnOffParagraphProperty(child, "contextualSpacing");
|
|
@@ -1307,7 +1325,7 @@ function parseBodyChild(
|
|
|
1307
1325
|
flushActiveComplexField(children, () => {
|
|
1308
1326
|
activeComplexField = null;
|
|
1309
1327
|
}, activeComplexField);
|
|
1310
|
-
const hyperlink = parseHyperlink(child, sourceXml, relationshipMap);
|
|
1328
|
+
const hyperlink = parseHyperlink(child, sourceXml, relationshipMap, {}, sourcePartPath);
|
|
1311
1329
|
children.push(hyperlink);
|
|
1312
1330
|
break;
|
|
1313
1331
|
}
|
|
@@ -1400,6 +1418,7 @@ function parseBodyChild(
|
|
|
1400
1418
|
instruction: fieldInstr,
|
|
1401
1419
|
contentXml: fieldContentXml,
|
|
1402
1420
|
rawXml: sourceXml.slice(child.start, child.end),
|
|
1421
|
+
sourceRef: createFieldSequenceSourceRef(sourcePartPath, child),
|
|
1403
1422
|
} as ParsedFieldInlineNode);
|
|
1404
1423
|
break;
|
|
1405
1424
|
}
|
|
@@ -1481,6 +1500,7 @@ function parseBodyChild(
|
|
|
1481
1500
|
|
|
1482
1501
|
return {
|
|
1483
1502
|
type: "paragraph",
|
|
1503
|
+
sourceRef: createElementSourceRef(sourcePartPath, "p", node),
|
|
1484
1504
|
styleId,
|
|
1485
1505
|
...(numbering ? { numbering } : {}),
|
|
1486
1506
|
...(alignment ? { alignment } : {}),
|
|
@@ -1514,6 +1534,7 @@ function appendParagraphRunNodes(
|
|
|
1514
1534
|
instruction: string;
|
|
1515
1535
|
children: Array<ParsedTextNode | ParsedBreakNode | ParsedTabNode>;
|
|
1516
1536
|
mode: "instruction" | "result";
|
|
1537
|
+
sourceRef?: CanonicalSourceRef;
|
|
1517
1538
|
legacyFormField?: import("../../model/canonical-document.ts").LegacyFormFieldNode;
|
|
1518
1539
|
} | null,
|
|
1519
1540
|
sourceXml: string,
|
|
@@ -1524,6 +1545,7 @@ function appendParagraphRunNodes(
|
|
|
1524
1545
|
instruction: string;
|
|
1525
1546
|
children: Array<ParsedTextNode | ParsedBreakNode | ParsedTabNode>;
|
|
1526
1547
|
mode: "instruction" | "result";
|
|
1548
|
+
sourceRef?: CanonicalSourceRef;
|
|
1527
1549
|
legacyFormField?: import("../../model/canonical-document.ts").LegacyFormFieldNode;
|
|
1528
1550
|
} | null {
|
|
1529
1551
|
const hasFieldMarkers = node.children.some(
|
|
@@ -1565,6 +1587,7 @@ function appendParagraphRunNodes(
|
|
|
1565
1587
|
instruction: "",
|
|
1566
1588
|
children: [],
|
|
1567
1589
|
mode: "instruction",
|
|
1590
|
+
sourceRef: createFieldSequenceSourceRef(sourcePartPath, node),
|
|
1568
1591
|
...(legacyFormField ? { legacyFormField } : {}),
|
|
1569
1592
|
};
|
|
1570
1593
|
} else if (fldType === "separate" && activeComplexField) {
|
|
@@ -1591,6 +1614,7 @@ function appendParagraphRunNodes(
|
|
|
1591
1614
|
instruction,
|
|
1592
1615
|
children: [],
|
|
1593
1616
|
rawXml: sourceXml.slice(node.start, node.end),
|
|
1617
|
+
sourceRef: createFieldSequenceSourceRef(sourcePartPath, node),
|
|
1594
1618
|
});
|
|
1595
1619
|
}
|
|
1596
1620
|
continue;
|
|
@@ -1607,6 +1631,7 @@ function flushActiveComplexField(
|
|
|
1607
1631
|
instruction: string;
|
|
1608
1632
|
children: Array<ParsedTextNode | ParsedBreakNode | ParsedTabNode>;
|
|
1609
1633
|
mode: "instruction" | "result";
|
|
1634
|
+
sourceRef?: CanonicalSourceRef;
|
|
1610
1635
|
legacyFormField?: import("../../model/canonical-document.ts").LegacyFormFieldNode;
|
|
1611
1636
|
} | null,
|
|
1612
1637
|
): void {
|
|
@@ -1620,6 +1645,7 @@ function flushActiveComplexField(
|
|
|
1620
1645
|
instruction: activeComplexField.instruction,
|
|
1621
1646
|
children: activeComplexField.children,
|
|
1622
1647
|
rawXml: "",
|
|
1648
|
+
...(activeComplexField.sourceRef ? { sourceRef: activeComplexField.sourceRef } : {}),
|
|
1623
1649
|
...(activeComplexField.legacyFormField ? { legacyFormField: activeComplexField.legacyFormField } : {}),
|
|
1624
1650
|
});
|
|
1625
1651
|
reset();
|
|
@@ -2547,6 +2573,7 @@ function readParagraphStyleId(node: XmlElementNode): string | undefined {
|
|
|
2547
2573
|
|
|
2548
2574
|
function readParagraphNumbering(
|
|
2549
2575
|
node: XmlElementNode,
|
|
2576
|
+
sourcePartPath: string,
|
|
2550
2577
|
): ParsedParagraphNode["numbering"] | undefined {
|
|
2551
2578
|
const numberingProperties = node.children.find(
|
|
2552
2579
|
(child): child is XmlElementNode =>
|
|
@@ -2572,10 +2599,50 @@ function readParagraphNumbering(
|
|
|
2572
2599
|
|
|
2573
2600
|
return {
|
|
2574
2601
|
numberingInstanceId: toCanonicalNumberingInstanceId(rawInstanceId),
|
|
2602
|
+
sourceRef: createElementSourceRef(sourcePartPath, "numPr", numberingProperties),
|
|
2575
2603
|
level: Number.parseInt(rawLevel, 10),
|
|
2576
2604
|
};
|
|
2577
2605
|
}
|
|
2578
2606
|
|
|
2607
|
+
function createElementSourceRef(
|
|
2608
|
+
partPath: string,
|
|
2609
|
+
element: string,
|
|
2610
|
+
node: XmlElementNode,
|
|
2611
|
+
): CanonicalSourceRef {
|
|
2612
|
+
return {
|
|
2613
|
+
sourceId: `part:${partPath}#${element}:${node.start}`,
|
|
2614
|
+
partPath,
|
|
2615
|
+
storyKind: storyKindFromPartPath(partPath),
|
|
2616
|
+
element,
|
|
2617
|
+
startOffset: node.start,
|
|
2618
|
+
endOffset: node.end,
|
|
2619
|
+
};
|
|
2620
|
+
}
|
|
2621
|
+
|
|
2622
|
+
function createFieldSequenceSourceRef(
|
|
2623
|
+
partPath: string,
|
|
2624
|
+
node: XmlElementNode,
|
|
2625
|
+
): CanonicalSourceRef {
|
|
2626
|
+
activeFieldSequenceOrdinal += 1;
|
|
2627
|
+
return {
|
|
2628
|
+
sourceId: `part:${partPath}#fieldSequence:${activeFieldSequenceOrdinal}`,
|
|
2629
|
+
partPath,
|
|
2630
|
+
storyKind: storyKindFromPartPath(partPath),
|
|
2631
|
+
element: "fieldSequence",
|
|
2632
|
+
ordinal: activeFieldSequenceOrdinal,
|
|
2633
|
+
startOffset: node.start,
|
|
2634
|
+
endOffset: node.end,
|
|
2635
|
+
};
|
|
2636
|
+
}
|
|
2637
|
+
|
|
2638
|
+
function storyKindFromPartPath(partPath: string): string {
|
|
2639
|
+
if (/\/header\d+\.xml$/i.test(partPath)) return "header";
|
|
2640
|
+
if (/\/footer\d+\.xml$/i.test(partPath)) return "footer";
|
|
2641
|
+
if (/\/footnotes\.xml$/i.test(partPath)) return "footnote";
|
|
2642
|
+
if (/\/endnotes\.xml$/i.test(partPath)) return "endnote";
|
|
2643
|
+
return "main";
|
|
2644
|
+
}
|
|
2645
|
+
|
|
2579
2646
|
function parseRun(
|
|
2580
2647
|
node: XmlElementNode,
|
|
2581
2648
|
sourceXml: string,
|
|
@@ -2916,10 +2983,16 @@ function parseRevisionContainer(
|
|
|
2916
2983
|
break;
|
|
2917
2984
|
}
|
|
2918
2985
|
case "hyperlink": {
|
|
2919
|
-
const hyperlink = parseHyperlink(
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2986
|
+
const hyperlink = parseHyperlink(
|
|
2987
|
+
child,
|
|
2988
|
+
sourceXml,
|
|
2989
|
+
relationshipMap,
|
|
2990
|
+
{
|
|
2991
|
+
allowDeletedText: allowsDeletedText,
|
|
2992
|
+
preserveUnsupportedReviewMarkup: true,
|
|
2993
|
+
},
|
|
2994
|
+
"/word/document.xml",
|
|
2995
|
+
);
|
|
2923
2996
|
if (hyperlink.type === "opaque_inline") {
|
|
2924
2997
|
return [
|
|
2925
2998
|
{
|
|
@@ -3020,6 +3093,7 @@ function parseHyperlink(
|
|
|
3020
3093
|
allowDeletedText?: boolean;
|
|
3021
3094
|
preserveUnsupportedReviewMarkup?: boolean;
|
|
3022
3095
|
} = {},
|
|
3096
|
+
sourcePartPath = "/word/document.xml",
|
|
3023
3097
|
): ParsedHyperlinkNode | ParsedOpaqueInlineNode {
|
|
3024
3098
|
const relationshipId = node.attributes["r:id"] ?? node.attributes.id;
|
|
3025
3099
|
const anchor = node.attributes["w:anchor"] ?? node.attributes.anchor;
|
|
@@ -3058,6 +3132,10 @@ function parseHyperlink(
|
|
|
3058
3132
|
// escape the hyperlink scope.
|
|
3059
3133
|
type FieldBracketMode = "outside" | "instruction" | "result";
|
|
3060
3134
|
let bracketMode: FieldBracketMode = "outside";
|
|
3135
|
+
let fieldSourceRef: CanonicalSourceRef | undefined;
|
|
3136
|
+
let fieldInstruction = "";
|
|
3137
|
+
let fieldLocked: boolean | undefined;
|
|
3138
|
+
let fieldDirty: boolean | undefined;
|
|
3061
3139
|
|
|
3062
3140
|
for (const child of node.children) {
|
|
3063
3141
|
if (child.type !== "element") {
|
|
@@ -3081,9 +3159,29 @@ function parseHyperlink(
|
|
|
3081
3159
|
if (fldChar) {
|
|
3082
3160
|
const fldType =
|
|
3083
3161
|
fldChar.attributes["w:fldCharType"] ?? fldChar.attributes.fldCharType;
|
|
3084
|
-
if (fldType === "begin")
|
|
3085
|
-
|
|
3086
|
-
|
|
3162
|
+
if (fldType === "begin") {
|
|
3163
|
+
bracketMode = "instruction";
|
|
3164
|
+
fieldSourceRef = createFieldSequenceSourceRef(sourcePartPath, child);
|
|
3165
|
+
fieldInstruction = "";
|
|
3166
|
+
fieldLocked = readOnOffFieldFlag(fldChar, "fldLock");
|
|
3167
|
+
fieldDirty = readOnOffFieldFlag(fldChar, "dirty");
|
|
3168
|
+
} else if (fldType === "separate") {
|
|
3169
|
+
bracketMode = "result";
|
|
3170
|
+
} else if (fldType === "end") {
|
|
3171
|
+
bracketMode = "outside";
|
|
3172
|
+
}
|
|
3173
|
+
continue;
|
|
3174
|
+
}
|
|
3175
|
+
|
|
3176
|
+
const instrText = child.children.find(
|
|
3177
|
+
(c): c is XmlElementNode =>
|
|
3178
|
+
c.type === "element" && localName(c.name) === "instrText",
|
|
3179
|
+
);
|
|
3180
|
+
if (instrText && bracketMode === "instruction") {
|
|
3181
|
+
fieldInstruction += instrText.children
|
|
3182
|
+
.filter((entry): entry is XmlTextNode => entry.type === "text")
|
|
3183
|
+
.map((entry) => entry.text)
|
|
3184
|
+
.join("");
|
|
3087
3185
|
continue;
|
|
3088
3186
|
}
|
|
3089
3187
|
|
|
@@ -3107,14 +3205,60 @@ function parseHyperlink(
|
|
|
3107
3205
|
children.push(...run.nodes);
|
|
3108
3206
|
}
|
|
3109
3207
|
|
|
3208
|
+
const fieldClassification = fieldInstruction.trim().length > 0
|
|
3209
|
+
? classifyFieldInstruction(fieldInstruction)
|
|
3210
|
+
: undefined;
|
|
3110
3211
|
return {
|
|
3111
3212
|
type: "hyperlink",
|
|
3112
3213
|
href,
|
|
3214
|
+
sourceRef: createElementSourceRef(sourcePartPath, "hyperlink", node),
|
|
3215
|
+
...(fieldSourceRef
|
|
3216
|
+
? {
|
|
3217
|
+
fieldCarrier: {
|
|
3218
|
+
sourceRef: fieldSourceRef,
|
|
3219
|
+
...(fieldClassification ? { fieldFamily: fieldClassification.family } : {}),
|
|
3220
|
+
refreshStatus: fieldClassification?.supported
|
|
3221
|
+
? "stale"
|
|
3222
|
+
: "preserve-only",
|
|
3223
|
+
...(fieldInstruction ? { instructionHash: sha256TextHex(fieldInstruction) } : {}),
|
|
3224
|
+
...(children.length > 0 ? { resultHash: sha256TextHex(hyperlinkFieldResultText(children)) } : {}),
|
|
3225
|
+
...(fieldLocked !== undefined ? { locked: fieldLocked } : {}),
|
|
3226
|
+
...(fieldDirty !== undefined ? { dirty: fieldDirty } : {}),
|
|
3227
|
+
},
|
|
3228
|
+
}
|
|
3229
|
+
: {}),
|
|
3113
3230
|
children,
|
|
3114
3231
|
rawXml: sourceXml.slice(node.start, node.end),
|
|
3115
3232
|
};
|
|
3116
3233
|
}
|
|
3117
3234
|
|
|
3235
|
+
function hyperlinkFieldResultText(children: readonly ParsedInlineNode[]): string {
|
|
3236
|
+
return children
|
|
3237
|
+
.map((child) => {
|
|
3238
|
+
switch (child.type) {
|
|
3239
|
+
case "text":
|
|
3240
|
+
return child.text;
|
|
3241
|
+
case "tab":
|
|
3242
|
+
return "\t";
|
|
3243
|
+
case "hard_break":
|
|
3244
|
+
return "\n";
|
|
3245
|
+
case "symbol":
|
|
3246
|
+
return child.char;
|
|
3247
|
+
default:
|
|
3248
|
+
return "";
|
|
3249
|
+
}
|
|
3250
|
+
})
|
|
3251
|
+
.join("");
|
|
3252
|
+
}
|
|
3253
|
+
|
|
3254
|
+
function readOnOffFieldFlag(node: XmlElementNode, name: string): boolean | undefined {
|
|
3255
|
+
const raw = node.attributes[`w:${name}`] ?? node.attributes[name];
|
|
3256
|
+
if (raw === undefined) return undefined;
|
|
3257
|
+
const normalized = raw.toLowerCase();
|
|
3258
|
+
if (normalized === "0" || normalized === "false" || normalized === "off") return false;
|
|
3259
|
+
return true;
|
|
3260
|
+
}
|
|
3261
|
+
|
|
3118
3262
|
function parseRunContentOnly(
|
|
3119
3263
|
node: XmlElementNode,
|
|
3120
3264
|
_sourceXml: string,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type {
|
|
2
|
+
CanonicalSourceRef,
|
|
2
3
|
NumberingCatalog,
|
|
3
4
|
NumberingLevelDefinition,
|
|
4
5
|
NumberingLevelParagraphGeometry,
|
|
@@ -93,6 +94,9 @@ export function parseNumberingXml(xml: string, context?: ParseNumberingContext):
|
|
|
93
94
|
const numStyleLink = numStyleLinkEl ? readStringAttr(numStyleLinkEl, "w:val") : undefined;
|
|
94
95
|
abstractDefinitions[abstractNumberingId] = {
|
|
95
96
|
abstractNumberingId,
|
|
97
|
+
...(context?.partPath !== undefined
|
|
98
|
+
? { sourceRef: createNumberingSourceRef(context.partPath, "abstractNum", rawId) }
|
|
99
|
+
: {}),
|
|
96
100
|
levels: readLevels(child),
|
|
97
101
|
...(nsid ? { nsid } : {}),
|
|
98
102
|
...(multiLevelType ? { multiLevelType } : {}),
|
|
@@ -114,6 +118,9 @@ export function parseNumberingXml(xml: string, context?: ParseNumberingContext):
|
|
|
114
118
|
const numberingInstanceId = toCanonicalNumberingInstanceId(rawId);
|
|
115
119
|
instances[numberingInstanceId] = {
|
|
116
120
|
numberingInstanceId,
|
|
121
|
+
...(context?.partPath !== undefined
|
|
122
|
+
? { sourceRef: createNumberingSourceRef(context.partPath, "num", rawId) }
|
|
123
|
+
: {}),
|
|
117
124
|
abstractNumberingId: toCanonicalAbstractNumberingId(rawAbstractId),
|
|
118
125
|
overrides: readOverrides(child),
|
|
119
126
|
};
|
|
@@ -129,6 +136,19 @@ export function parseNumberingXml(xml: string, context?: ParseNumberingContext):
|
|
|
129
136
|
};
|
|
130
137
|
}
|
|
131
138
|
|
|
139
|
+
function createNumberingSourceRef(
|
|
140
|
+
partPath: string,
|
|
141
|
+
element: "abstractNum" | "num",
|
|
142
|
+
rawId: string,
|
|
143
|
+
): CanonicalSourceRef {
|
|
144
|
+
return {
|
|
145
|
+
sourceId: `part:${partPath}#${element}:${rawId}`,
|
|
146
|
+
partPath,
|
|
147
|
+
storyKind: "numbering",
|
|
148
|
+
element,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
132
152
|
/**
|
|
133
153
|
* Read a `<w:numPicBullet>` element into a catalog entry. Extracts the
|
|
134
154
|
* inner `wp:extent` when present (drawingML path); the raw XML is
|
|
@@ -847,7 +847,7 @@ function parseTableRowAndCellRevisions(
|
|
|
847
847
|
const metadata = readRevisionMetadata(trPrChange, state, "property-change");
|
|
848
848
|
const innerTrPr = findChildElement(trPrChange, "trPr");
|
|
849
849
|
const beforeXml = innerTrPr ? state.documentXml.slice(innerTrPr.start, innerTrPr.end) : "";
|
|
850
|
-
const propertyChangeData: PropertyChangeData = { xmlTag: "
|
|
850
|
+
const propertyChangeData: PropertyChangeData = { xmlTag: "trPrChange", beforeXml };
|
|
851
851
|
|
|
852
852
|
state.revisions.push(
|
|
853
853
|
createRevisionRecord({
|
|
@@ -861,7 +861,6 @@ function parseTableRowAndCellRevisions(
|
|
|
861
861
|
originalRevisionType: "trPrChange",
|
|
862
862
|
ooxmlRevisionId: metadata.ooxmlRevisionId,
|
|
863
863
|
propertyChangeData,
|
|
864
|
-
preserveOnlyReason: "Row property changes remain preserve-only for export safety.",
|
|
865
864
|
},
|
|
866
865
|
}),
|
|
867
866
|
);
|
|
@@ -937,7 +936,7 @@ function parseTableRowAndCellRevisions(
|
|
|
937
936
|
const metadata = readRevisionMetadata(tcPrChange, state, "property-change");
|
|
938
937
|
const innerTcPr = findChildElement(tcPrChange, "tcPr");
|
|
939
938
|
const beforeXml = innerTcPr ? state.documentXml.slice(innerTcPr.start, innerTcPr.end) : "";
|
|
940
|
-
const propertyChangeData: PropertyChangeData = { xmlTag: "
|
|
939
|
+
const propertyChangeData: PropertyChangeData = { xmlTag: "tcPrChange", beforeXml };
|
|
941
940
|
|
|
942
941
|
state.revisions.push(
|
|
943
942
|
createRevisionRecord({
|
|
@@ -951,7 +950,6 @@ function parseTableRowAndCellRevisions(
|
|
|
951
950
|
originalRevisionType: "tcPrChange",
|
|
952
951
|
ooxmlRevisionId: metadata.ooxmlRevisionId,
|
|
953
952
|
propertyChangeData,
|
|
954
|
-
preserveOnlyReason: "Cell property changes remain preserve-only for export safety.",
|
|
955
953
|
},
|
|
956
954
|
}),
|
|
957
955
|
);
|
|
@@ -1148,18 +1146,20 @@ function linkMoveRevisionPairs(state: ParseState): void {
|
|
|
1148
1146
|
if (fromRevision && toRevision) {
|
|
1149
1147
|
fromRevision.metadata.moveData!.linkedRevisionId = toRevision.revisionId;
|
|
1150
1148
|
toRevision.metadata.moveData!.linkedRevisionId = fromRevision.revisionId;
|
|
1149
|
+
removePreserveOnlyMoveDiagnostic(state, fromRevision.revisionId);
|
|
1150
|
+
removePreserveOnlyMoveDiagnostic(state, toRevision.revisionId);
|
|
1151
1151
|
|
|
1152
1152
|
state.diagnostics.push({
|
|
1153
1153
|
revisionId: fromRevision.revisionId,
|
|
1154
1154
|
code: "linked_move_pair",
|
|
1155
|
-
message: `Move-from revision linked to move-to revision ${toRevision.revisionId} via moveId ${moveId}.`,
|
|
1156
|
-
featureClass: "
|
|
1155
|
+
message: `Move-from revision linked to move-to revision ${toRevision.revisionId} via moveId ${moveId}; linked move pairs are actionable.`,
|
|
1156
|
+
featureClass: "supported",
|
|
1157
1157
|
});
|
|
1158
1158
|
state.diagnostics.push({
|
|
1159
1159
|
revisionId: toRevision.revisionId,
|
|
1160
1160
|
code: "linked_move_pair",
|
|
1161
|
-
message: `Move-to revision linked to move-from revision ${fromRevision.revisionId} via moveId ${moveId}.`,
|
|
1162
|
-
featureClass: "
|
|
1161
|
+
message: `Move-to revision linked to move-from revision ${fromRevision.revisionId} via moveId ${moveId}; linked move pairs are actionable.`,
|
|
1162
|
+
featureClass: "supported",
|
|
1163
1163
|
});
|
|
1164
1164
|
} else {
|
|
1165
1165
|
for (const revision of group) {
|
|
@@ -1174,6 +1174,17 @@ function linkMoveRevisionPairs(state: ParseState): void {
|
|
|
1174
1174
|
}
|
|
1175
1175
|
}
|
|
1176
1176
|
|
|
1177
|
+
function removePreserveOnlyMoveDiagnostic(
|
|
1178
|
+
state: ParseState,
|
|
1179
|
+
revisionId: string,
|
|
1180
|
+
): void {
|
|
1181
|
+
state.diagnostics = state.diagnostics.filter(
|
|
1182
|
+
(diagnostic) =>
|
|
1183
|
+
diagnostic.revisionId !== revisionId ||
|
|
1184
|
+
diagnostic.code !== "preserve_only_move_revision",
|
|
1185
|
+
);
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1177
1188
|
function isShallowPropertyChangeNesting(node: XmlElementNode): boolean {
|
|
1178
1189
|
for (const child of node.children) {
|
|
1179
1190
|
if (child.type !== "element") {
|