@beyondwork/docx-react-component 1.0.28 → 1.0.30
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 +26 -37
- package/src/api/public-types.ts +531 -0
- package/src/api/session-state.ts +2 -0
- package/src/core/commands/index.ts +201 -79
- package/src/core/commands/table-structure-commands.ts +138 -5
- package/src/core/state/text-transaction.ts +370 -3
- package/src/index.ts +41 -0
- package/src/io/docx-session.ts +318 -25
- package/src/io/export/serialize-footnotes.ts +41 -46
- package/src/io/export/serialize-headers-footers.ts +36 -40
- package/src/io/export/serialize-main-document.ts +55 -89
- package/src/io/export/serialize-numbering.ts +104 -4
- package/src/io/export/serialize-runtime-revisions.ts +196 -2
- package/src/io/export/split-story-blocks-for-runtime-revisions.ts +252 -0
- package/src/io/export/table-properties-xml.ts +318 -0
- package/src/io/normalize/normalize-text.ts +34 -3
- package/src/io/ooxml/parse-comments.ts +6 -0
- package/src/io/ooxml/parse-footnotes.ts +69 -13
- package/src/io/ooxml/parse-headers-footers.ts +54 -11
- package/src/io/ooxml/parse-main-document.ts +112 -42
- package/src/io/ooxml/parse-numbering.ts +341 -26
- package/src/io/ooxml/parse-revisions.ts +118 -4
- package/src/io/ooxml/parse-styles.ts +176 -0
- package/src/io/ooxml/parse-tables.ts +34 -25
- package/src/io/ooxml/revision-boundaries.ts +127 -3
- package/src/io/ooxml/workflow-payload.ts +544 -0
- package/src/model/canonical-document.ts +91 -1
- package/src/model/snapshot.ts +112 -1
- package/src/preservation/store.ts +73 -3
- package/src/review/store/comment-store.ts +19 -1
- package/src/review/store/revision-actions.ts +29 -0
- package/src/review/store/revision-store.ts +12 -1
- package/src/review/store/revision-types.ts +11 -0
- package/src/runtime/context-analytics.ts +824 -0
- package/src/runtime/document-locations.ts +521 -0
- package/src/runtime/document-navigation.ts +14 -1
- package/src/runtime/document-outline.ts +440 -0
- package/src/runtime/document-runtime.ts +941 -45
- package/src/runtime/event-refresh-hints.ts +137 -0
- package/src/runtime/numbering-prefix.ts +67 -39
- package/src/runtime/page-layout-estimation.ts +100 -7
- package/src/runtime/resolved-numbering-geometry.ts +293 -0
- package/src/runtime/session-capabilities.ts +2 -2
- package/src/runtime/suggestions-snapshot.ts +137 -0
- package/src/runtime/surface-projection.ts +223 -27
- package/src/runtime/table-style-resolver.ts +409 -0
- package/src/runtime/view-state.ts +17 -1
- package/src/runtime/workflow-markup.ts +54 -14
- package/src/ui/WordReviewEditor.tsx +1269 -87
- package/src/ui/editor-command-bag.ts +7 -0
- package/src/ui/editor-runtime-boundary.ts +111 -10
- package/src/ui/editor-shell-view.tsx +17 -15
- package/src/ui/editor-surface-controller.tsx +5 -0
- package/src/ui/headless/selection-tool-context.ts +19 -0
- package/src/ui/headless/selection-tool-resolver.ts +752 -0
- package/src/ui/headless/selection-tool-types.ts +129 -0
- package/src/ui/headless/selection-toolbar-model.ts +10 -33
- package/src/ui/runtime-shortcut-dispatch.ts +365 -0
- package/src/ui-tailwind/chrome/chrome-preset-model.ts +107 -0
- package/src/ui-tailwind/chrome/chrome-preset-toolbar.tsx +15 -0
- package/src/ui-tailwind/chrome/review-queue-bar.tsx +97 -0
- package/src/ui-tailwind/chrome/tw-context-analytics-summary.tsx +122 -0
- package/src/ui-tailwind/chrome/tw-image-context-toolbar.tsx +1 -9
- package/src/ui-tailwind/chrome/tw-object-context-toolbar.tsx +1 -5
- package/src/ui-tailwind/chrome/tw-page-ruler.tsx +8 -29
- package/src/ui-tailwind/chrome/tw-selection-tool-blocked.tsx +23 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-comment.tsx +35 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-formatting.tsx +37 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +298 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-structure.tsx +116 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-suggestion.tsx +29 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-workflow.tsx +27 -0
- package/src/ui-tailwind/chrome/tw-selection-toolbar.tsx +3 -3
- package/src/ui-tailwind/chrome/tw-suggestion-card.tsx +3 -3
- package/src/ui-tailwind/chrome/tw-table-context-toolbar.tsx +86 -14
- package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +57 -52
- package/src/ui-tailwind/editor-surface/pm-decorations.ts +36 -52
- package/src/ui-tailwind/editor-surface/pm-schema.ts +56 -5
- package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +87 -24
- package/src/ui-tailwind/editor-surface/surface-build-keys.ts +4 -0
- package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +135 -32
- package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +74 -7
- package/src/ui-tailwind/review/tw-comment-sidebar.tsx +17 -17
- package/src/ui-tailwind/review/tw-review-rail.tsx +19 -17
- package/src/ui-tailwind/review/tw-revision-sidebar.tsx +10 -10
- package/src/ui-tailwind/status/tw-status-bar.tsx +10 -6
- package/src/ui-tailwind/theme/editor-theme.css +58 -40
- package/src/ui-tailwind/toolbar/tw-toolbar-icon-button.tsx +4 -4
- package/src/ui-tailwind/toolbar/tw-toolbar.tsx +250 -181
- package/src/ui-tailwind/tw-review-workspace.tsx +323 -280
- package/src/validation/compatibility-engine.ts +246 -2
- package/src/validation/docx-comment-proof.ts +24 -11
|
@@ -14,6 +14,7 @@ import type {
|
|
|
14
14
|
} from "../model/canonical-document.ts";
|
|
15
15
|
import {
|
|
16
16
|
describeOpaqueFragment,
|
|
17
|
+
describeStructuredWrapperBlock,
|
|
17
18
|
listOpaqueFragments,
|
|
18
19
|
listPreservedPackageParts,
|
|
19
20
|
} from "../preservation/store.ts";
|
|
@@ -40,6 +41,8 @@ export function buildCompatibilityReport(
|
|
|
40
41
|
}
|
|
41
42
|
const featureEntries: CompatibilityFeatureEntry[] = [
|
|
42
43
|
...contentFeatures,
|
|
44
|
+
...collectStructuredWrapperFeatures(content),
|
|
45
|
+
...collectReviewFeatures(input.document),
|
|
43
46
|
...collectPreservationFeatures(input.document),
|
|
44
47
|
];
|
|
45
48
|
const warnings = dedupeWarnings([
|
|
@@ -69,6 +72,110 @@ function hasSupportedRuntimeComments(
|
|
|
69
72
|
return Object.values(comments).some((comment) => comment.anchor.kind !== "detached");
|
|
70
73
|
}
|
|
71
74
|
|
|
75
|
+
function collectReviewFeatures(
|
|
76
|
+
document: CanonicalDocumentEnvelope,
|
|
77
|
+
): CompatibilityFeatureEntry[] {
|
|
78
|
+
const entries: CompatibilityFeatureEntry[] = [];
|
|
79
|
+
const comments = Object.values(document.review.comments ?? {});
|
|
80
|
+
const revisions = Object.values(document.review.revisions ?? {});
|
|
81
|
+
|
|
82
|
+
const multiParagraphComment = comments.find(
|
|
83
|
+
(comment) => comment.metadata?.detachedReason === "multi-paragraph" && comment.anchor.kind === "detached",
|
|
84
|
+
);
|
|
85
|
+
if (multiParagraphComment?.anchor.kind === "detached") {
|
|
86
|
+
entries.push({
|
|
87
|
+
featureEntryId: "feature:comments-multi-paragraph-ranges",
|
|
88
|
+
featureKey: "comments-multi-paragraph-ranges",
|
|
89
|
+
featureClass: "preserve-only",
|
|
90
|
+
message:
|
|
91
|
+
"Cross-paragraph comment anchors remain visible but detached to preserve package truth and export safety.",
|
|
92
|
+
affectedAnchor: createRangeAnchor(
|
|
93
|
+
multiParagraphComment.anchor.lastKnownRange.from,
|
|
94
|
+
multiParagraphComment.anchor.lastKnownRange.to,
|
|
95
|
+
),
|
|
96
|
+
details: {
|
|
97
|
+
commentId: multiParagraphComment.commentId,
|
|
98
|
+
detachedReason: multiParagraphComment.metadata?.detachedReason,
|
|
99
|
+
actionabilityNote: multiParagraphComment.metadata?.actionabilityNote,
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const moveRevision = revisions.find((revision) => revision.kind === "move");
|
|
105
|
+
if (moveRevision) {
|
|
106
|
+
entries.push({
|
|
107
|
+
featureEntryId: "feature:tracked-moves",
|
|
108
|
+
featureKey: "tracked-moves",
|
|
109
|
+
featureClass: "preserve-only",
|
|
110
|
+
message:
|
|
111
|
+
"Tracked move revisions are preserved for round-trip and review visibility but remain non-actionable in the current runtime.",
|
|
112
|
+
affectedAnchor: toRevisionAffectedAnchor(moveRevision),
|
|
113
|
+
details: {
|
|
114
|
+
revisionId: moveRevision.changeId,
|
|
115
|
+
moveDirection: moveRevision.metadata?.moveData?.direction,
|
|
116
|
+
linkedRevisionId: moveRevision.metadata?.moveData?.linkedRevisionId,
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const formattingRevisions = revisions.filter(
|
|
122
|
+
(revision) =>
|
|
123
|
+
revision.kind === "formatting" ||
|
|
124
|
+
(revision.kind === "property-change" && revision.metadata?.propertyChangeData?.xmlTag === "rPrChange"),
|
|
125
|
+
);
|
|
126
|
+
if (formattingRevisions.length > 0) {
|
|
127
|
+
const featureClass = formattingRevisions.some(
|
|
128
|
+
(revision) => typeof revision.metadata?.preserveOnlyReason === "string" && revision.metadata.preserveOnlyReason.length > 0,
|
|
129
|
+
)
|
|
130
|
+
? "preserve-only"
|
|
131
|
+
: "supported-roundtrip";
|
|
132
|
+
entries.push({
|
|
133
|
+
featureEntryId: "feature:formatting-revisions",
|
|
134
|
+
featureKey: "formatting-revisions",
|
|
135
|
+
featureClass,
|
|
136
|
+
message:
|
|
137
|
+
featureClass === "preserve-only"
|
|
138
|
+
? "Formatting revisions remain visible for review, but at least one formatting-change slice is still preserve-only."
|
|
139
|
+
: "Formatting-change revisions remain structured and round-trip through the runtime review model.",
|
|
140
|
+
affectedAnchor: toRevisionAffectedAnchor(formattingRevisions[0]!),
|
|
141
|
+
details: {
|
|
142
|
+
revisionCount: formattingRevisions.length,
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const structuralRevisions = revisions.filter(
|
|
148
|
+
(revision) =>
|
|
149
|
+
revision.kind === "property-change" &&
|
|
150
|
+
revision.metadata?.propertyChangeData?.xmlTag !== "rPrChange",
|
|
151
|
+
);
|
|
152
|
+
if (structuralRevisions.length > 0) {
|
|
153
|
+
const featureClass = structuralRevisions.some(
|
|
154
|
+
(revision) => typeof revision.metadata?.preserveOnlyReason === "string" && revision.metadata.preserveOnlyReason.length > 0,
|
|
155
|
+
)
|
|
156
|
+
? "preserve-only"
|
|
157
|
+
: "supported-roundtrip";
|
|
158
|
+
entries.push({
|
|
159
|
+
featureEntryId: "feature:structural-revisions",
|
|
160
|
+
featureKey: "structural-revisions",
|
|
161
|
+
featureClass,
|
|
162
|
+
message:
|
|
163
|
+
featureClass === "preserve-only"
|
|
164
|
+
? "Structural property revisions are preserved for round-trip, but at least one slice remains non-actionable."
|
|
165
|
+
: "Structured paragraph, table, or section property revisions remain mapped in the runtime review model.",
|
|
166
|
+
affectedAnchor: toRevisionAffectedAnchor(structuralRevisions[0]!),
|
|
167
|
+
details: {
|
|
168
|
+
revisionCount: structuralRevisions.length,
|
|
169
|
+
revisionKinds: structuralRevisions.map(
|
|
170
|
+
(revision) => revision.metadata?.propertyChangeData?.xmlTag ?? revision.kind,
|
|
171
|
+
),
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return entries;
|
|
177
|
+
}
|
|
178
|
+
|
|
72
179
|
function normalizeDocumentRoot(content: unknown): DocumentRootNode {
|
|
73
180
|
if (content && typeof content === "object" && (content as { type?: string }).type === "doc") {
|
|
74
181
|
return content as DocumentRootNode;
|
|
@@ -105,6 +212,7 @@ function collectContentFeatures(
|
|
|
105
212
|
hyperlinks: false,
|
|
106
213
|
images: false,
|
|
107
214
|
tables: false,
|
|
215
|
+
mergedCells: false,
|
|
108
216
|
sections: false,
|
|
109
217
|
contentControls: false,
|
|
110
218
|
};
|
|
@@ -139,7 +247,15 @@ function collectContentFeatures(
|
|
|
139
247
|
entries.push(
|
|
140
248
|
supportedEntry(
|
|
141
249
|
"tables",
|
|
142
|
-
"Structured tables keep
|
|
250
|
+
"Structured tables keep bounded topology and common visual properties through runtime editing and export.",
|
|
251
|
+
),
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
if (flags.mergedCells) {
|
|
255
|
+
entries.push(
|
|
256
|
+
supportedEntry(
|
|
257
|
+
"merged-cells",
|
|
258
|
+
"Merged-cell topology survives through the supported table runtime and export path.",
|
|
143
259
|
),
|
|
144
260
|
);
|
|
145
261
|
}
|
|
@@ -173,6 +289,7 @@ function measureBlock(
|
|
|
173
289
|
hyperlinks: boolean;
|
|
174
290
|
images: boolean;
|
|
175
291
|
tables: boolean;
|
|
292
|
+
mergedCells: boolean;
|
|
176
293
|
sections: boolean;
|
|
177
294
|
contentControls: boolean;
|
|
178
295
|
},
|
|
@@ -189,6 +306,13 @@ function measureBlock(
|
|
|
189
306
|
return measureParagraph(block, flags);
|
|
190
307
|
case "table":
|
|
191
308
|
flags.tables = true;
|
|
309
|
+
if (
|
|
310
|
+
block.rows.some((row) =>
|
|
311
|
+
row.cells.some((cell) => (cell.gridSpan ?? 1) > 1 || cell.verticalMerge != null),
|
|
312
|
+
)
|
|
313
|
+
) {
|
|
314
|
+
flags.mergedCells = true;
|
|
315
|
+
}
|
|
192
316
|
return block.rows.reduce(
|
|
193
317
|
(size, row) =>
|
|
194
318
|
size +
|
|
@@ -200,10 +324,15 @@ function measureBlock(
|
|
|
200
324
|
0,
|
|
201
325
|
);
|
|
202
326
|
case "sdt":
|
|
327
|
+
if (describeStructuredWrapperBlock(block)?.featureKey === "content-controls") {
|
|
328
|
+
return 1;
|
|
329
|
+
}
|
|
203
330
|
flags.contentControls = true;
|
|
204
331
|
return block.children.reduce((size, child) => size + measureBlock(child, flags), 0);
|
|
205
332
|
case "custom_xml":
|
|
206
|
-
return
|
|
333
|
+
return 1;
|
|
334
|
+
case "alt_chunk":
|
|
335
|
+
return 1;
|
|
207
336
|
case "section_break":
|
|
208
337
|
flags.sections = true;
|
|
209
338
|
return 1;
|
|
@@ -212,6 +341,54 @@ function measureBlock(
|
|
|
212
341
|
}
|
|
213
342
|
}
|
|
214
343
|
|
|
344
|
+
function collectStructuredWrapperFeatures(
|
|
345
|
+
content: DocumentRootNode,
|
|
346
|
+
): CompatibilityFeatureEntry[] {
|
|
347
|
+
const entries: CompatibilityFeatureEntry[] = [];
|
|
348
|
+
let structuredWrapperIndex = 0;
|
|
349
|
+
|
|
350
|
+
function visitBlock(block: BlockNode): void {
|
|
351
|
+
const descriptor = describeStructuredWrapperBlock(block);
|
|
352
|
+
if (descriptor) {
|
|
353
|
+
entries.push({
|
|
354
|
+
featureEntryId: `feature:structured-wrapper:${structuredWrapperIndex}`,
|
|
355
|
+
featureKey: descriptor.featureKey,
|
|
356
|
+
featureClass: "preserve-only",
|
|
357
|
+
message: descriptor.label,
|
|
358
|
+
details: {
|
|
359
|
+
detail: descriptor.detail,
|
|
360
|
+
surface: "structured-wrapper",
|
|
361
|
+
},
|
|
362
|
+
});
|
|
363
|
+
structuredWrapperIndex += 1;
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if (block.type === "table") {
|
|
368
|
+
for (const row of block.rows) {
|
|
369
|
+
for (const cell of row.cells) {
|
|
370
|
+
for (const child of cell.children) {
|
|
371
|
+
visitBlock(child);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
if (block.type === "sdt") {
|
|
379
|
+
for (const child of block.children) {
|
|
380
|
+
visitBlock(child);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
for (const block of content.children) {
|
|
386
|
+
visitBlock(block);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
return entries;
|
|
390
|
+
}
|
|
391
|
+
|
|
215
392
|
function measureParagraph(
|
|
216
393
|
paragraph: ParagraphNode,
|
|
217
394
|
flags: {
|
|
@@ -381,6 +558,16 @@ function collectSubPartFeatures(
|
|
|
381
558
|
const noteCount =
|
|
382
559
|
Object.keys(subParts.footnoteCollection?.footnotes ?? {}).length +
|
|
383
560
|
Object.keys(subParts.footnoteCollection?.endnotes ?? {}).length;
|
|
561
|
+
const headerFooterBookmarkCount =
|
|
562
|
+
[...(subParts.headers ?? []), ...(subParts.footers ?? [])].reduce(
|
|
563
|
+
(count, subPart) => count + countBookmarksInBlocks(subPart.blocks),
|
|
564
|
+
0,
|
|
565
|
+
);
|
|
566
|
+
const noteBookmarkCount =
|
|
567
|
+
[
|
|
568
|
+
...Object.values(subParts.footnoteCollection?.footnotes ?? {}),
|
|
569
|
+
...Object.values(subParts.footnoteCollection?.endnotes ?? {}),
|
|
570
|
+
].reduce((count, note) => count + countBookmarksInBlocks(note.blocks), 0);
|
|
384
571
|
|
|
385
572
|
if (hasHeaderFooterContent && !entries.some((entry) => entry.featureKey === "headers-footers-lossy")) {
|
|
386
573
|
entries.push({
|
|
@@ -391,6 +578,7 @@ function collectSubPartFeatures(
|
|
|
391
578
|
details: {
|
|
392
579
|
headerCount: subParts.headers?.length ?? 0,
|
|
393
580
|
footerCount: subParts.footers?.length ?? 0,
|
|
581
|
+
bookmarkCount: headerFooterBookmarkCount,
|
|
394
582
|
},
|
|
395
583
|
});
|
|
396
584
|
}
|
|
@@ -404,6 +592,7 @@ function collectSubPartFeatures(
|
|
|
404
592
|
details: {
|
|
405
593
|
footnoteCount: Object.keys(subParts.footnoteCollection?.footnotes ?? {}).length,
|
|
406
594
|
endnoteCount: Object.keys(subParts.footnoteCollection?.endnotes ?? {}).length,
|
|
595
|
+
bookmarkCount: noteBookmarkCount,
|
|
407
596
|
},
|
|
408
597
|
});
|
|
409
598
|
}
|
|
@@ -472,6 +661,45 @@ function collectLossySubPartFeatures(
|
|
|
472
661
|
return entries;
|
|
473
662
|
}
|
|
474
663
|
|
|
664
|
+
function countBookmarksInBlocks(blocks: readonly BlockNode[]): number {
|
|
665
|
+
return blocks.reduce((count, block) => count + countBookmarksInBlock(block), 0);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
function countBookmarksInBlock(block: BlockNode): number {
|
|
669
|
+
switch (block.type) {
|
|
670
|
+
case "paragraph":
|
|
671
|
+
return (block.children ?? []).reduce((count, child) => count + countBookmarksInInlineNode(child), 0);
|
|
672
|
+
case "table":
|
|
673
|
+
return block.rows.reduce(
|
|
674
|
+
(count, row) =>
|
|
675
|
+
count +
|
|
676
|
+
row.cells.reduce(
|
|
677
|
+
(cellCount, cell) =>
|
|
678
|
+
cellCount + cell.children.reduce((childCount, child) => childCount + countBookmarksInBlock(child), 0),
|
|
679
|
+
0,
|
|
680
|
+
),
|
|
681
|
+
0,
|
|
682
|
+
);
|
|
683
|
+
case "sdt":
|
|
684
|
+
case "custom_xml":
|
|
685
|
+
return block.children.reduce((count, child) => count + countBookmarksInBlock(child), 0);
|
|
686
|
+
default:
|
|
687
|
+
return 0;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
function countBookmarksInInlineNode(node: InlineNode): number {
|
|
692
|
+
switch (node.type) {
|
|
693
|
+
case "bookmark_start":
|
|
694
|
+
return 1;
|
|
695
|
+
case "hyperlink":
|
|
696
|
+
case "field":
|
|
697
|
+
return (node.children ?? []).reduce((count, child) => count + countBookmarksInInlineNode(child), 0);
|
|
698
|
+
default:
|
|
699
|
+
return 0;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
475
703
|
function collectLossyBlocks(
|
|
476
704
|
blocks: readonly BlockNode[],
|
|
477
705
|
surface: string,
|
|
@@ -613,6 +841,22 @@ function supportedEntry(
|
|
|
613
841
|
};
|
|
614
842
|
}
|
|
615
843
|
|
|
844
|
+
function toRevisionAffectedAnchor(
|
|
845
|
+
revision: CanonicalDocumentEnvelope["review"]["revisions"][string],
|
|
846
|
+
) {
|
|
847
|
+
switch (revision.anchor.kind) {
|
|
848
|
+
case "range":
|
|
849
|
+
return createRangeAnchor(revision.anchor.range.from, revision.anchor.range.to);
|
|
850
|
+
case "node":
|
|
851
|
+
return createRangeAnchor(revision.anchor.at, revision.anchor.at + 1);
|
|
852
|
+
case "detached":
|
|
853
|
+
return createRangeAnchor(
|
|
854
|
+
revision.anchor.lastKnownRange.from,
|
|
855
|
+
revision.anchor.lastKnownRange.to,
|
|
856
|
+
);
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
|
|
616
860
|
function dedupeWarnings(warnings: EditorWarning[]): EditorWarning[] {
|
|
617
861
|
const byId = new Map<string, EditorWarning>();
|
|
618
862
|
|
|
@@ -26,18 +26,31 @@ export interface ClosureValidationContext {
|
|
|
26
26
|
harnessShowcase?: HarnessShowcaseValidationContext;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
export const HARNESS_SHOWCASE_AREAS = [
|
|
30
|
+
"workflow-overlay",
|
|
31
|
+
"blocked-commands",
|
|
32
|
+
"preserve-only",
|
|
33
|
+
"search-candidates",
|
|
34
|
+
"right-rail",
|
|
35
|
+
"multi-scope",
|
|
36
|
+
"public-api",
|
|
37
|
+
"sidebar-integration",
|
|
38
|
+
"policy-yaml",
|
|
39
|
+
"harness-lifecycle",
|
|
40
|
+
"export-continuity",
|
|
41
|
+
"main-story-text",
|
|
42
|
+
"paragraph-structure",
|
|
43
|
+
"secondary-story-text",
|
|
44
|
+
"formatting-property-list",
|
|
45
|
+
"table-field-slices",
|
|
46
|
+
"fail-closed-boundaries",
|
|
47
|
+
"media-section-fail-closed",
|
|
48
|
+
"continuity-proof",
|
|
49
|
+
"harness-suggestion-telemetry",
|
|
50
|
+
] as const;
|
|
51
|
+
|
|
29
52
|
export type HarnessShowcaseArea =
|
|
30
|
-
|
|
31
|
-
| "blocked-commands"
|
|
32
|
-
| "preserve-only"
|
|
33
|
-
| "search-candidates"
|
|
34
|
-
| "right-rail"
|
|
35
|
-
| "multi-scope"
|
|
36
|
-
| "public-api"
|
|
37
|
-
| "sidebar-integration"
|
|
38
|
-
| "policy-yaml"
|
|
39
|
-
| "harness-lifecycle"
|
|
40
|
-
| "export-continuity";
|
|
53
|
+
(typeof HARNESS_SHOWCASE_AREAS)[number];
|
|
41
54
|
|
|
42
55
|
export interface HarnessShowcaseAreaProof {
|
|
43
56
|
demonstrated: boolean;
|