@beyondwork/docx-react-component 1.0.18 → 1.0.20
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/README.md +8 -2
- package/package.json +24 -34
- package/src/api/README.md +5 -1
- package/src/api/public-types.ts +710 -4
- package/src/api/session-state.ts +60 -0
- package/src/core/commands/formatting-commands.ts +2 -1
- package/src/core/commands/image-commands.ts +147 -0
- package/src/core/commands/index.ts +19 -3
- package/src/core/commands/list-commands.ts +231 -36
- package/src/core/commands/paragraph-layout-commands.ts +339 -0
- package/src/core/commands/section-layout-commands.ts +680 -0
- package/src/core/commands/style-commands.ts +262 -0
- package/src/core/search/search-text.ts +357 -0
- package/src/core/selection/mapping.ts +41 -0
- package/src/core/state/editor-state.ts +4 -1
- package/src/index.ts +51 -0
- package/src/io/docx-session.ts +623 -56
- package/src/io/export/serialize-comments.ts +104 -34
- package/src/io/export/serialize-footnotes.ts +198 -1
- package/src/io/export/serialize-headers-footers.ts +203 -10
- package/src/io/export/serialize-main-document.ts +285 -8
- package/src/io/export/serialize-numbering.ts +28 -7
- package/src/io/export/split-review-boundaries.ts +181 -19
- package/src/io/normalize/normalize-text.ts +144 -32
- package/src/io/ooxml/highlight-colors.ts +39 -0
- package/src/io/ooxml/numbering-sentinels.ts +44 -0
- package/src/io/ooxml/parse-comments.ts +85 -19
- package/src/io/ooxml/parse-fields.ts +396 -0
- package/src/io/ooxml/parse-footnotes.ts +452 -22
- package/src/io/ooxml/parse-headers-footers.ts +657 -29
- package/src/io/ooxml/parse-inline-media.ts +30 -0
- package/src/io/ooxml/parse-main-document.ts +807 -20
- package/src/io/ooxml/parse-numbering.ts +7 -0
- package/src/io/ooxml/parse-revisions.ts +317 -38
- package/src/io/ooxml/parse-settings.ts +184 -0
- package/src/io/ooxml/parse-shapes.ts +25 -0
- package/src/io/ooxml/parse-styles.ts +463 -0
- package/src/io/ooxml/parse-theme.ts +32 -0
- package/src/legal/bookmarks.ts +44 -0
- package/src/legal/cross-references.ts +59 -1
- package/src/model/canonical-document.ts +250 -4
- package/src/model/cds-1.0.0.ts +13 -0
- package/src/model/snapshot.ts +87 -2
- package/src/review/store/revision-store.ts +6 -0
- package/src/review/store/revision-types.ts +1 -0
- package/src/runtime/document-layout.ts +332 -0
- package/src/runtime/document-navigation.ts +603 -0
- package/src/runtime/document-runtime.ts +1754 -78
- package/src/runtime/document-search.ts +145 -0
- package/src/runtime/numbering-prefix.ts +47 -26
- package/src/runtime/page-layout-estimation.ts +212 -0
- package/src/runtime/read-only-diagnostics-runtime.ts +9 -0
- package/src/runtime/session-capabilities.ts +35 -3
- package/src/runtime/story-context.ts +164 -0
- package/src/runtime/story-targeting.ts +162 -0
- package/src/runtime/surface-projection.ts +324 -36
- package/src/runtime/table-schema.ts +89 -7
- package/src/runtime/view-state.ts +477 -0
- package/src/runtime/workflow-markup.ts +349 -0
- package/src/ui/WordReviewEditor.tsx +2469 -1344
- package/src/ui/browser-export.ts +52 -0
- package/src/ui/editor-command-bag.ts +120 -0
- package/src/ui/editor-runtime-boundary.ts +1422 -0
- package/src/ui/editor-shell-view.tsx +134 -0
- package/src/ui/editor-surface-controller.tsx +51 -0
- package/src/ui/headless/preserve-editor-selection.ts +5 -0
- package/src/ui/headless/revision-decoration-model.ts +4 -4
- package/src/ui/headless/selection-helpers.ts +20 -0
- package/src/ui/headless/selection-toolbar-model.ts +22 -0
- package/src/ui/headless/use-editor-keyboard.ts +6 -1
- package/src/ui/runtime-snapshot-selectors.ts +197 -0
- package/src/ui-tailwind/chrome/tw-alert-banner.tsx +18 -2
- package/src/ui-tailwind/chrome/tw-image-context-toolbar.tsx +129 -0
- package/src/ui-tailwind/chrome/tw-layout-panel.tsx +114 -0
- package/src/ui-tailwind/chrome/tw-object-context-toolbar.tsx +34 -0
- package/src/ui-tailwind/chrome/tw-page-ruler.tsx +386 -0
- package/src/ui-tailwind/chrome/tw-selection-toolbar.tsx +150 -14
- package/src/ui-tailwind/chrome/tw-table-context-toolbar.tsx +128 -0
- package/src/ui-tailwind/editor-surface/perf-probe.ts +179 -0
- package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +46 -7
- package/src/ui-tailwind/editor-surface/pm-contextual-ui.ts +31 -0
- package/src/ui-tailwind/editor-surface/pm-decorations.ts +35 -0
- package/src/ui-tailwind/editor-surface/pm-position-map.ts +3 -3
- package/src/ui-tailwind/editor-surface/pm-schema.ts +186 -13
- package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +191 -68
- package/src/ui-tailwind/editor-surface/search-plugin.ts +19 -68
- package/src/ui-tailwind/editor-surface/surface-build-keys.ts +51 -0
- package/src/ui-tailwind/editor-surface/tw-inline-token.tsx +11 -0
- package/src/ui-tailwind/editor-surface/tw-opaque-block.tsx +7 -1
- package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +528 -85
- package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +0 -1
- package/src/ui-tailwind/index.ts +2 -1
- package/src/ui-tailwind/page-chrome-model.ts +27 -0
- package/src/ui-tailwind/review/tw-comment-sidebar.tsx +277 -147
- package/src/ui-tailwind/review/tw-health-panel.tsx +31 -2
- package/src/ui-tailwind/review/tw-review-rail.tsx +8 -8
- package/src/ui-tailwind/review/tw-revision-sidebar.tsx +15 -15
- package/src/ui-tailwind/theme/editor-theme.css +127 -0
- package/src/ui-tailwind/toolbar/tw-toolbar-icon-button.tsx +4 -0
- package/src/ui-tailwind/toolbar/tw-toolbar.tsx +829 -12
- package/src/ui-tailwind/tw-review-workspace.tsx +1238 -42
- package/src/validation/compatibility-engine.ts +119 -24
- package/src/validation/compatibility-report.ts +1 -0
- package/src/validation/diagnostics.ts +1 -0
- package/src/validation/docx-comment-proof.ts +707 -0
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
expectExactString,
|
|
9
9
|
expectIso8601UtcTimestamp,
|
|
10
10
|
expectString,
|
|
11
|
+
expectStringAllowEmpty,
|
|
11
12
|
expectUuid,
|
|
12
13
|
stableStringify,
|
|
13
14
|
} from "./cds-1.0.0.ts";
|
|
@@ -27,7 +28,7 @@ const CANONICAL_DOCUMENT_TOP_LEVEL_KEYS = [
|
|
|
27
28
|
"diagnostics",
|
|
28
29
|
] as const;
|
|
29
30
|
|
|
30
|
-
const CANONICAL_DOCUMENT_OPTIONAL_KEYS = ["subParts"] as const;
|
|
31
|
+
const CANONICAL_DOCUMENT_OPTIONAL_KEYS = ["subParts", "fieldRegistry"] as const;
|
|
31
32
|
|
|
32
33
|
const ID_PATTERNS = {
|
|
33
34
|
styleId: /^[A-Za-z_][A-Za-z0-9._-]{0,127}$/,
|
|
@@ -61,6 +62,8 @@ export interface CanonicalDocument {
|
|
|
61
62
|
preservation: PreservationStore;
|
|
62
63
|
diagnostics: DiagnosticStore;
|
|
63
64
|
subParts?: SubPartsCatalog;
|
|
65
|
+
/** Package-backed field registry for supported field families. */
|
|
66
|
+
fieldRegistry?: FieldRegistry;
|
|
64
67
|
}
|
|
65
68
|
|
|
66
69
|
export interface DocumentMetadata {
|
|
@@ -79,12 +82,14 @@ export interface StylesCatalog {
|
|
|
79
82
|
characters: Record<string, CharacterStyleDefinition>;
|
|
80
83
|
tables: Record<string, TableStyleDefinition>;
|
|
81
84
|
latentStyles?: Record<string, LatentStyleDefinition>;
|
|
85
|
+
fromPackage?: boolean;
|
|
82
86
|
}
|
|
83
87
|
|
|
84
88
|
export interface ParagraphStyleDefinition {
|
|
85
89
|
styleId: string;
|
|
86
90
|
basedOn?: string;
|
|
87
91
|
nextStyle?: string;
|
|
92
|
+
outlineLevel?: number;
|
|
88
93
|
displayName: string;
|
|
89
94
|
kind: "paragraph";
|
|
90
95
|
isDefault: boolean;
|
|
@@ -131,6 +136,8 @@ export interface NumberingLevelDefinition {
|
|
|
131
136
|
text: string;
|
|
132
137
|
startAt?: number;
|
|
133
138
|
paragraphStyleId?: string;
|
|
139
|
+
isLegalNumbering?: boolean;
|
|
140
|
+
suffix?: "tab" | "space" | "nothing";
|
|
134
141
|
}
|
|
135
142
|
|
|
136
143
|
export interface NumberingInstance {
|
|
@@ -155,6 +162,9 @@ export interface MediaItem {
|
|
|
155
162
|
relationshipId?: string;
|
|
156
163
|
packagePartName: string;
|
|
157
164
|
altText?: string;
|
|
165
|
+
display?: "inline" | "floating";
|
|
166
|
+
widthEmu?: number;
|
|
167
|
+
heightEmu?: number;
|
|
158
168
|
}
|
|
159
169
|
|
|
160
170
|
// ---- Sub-part canonical types ----
|
|
@@ -166,6 +176,7 @@ export interface HeaderDocument {
|
|
|
166
176
|
partPath: string;
|
|
167
177
|
relationshipId: string;
|
|
168
178
|
blocks: BlockNode[];
|
|
179
|
+
sectionIndex?: number;
|
|
169
180
|
}
|
|
170
181
|
|
|
171
182
|
export interface FooterDocument {
|
|
@@ -173,6 +184,7 @@ export interface FooterDocument {
|
|
|
173
184
|
partPath: string;
|
|
174
185
|
relationshipId: string;
|
|
175
186
|
blocks: BlockNode[];
|
|
187
|
+
sectionIndex?: number;
|
|
176
188
|
}
|
|
177
189
|
|
|
178
190
|
export interface FootnoteDefinition {
|
|
@@ -203,11 +215,25 @@ export interface ThemeDefinition {
|
|
|
203
215
|
fontScheme?: ThemeFontScheme;
|
|
204
216
|
}
|
|
205
217
|
|
|
218
|
+
export interface DocumentSettings {
|
|
219
|
+
evenAndOddHeaders?: boolean;
|
|
220
|
+
zoomLevel?: "pageWidth" | "onePage" | number;
|
|
221
|
+
}
|
|
222
|
+
|
|
206
223
|
export interface SubPartsCatalog {
|
|
207
224
|
headers: HeaderDocument[];
|
|
208
225
|
footers: FooterDocument[];
|
|
209
226
|
footnoteCollection?: FootnoteCollection;
|
|
210
227
|
theme?: ThemeDefinition;
|
|
228
|
+
finalSectionProperties?: SectionProperties;
|
|
229
|
+
resolvedTheme?: ResolvedTheme;
|
|
230
|
+
settings?: DocumentSettings;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export interface ResolvedTheme {
|
|
234
|
+
colors: Record<string, string>;
|
|
235
|
+
majorFont?: string;
|
|
236
|
+
minorFont?: string;
|
|
211
237
|
}
|
|
212
238
|
|
|
213
239
|
// ---- Inline footnote reference node ----
|
|
@@ -305,6 +331,7 @@ export interface ParagraphNode {
|
|
|
305
331
|
};
|
|
306
332
|
alignment?: "left" | "center" | "right" | "both" | "distribute";
|
|
307
333
|
spacing?: ParagraphSpacing;
|
|
334
|
+
contextualSpacing?: boolean;
|
|
308
335
|
indentation?: ParagraphIndentation;
|
|
309
336
|
tabStops?: TabStop[];
|
|
310
337
|
keepNext?: boolean;
|
|
@@ -407,6 +434,23 @@ export interface TableCellNode {
|
|
|
407
434
|
verticalAlign?: "top" | "center" | "bottom";
|
|
408
435
|
}
|
|
409
436
|
|
|
437
|
+
export interface SdtCheckboxState {
|
|
438
|
+
checked: boolean;
|
|
439
|
+
checkedChar?: string;
|
|
440
|
+
uncheckedChar?: string;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
export interface SdtDatePickerState {
|
|
444
|
+
fullDate?: string;
|
|
445
|
+
dateFormat?: string;
|
|
446
|
+
lid?: string;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
export interface SdtDropdownListItem {
|
|
450
|
+
displayText?: string;
|
|
451
|
+
value: string;
|
|
452
|
+
}
|
|
453
|
+
|
|
410
454
|
export interface SdtNode {
|
|
411
455
|
type: "sdt";
|
|
412
456
|
properties: {
|
|
@@ -415,6 +459,11 @@ export interface SdtNode {
|
|
|
415
459
|
tag?: string;
|
|
416
460
|
lock?: string;
|
|
417
461
|
propertiesXml?: string;
|
|
462
|
+
checkbox?: SdtCheckboxState;
|
|
463
|
+
datePicker?: SdtDatePickerState;
|
|
464
|
+
dropdownList?: SdtDropdownListItem[];
|
|
465
|
+
comboBox?: SdtDropdownListItem[];
|
|
466
|
+
showingPlcHdr?: boolean;
|
|
418
467
|
};
|
|
419
468
|
children: BlockNode[];
|
|
420
469
|
}
|
|
@@ -431,11 +480,119 @@ export interface AltChunkNode {
|
|
|
431
480
|
relationshipId: string;
|
|
432
481
|
}
|
|
433
482
|
|
|
483
|
+
/**
|
|
484
|
+
* Supported field families that receive first-class canonical treatment.
|
|
485
|
+
* These families have stable registry IDs, dependency metadata, and
|
|
486
|
+
* runtime-owned refresh behavior.
|
|
487
|
+
*/
|
|
488
|
+
export type SupportedFieldFamily = "REF" | "PAGEREF" | "NOTEREF" | "TOC";
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Unsupported field families that remain preserve-only.
|
|
492
|
+
* They survive round-trip but do not participate in runtime refresh.
|
|
493
|
+
*/
|
|
494
|
+
export type PreserveOnlyFieldFamily =
|
|
495
|
+
| "PAGE"
|
|
496
|
+
| "NUMPAGES"
|
|
497
|
+
| "DATE"
|
|
498
|
+
| "TIME"
|
|
499
|
+
| "AUTHOR"
|
|
500
|
+
| "FILENAME"
|
|
501
|
+
| "MERGEFIELD"
|
|
502
|
+
| "IF"
|
|
503
|
+
| "SEQ"
|
|
504
|
+
| "INDEX"
|
|
505
|
+
| "TC"
|
|
506
|
+
| "STYLEREF"
|
|
507
|
+
| "FORMULA"
|
|
508
|
+
| "UNKNOWN";
|
|
509
|
+
|
|
510
|
+
export type FieldFamily = SupportedFieldFamily | PreserveOnlyFieldFamily;
|
|
511
|
+
|
|
512
|
+
/** Runtime refresh status for a field instance. */
|
|
513
|
+
export type FieldRefreshStatus =
|
|
514
|
+
| "current"
|
|
515
|
+
| "stale"
|
|
516
|
+
| "unresolvable"
|
|
517
|
+
| "preserve-only";
|
|
518
|
+
|
|
434
519
|
export interface FieldNode {
|
|
435
520
|
type: "field";
|
|
436
521
|
fieldType: "simple" | "complex";
|
|
437
522
|
instruction: string;
|
|
438
523
|
children: InlineNode[];
|
|
524
|
+
/** Classified field family. Undefined for legacy snapshots. */
|
|
525
|
+
fieldFamily?: FieldFamily;
|
|
526
|
+
/** Target bookmark name for REF/PAGEREF/NOTEREF fields. */
|
|
527
|
+
fieldTarget?: string;
|
|
528
|
+
/** Runtime refresh status. Undefined for legacy or preserve-only fields. */
|
|
529
|
+
refreshStatus?: FieldRefreshStatus;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// ─── Field registry ─────────────────────────────────────────────────────────
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Package-backed field registry that catalogs every field instance in the
|
|
536
|
+
* document, grouped by supported vs preserve-only families.
|
|
537
|
+
*
|
|
538
|
+
* Supported field entries carry dependency metadata (bookmark targets) and
|
|
539
|
+
* participate in deterministic refresh. Preserve-only entries survive
|
|
540
|
+
* round-trip but are not refreshable.
|
|
541
|
+
*/
|
|
542
|
+
export interface FieldRegistry {
|
|
543
|
+
/** Supported field instances that participate in refresh. */
|
|
544
|
+
supported: FieldRegistryEntry[];
|
|
545
|
+
/** Preserve-only field instances cataloged for round-trip safety. */
|
|
546
|
+
preserveOnly: FieldRegistryEntry[];
|
|
547
|
+
/** Generated TOC structure extracted from heading-driven TOC fields. */
|
|
548
|
+
tocStructure?: TocStructure;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
export interface FieldRegistryEntry {
|
|
552
|
+
/** Stable document-order index of this field (0-based). */
|
|
553
|
+
fieldIndex: number;
|
|
554
|
+
/** Classified field family. */
|
|
555
|
+
fieldFamily: FieldFamily;
|
|
556
|
+
/** Whether the field is in the supported refresh slice. */
|
|
557
|
+
supported: boolean;
|
|
558
|
+
/** Field instruction text. */
|
|
559
|
+
instruction: string;
|
|
560
|
+
/** Target bookmark name for REF/PAGEREF/NOTEREF fields. */
|
|
561
|
+
fieldTarget?: string;
|
|
562
|
+
/** Current display text extracted from field content. */
|
|
563
|
+
displayText: string;
|
|
564
|
+
/** Paragraph index in document order where this field appears. */
|
|
565
|
+
paragraphIndex: number;
|
|
566
|
+
/** Runtime refresh status. */
|
|
567
|
+
refreshStatus: FieldRefreshStatus;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* Generated table-of-contents structure extracted from TOC fields and
|
|
572
|
+
* heading-styled paragraphs in the document.
|
|
573
|
+
*/
|
|
574
|
+
export interface TocStructure {
|
|
575
|
+
/** The raw TOC field instruction (e.g. "TOC \\o \"1-3\" \\h"). */
|
|
576
|
+
instruction: string;
|
|
577
|
+
/** Heading level range the TOC covers. */
|
|
578
|
+
levelRange: { from: number; to: number };
|
|
579
|
+
/** Ordered TOC entries derived from heading paragraphs. */
|
|
580
|
+
entries: TocEntry[];
|
|
581
|
+
/** Whether the TOC content is current with the heading structure. */
|
|
582
|
+
status: "current" | "stale";
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
export interface TocEntry {
|
|
586
|
+
/** Heading text. */
|
|
587
|
+
text: string;
|
|
588
|
+
/** Heading outline level (1-9). */
|
|
589
|
+
level: number;
|
|
590
|
+
/** Paragraph index of the heading in document order. */
|
|
591
|
+
paragraphIndex: number;
|
|
592
|
+
/** Style ID of the heading paragraph, if available. */
|
|
593
|
+
styleId?: string;
|
|
594
|
+
/** Bookmark name anchoring this heading, if present. */
|
|
595
|
+
bookmarkName?: string;
|
|
439
596
|
}
|
|
440
597
|
|
|
441
598
|
export interface BookmarkStartNode {
|
|
@@ -451,7 +608,86 @@ export interface BookmarkEndNode {
|
|
|
451
608
|
|
|
452
609
|
export interface SectionBreakNode {
|
|
453
610
|
type: "section_break";
|
|
611
|
+
sectionPropertiesXml?: string;
|
|
612
|
+
/**
|
|
613
|
+
* @deprecated Legacy field from older snapshots. New exports should use
|
|
614
|
+
* sectionPropertiesXml and only contain raw <w:sectPr> content.
|
|
615
|
+
*/
|
|
454
616
|
propertiesXml?: string;
|
|
617
|
+
sectionProperties?: SectionProperties;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
export interface SectionProperties {
|
|
621
|
+
pageSize?: PageSize;
|
|
622
|
+
pageMargins?: PageMargins;
|
|
623
|
+
columns?: ColumnProperties;
|
|
624
|
+
pageNumbering?: PageNumbering;
|
|
625
|
+
lineNumbering?: SectionLineNumbering;
|
|
626
|
+
pageBorders?: SectionPageBorders;
|
|
627
|
+
documentGrid?: SectionDocumentGrid;
|
|
628
|
+
headerReferences?: HeaderFooterReference[];
|
|
629
|
+
footerReferences?: HeaderFooterReference[];
|
|
630
|
+
sectionType?: "continuous" | "nextPage" | "evenPage" | "oddPage" | "nextColumn";
|
|
631
|
+
titlePage?: boolean;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
export interface PageSize {
|
|
635
|
+
width: number;
|
|
636
|
+
height: number;
|
|
637
|
+
orientation?: "portrait" | "landscape";
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
export interface PageMargins {
|
|
641
|
+
top: number;
|
|
642
|
+
right: number;
|
|
643
|
+
bottom: number;
|
|
644
|
+
left: number;
|
|
645
|
+
header?: number;
|
|
646
|
+
footer?: number;
|
|
647
|
+
gutter?: number;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
export interface ColumnProperties {
|
|
651
|
+
count?: number;
|
|
652
|
+
space?: number;
|
|
653
|
+
equalWidth?: boolean;
|
|
654
|
+
columns?: Array<{ width: number; space?: number }>;
|
|
655
|
+
separator?: boolean;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
export interface PageNumbering {
|
|
659
|
+
format?: string;
|
|
660
|
+
start?: number;
|
|
661
|
+
chapStyle?: string;
|
|
662
|
+
chapSep?: string;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
export interface SectionLineNumbering {
|
|
666
|
+
countBy?: number;
|
|
667
|
+
start?: number;
|
|
668
|
+
distance?: number;
|
|
669
|
+
restart?: "newPage" | "newSection" | "continuous";
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
export interface SectionPageBorders {
|
|
673
|
+
top?: BorderSpec;
|
|
674
|
+
left?: BorderSpec;
|
|
675
|
+
bottom?: BorderSpec;
|
|
676
|
+
right?: BorderSpec;
|
|
677
|
+
offsetFrom?: "page" | "text";
|
|
678
|
+
display?: "allPages" | "firstPage" | "notFirstPage";
|
|
679
|
+
zOrder?: "front" | "back";
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
export interface SectionDocumentGrid {
|
|
683
|
+
type?: "default" | "lines" | "linesAndChars" | "snapToChars";
|
|
684
|
+
linePitch?: number;
|
|
685
|
+
charSpace?: number;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
export interface HeaderFooterReference {
|
|
689
|
+
variant: HeaderFooterVariant;
|
|
690
|
+
relationshipId: string;
|
|
455
691
|
}
|
|
456
692
|
|
|
457
693
|
export type InlineNode =
|
|
@@ -487,6 +723,7 @@ export type TextMark =
|
|
|
487
723
|
| { type: "doubleStrikethrough" }
|
|
488
724
|
| { type: "vanish" }
|
|
489
725
|
| { type: "lang"; val: string }
|
|
726
|
+
| { type: "highlight"; color: string; val: string }
|
|
490
727
|
| { type: "backgroundColor"; color: string }
|
|
491
728
|
| { type: "charSpacing"; val: number }
|
|
492
729
|
| { type: "kerning"; val: number }
|
|
@@ -587,6 +824,7 @@ export interface ShapeNode {
|
|
|
587
824
|
type: "shape";
|
|
588
825
|
text?: string;
|
|
589
826
|
geometry?: string;
|
|
827
|
+
isTextBox?: boolean;
|
|
590
828
|
rawXml: string;
|
|
591
829
|
}
|
|
592
830
|
|
|
@@ -617,6 +855,7 @@ export interface OpaqueBlockNode {
|
|
|
617
855
|
type: "opaque_block";
|
|
618
856
|
fragmentId: string;
|
|
619
857
|
warningId: string;
|
|
858
|
+
rawXml?: string;
|
|
620
859
|
}
|
|
621
860
|
|
|
622
861
|
export interface DocRange {
|
|
@@ -781,7 +1020,7 @@ export interface DiagnosticErrorEntry {
|
|
|
781
1020
|
| "internal_invariant";
|
|
782
1021
|
message: string;
|
|
783
1022
|
isFatal: boolean;
|
|
784
|
-
source: "import" | "runtime" | "validation" | "datastore" | "export";
|
|
1023
|
+
source: "import" | "runtime" | "validation" | "datastore" | "host" | "export";
|
|
785
1024
|
details?: unknown;
|
|
786
1025
|
}
|
|
787
1026
|
|
|
@@ -1146,6 +1385,9 @@ function validateDocumentNode(
|
|
|
1146
1385
|
case "opaque_block":
|
|
1147
1386
|
expectDomainString(record.fragmentId, "fragmentId", `${path}.fragmentId`, issues);
|
|
1148
1387
|
expectDomainString(record.warningId, "warningId", `${path}.warningId`, issues);
|
|
1388
|
+
if (record.rawXml !== undefined) {
|
|
1389
|
+
expectString(record.rawXml, `${path}.rawXml`, issues);
|
|
1390
|
+
}
|
|
1149
1391
|
return;
|
|
1150
1392
|
case "table":
|
|
1151
1393
|
if (!Array.isArray(record.gridColumns)) {
|
|
@@ -1343,7 +1585,11 @@ function validateReviewStore(
|
|
|
1343
1585
|
);
|
|
1344
1586
|
}
|
|
1345
1587
|
if (threadRecord.body !== undefined) {
|
|
1346
|
-
|
|
1588
|
+
expectStringAllowEmpty(
|
|
1589
|
+
threadRecord.body,
|
|
1590
|
+
`${path}.comments.${commentId}.body`,
|
|
1591
|
+
issues,
|
|
1592
|
+
);
|
|
1347
1593
|
}
|
|
1348
1594
|
if (!Array.isArray(threadRecord.warningIds)) {
|
|
1349
1595
|
issues.push({
|
|
@@ -1489,7 +1735,7 @@ function validateCommentEntries(
|
|
|
1489
1735
|
}
|
|
1490
1736
|
expectString(record.entryId, `${path}[${index}].entryId`, issues);
|
|
1491
1737
|
expectString(record.authorId, `${path}[${index}].authorId`, issues);
|
|
1492
|
-
|
|
1738
|
+
expectStringAllowEmpty(record.body, `${path}[${index}].body`, issues);
|
|
1493
1739
|
expectIso8601UtcTimestamp(record.createdAt, `${path}[${index}].createdAt`, issues);
|
|
1494
1740
|
if (record.metadata !== undefined) {
|
|
1495
1741
|
validateCommentEntryMetadata(record.metadata, `${path}[${index}].metadata`, issues);
|
package/src/model/cds-1.0.0.ts
CHANGED
|
@@ -98,6 +98,19 @@ export function expectString(
|
|
|
98
98
|
return value;
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
export function expectStringAllowEmpty(
|
|
102
|
+
value: unknown,
|
|
103
|
+
path: string,
|
|
104
|
+
issues: ModelValidationIssue[],
|
|
105
|
+
): string | null {
|
|
106
|
+
if (typeof value !== "string") {
|
|
107
|
+
issues.push({ path, message: "Expected a string." });
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return value;
|
|
112
|
+
}
|
|
113
|
+
|
|
101
114
|
export function expectExactString<T extends string>(
|
|
102
115
|
value: unknown,
|
|
103
116
|
expected: T,
|
package/src/model/snapshot.ts
CHANGED
|
@@ -62,7 +62,7 @@ export interface EditorError {
|
|
|
62
62
|
code: EditorErrorCode;
|
|
63
63
|
message: string;
|
|
64
64
|
isFatal: boolean;
|
|
65
|
-
source: "import" | "runtime" | "validation" | "datastore" | "export";
|
|
65
|
+
source: "import" | "runtime" | "validation" | "datastore" | "host" | "export";
|
|
66
66
|
details?: Record<string, unknown>;
|
|
67
67
|
}
|
|
68
68
|
|
|
@@ -110,6 +110,7 @@ export interface PersistedEditorSnapshot {
|
|
|
110
110
|
canonicalDocument: CanonicalDocument;
|
|
111
111
|
compatibility: CompatibilityReport;
|
|
112
112
|
warningLog: EditorWarning[];
|
|
113
|
+
protectionSnapshot?: ProtectionSnapshotRecord;
|
|
113
114
|
sourcePackage?: PersistedSourcePackage;
|
|
114
115
|
}
|
|
115
116
|
|
|
@@ -127,7 +128,26 @@ const SNAPSHOT_REQUIRED_TOP_LEVEL_KEYS = [
|
|
|
127
128
|
"warningLog",
|
|
128
129
|
] as const;
|
|
129
130
|
|
|
130
|
-
const SNAPSHOT_OPTIONAL_TOP_LEVEL_KEYS = ["sourcePackage"] as const;
|
|
131
|
+
const SNAPSHOT_OPTIONAL_TOP_LEVEL_KEYS = ["sourcePackage", "protectionSnapshot"] as const;
|
|
132
|
+
|
|
133
|
+
export interface ProtectionRangeRecord {
|
|
134
|
+
rangeId: string;
|
|
135
|
+
start?: number;
|
|
136
|
+
end?: number;
|
|
137
|
+
editorGroup?: string;
|
|
138
|
+
editor?: string;
|
|
139
|
+
enforced: boolean;
|
|
140
|
+
enforcementReason: string;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export interface ProtectionSnapshotRecord {
|
|
144
|
+
hasDocumentProtection: boolean;
|
|
145
|
+
editType?: string;
|
|
146
|
+
enforcementActive: boolean;
|
|
147
|
+
ranges: ProtectionRangeRecord[];
|
|
148
|
+
enforcedRangeCount: number;
|
|
149
|
+
preservedRangeCount: number;
|
|
150
|
+
}
|
|
131
151
|
|
|
132
152
|
const PERSISTED_EDITOR_SNAPSHOT_VERSIONS = new Set<PersistedEditorSnapshotVersion>([
|
|
133
153
|
LEGACY_PERSISTED_EDITOR_SNAPSHOT_VERSION,
|
|
@@ -174,6 +194,7 @@ const EDITOR_ERROR_SOURCES = new Set<EditorError["source"]>([
|
|
|
174
194
|
"runtime",
|
|
175
195
|
"validation",
|
|
176
196
|
"datastore",
|
|
197
|
+
"host",
|
|
177
198
|
"export",
|
|
178
199
|
]);
|
|
179
200
|
|
|
@@ -259,6 +280,9 @@ export function validatePersistedEditorSnapshot(
|
|
|
259
280
|
if (record.sourcePackage !== undefined) {
|
|
260
281
|
validatePersistedSourcePackage(record.sourcePackage, "$.sourcePackage", issues);
|
|
261
282
|
}
|
|
283
|
+
if (record.protectionSnapshot !== undefined) {
|
|
284
|
+
validateProtectionSnapshot(record.protectionSnapshot, "$.protectionSnapshot", issues);
|
|
285
|
+
}
|
|
262
286
|
|
|
263
287
|
return issues;
|
|
264
288
|
}
|
|
@@ -536,6 +560,7 @@ export function createPersistedEditorSnapshot(params: {
|
|
|
536
560
|
canonicalDocument: CanonicalDocument;
|
|
537
561
|
compatibility: CompatibilityReport;
|
|
538
562
|
warningLog?: EditorWarning[];
|
|
563
|
+
protectionSnapshot?: ProtectionSnapshotRecord;
|
|
539
564
|
sourcePackage?: PersistedSourcePackage;
|
|
540
565
|
}): PersistedEditorSnapshot {
|
|
541
566
|
assertCanonicalDocument(params.canonicalDocument);
|
|
@@ -553,10 +578,70 @@ export function createPersistedEditorSnapshot(params: {
|
|
|
553
578
|
canonicalDocument: params.canonicalDocument,
|
|
554
579
|
compatibility: params.compatibility,
|
|
555
580
|
warningLog: params.warningLog ?? params.compatibility.warnings,
|
|
581
|
+
protectionSnapshot: params.protectionSnapshot,
|
|
556
582
|
sourcePackage: params.sourcePackage,
|
|
557
583
|
};
|
|
558
584
|
}
|
|
559
585
|
|
|
586
|
+
function validateProtectionSnapshot(
|
|
587
|
+
value: unknown,
|
|
588
|
+
path: string,
|
|
589
|
+
issues: ModelValidationIssue[],
|
|
590
|
+
): void {
|
|
591
|
+
const record = asPlainObject(value, path, issues);
|
|
592
|
+
if (!record) {
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
if (typeof record.hasDocumentProtection !== "boolean") {
|
|
596
|
+
issues.push({ path: `${path}.hasDocumentProtection`, message: "hasDocumentProtection must be a boolean." });
|
|
597
|
+
}
|
|
598
|
+
if (record.editType !== undefined) {
|
|
599
|
+
expectString(record.editType, `${path}.editType`, issues);
|
|
600
|
+
}
|
|
601
|
+
if (typeof record.enforcementActive !== "boolean") {
|
|
602
|
+
issues.push({ path: `${path}.enforcementActive`, message: "enforcementActive must be a boolean." });
|
|
603
|
+
}
|
|
604
|
+
if (!Array.isArray(record.ranges)) {
|
|
605
|
+
issues.push({ path: `${path}.ranges`, message: "ranges must be an array." });
|
|
606
|
+
} else {
|
|
607
|
+
record.ranges.forEach((range, index) => validateProtectionRange(range, `${path}.ranges[${index}]`, issues));
|
|
608
|
+
}
|
|
609
|
+
if (!Number.isInteger(record.enforcedRangeCount)) {
|
|
610
|
+
issues.push({ path: `${path}.enforcedRangeCount`, message: "enforcedRangeCount must be an integer." });
|
|
611
|
+
}
|
|
612
|
+
if (!Number.isInteger(record.preservedRangeCount)) {
|
|
613
|
+
issues.push({ path: `${path}.preservedRangeCount`, message: "preservedRangeCount must be an integer." });
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
function validateProtectionRange(
|
|
618
|
+
value: unknown,
|
|
619
|
+
path: string,
|
|
620
|
+
issues: ModelValidationIssue[],
|
|
621
|
+
): void {
|
|
622
|
+
const record = asPlainObject(value, path, issues);
|
|
623
|
+
if (!record) {
|
|
624
|
+
return;
|
|
625
|
+
}
|
|
626
|
+
expectString(record.rangeId, `${path}.rangeId`, issues);
|
|
627
|
+
if (record.start !== undefined && !Number.isInteger(record.start)) {
|
|
628
|
+
issues.push({ path: `${path}.start`, message: "start must be an integer." });
|
|
629
|
+
}
|
|
630
|
+
if (record.end !== undefined && !Number.isInteger(record.end)) {
|
|
631
|
+
issues.push({ path: `${path}.end`, message: "end must be an integer." });
|
|
632
|
+
}
|
|
633
|
+
if (record.editorGroup !== undefined) {
|
|
634
|
+
expectString(record.editorGroup, `${path}.editorGroup`, issues);
|
|
635
|
+
}
|
|
636
|
+
if (record.editor !== undefined) {
|
|
637
|
+
expectString(record.editor, `${path}.editor`, issues);
|
|
638
|
+
}
|
|
639
|
+
if (typeof record.enforced !== "boolean") {
|
|
640
|
+
issues.push({ path: `${path}.enforced`, message: "enforced must be a boolean." });
|
|
641
|
+
}
|
|
642
|
+
expectString(record.enforcementReason, `${path}.enforcementReason`, issues);
|
|
643
|
+
}
|
|
644
|
+
|
|
560
645
|
export function projectAnchorToSnapshot(
|
|
561
646
|
anchor: Record<string, unknown>,
|
|
562
647
|
): Record<string, unknown> {
|
|
@@ -44,6 +44,8 @@ export interface RevisionSidebarEntry {
|
|
|
44
44
|
canAccept: boolean;
|
|
45
45
|
canReject: boolean;
|
|
46
46
|
preserveOnlyReason?: string;
|
|
47
|
+
linkedMoveRevisionId?: string;
|
|
48
|
+
moveDirection?: "from" | "to";
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
export interface RevisionSidebarProjection {
|
|
@@ -212,6 +214,8 @@ function toSidebarEntry(revision: RevisionRecord): RevisionSidebarEntry {
|
|
|
212
214
|
const anchorSummary = summarizeRevisionAnchor(revision.anchor);
|
|
213
215
|
const actionability = getRevisionActionability(revision);
|
|
214
216
|
|
|
217
|
+
const moveData = revision.metadata.moveData;
|
|
218
|
+
|
|
215
219
|
return {
|
|
216
220
|
revisionId: revision.revisionId,
|
|
217
221
|
kind: revision.kind,
|
|
@@ -228,6 +232,8 @@ function toSidebarEntry(revision: RevisionRecord): RevisionSidebarEntry {
|
|
|
228
232
|
canAccept: isRevisionActionable(revision),
|
|
229
233
|
canReject: isRevisionActionable(revision),
|
|
230
234
|
preserveOnlyReason: revision.metadata.preserveOnlyReason,
|
|
235
|
+
linkedMoveRevisionId: moveData?.linkedRevisionId,
|
|
236
|
+
moveDirection: moveData?.direction,
|
|
231
237
|
};
|
|
232
238
|
}
|
|
233
239
|
|