@beyondwork/docx-react-component 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -104
- package/package.json +50 -30
- package/src/README.md +85 -0
- package/src/api/README.md +22 -0
- package/src/api/public-types.ts +525 -0
- package/src/compare/diff-engine.ts +530 -0
- package/src/compare/export-redlines.ts +162 -0
- package/src/compare/snapshot.ts +37 -0
- package/src/component-inventory.md +99 -0
- package/src/core/README.md +10 -0
- package/src/core/commands/README.md +3 -0
- package/src/core/commands/formatting-commands.ts +161 -0
- package/src/core/commands/image-commands.ts +144 -0
- package/src/core/commands/index.ts +1013 -0
- package/src/core/commands/list-commands.ts +370 -0
- package/src/core/commands/review-commands.ts +108 -0
- package/src/core/commands/text-commands.ts +119 -0
- package/src/core/schema/README.md +3 -0
- package/src/core/schema/text-schema.ts +512 -0
- package/src/core/selection/README.md +3 -0
- package/src/core/selection/mapping.ts +238 -0
- package/src/core/selection/review-anchors.ts +94 -0
- package/src/core/state/README.md +3 -0
- package/src/core/state/editor-state.ts +580 -0
- package/src/core/state/text-transaction.ts +276 -0
- package/src/formats/xlsx/io/parse-shared-strings.ts +41 -0
- package/src/formats/xlsx/io/parse-sheet.ts +289 -0
- package/src/formats/xlsx/io/parse-styles.ts +57 -0
- package/src/formats/xlsx/io/parse-workbook.ts +75 -0
- package/src/formats/xlsx/io/xlsx-session.ts +306 -0
- package/src/formats/xlsx/model/cell.ts +189 -0
- package/src/formats/xlsx/model/sheet.ts +244 -0
- package/src/formats/xlsx/model/styles.ts +118 -0
- package/src/formats/xlsx/model/workbook.ts +449 -0
- package/src/index.ts +45 -0
- package/src/io/README.md +10 -0
- package/src/io/docx-session.ts +1763 -0
- package/src/io/export/README.md +3 -0
- package/src/io/export/export-session.ts +165 -0
- package/src/io/export/minimal-docx.ts +115 -0
- package/src/io/export/reattach-preserved-parts.ts +54 -0
- package/src/io/export/serialize-comments.ts +876 -0
- package/src/io/export/serialize-footnotes.ts +217 -0
- package/src/io/export/serialize-headers-footers.ts +200 -0
- package/src/io/export/serialize-main-document.ts +982 -0
- package/src/io/export/serialize-numbering.ts +97 -0
- package/src/io/export/serialize-revisions.ts +389 -0
- package/src/io/export/serialize-runtime-revisions.ts +265 -0
- package/src/io/export/serialize-tables.ts +147 -0
- package/src/io/export/split-review-boundaries.ts +194 -0
- package/src/io/normalize/README.md +3 -0
- package/src/io/normalize/normalize-text.ts +437 -0
- package/src/io/ooxml/README.md +3 -0
- package/src/io/ooxml/parse-comments.ts +779 -0
- package/src/io/ooxml/parse-complex-content.ts +287 -0
- package/src/io/ooxml/parse-fields.ts +438 -0
- package/src/io/ooxml/parse-footnotes.ts +403 -0
- package/src/io/ooxml/parse-headers-footers.ts +483 -0
- package/src/io/ooxml/parse-inline-media.ts +431 -0
- package/src/io/ooxml/parse-main-document.ts +1846 -0
- package/src/io/ooxml/parse-numbering.ts +425 -0
- package/src/io/ooxml/parse-revisions.ts +658 -0
- package/src/io/ooxml/parse-shapes.ts +271 -0
- package/src/io/ooxml/parse-tables.ts +568 -0
- package/src/io/ooxml/parse-theme.ts +314 -0
- package/src/io/ooxml/part-manifest.ts +136 -0
- package/src/io/ooxml/revision-boundaries.ts +351 -0
- package/src/io/opc/README.md +3 -0
- package/src/io/opc/corrupt-package.ts +166 -0
- package/src/io/opc/docx-package.ts +74 -0
- package/src/io/opc/package-reader.ts +325 -0
- package/src/io/opc/package-writer.ts +273 -0
- package/src/legal/bookmarks.ts +196 -0
- package/src/legal/cross-references.ts +356 -0
- package/src/legal/defined-terms.ts +203 -0
- package/src/model/README.md +3 -0
- package/src/model/canonical-document.ts +1911 -0
- package/src/model/cds-1.0.0.ts +196 -0
- package/src/model/snapshot.ts +393 -0
- package/src/preservation/README.md +3 -0
- package/src/preservation/markup-compatibility.ts +48 -0
- package/src/preservation/opaque-fragment-store.ts +89 -0
- package/src/preservation/opaque-region.ts +233 -0
- package/src/preservation/package-preservation.ts +120 -0
- package/src/preservation/preserved-part-manifest.ts +56 -0
- package/src/preservation/relationship-retention.ts +57 -0
- package/src/preservation/store.ts +185 -0
- package/src/review/README.md +16 -0
- package/src/review/store/README.md +3 -0
- package/src/review/store/comment-anchors.ts +70 -0
- package/src/review/store/comment-remapping.ts +154 -0
- package/src/review/store/comment-store.ts +331 -0
- package/src/review/store/comment-thread.ts +109 -0
- package/src/review/store/revision-actions.ts +394 -0
- package/src/review/store/revision-store.ts +303 -0
- package/src/review/store/revision-types.ts +168 -0
- package/src/review/store/runtime-comment-store.ts +43 -0
- package/src/runtime/README.md +3 -0
- package/src/runtime/ai-action-policy.ts +764 -0
- package/src/runtime/document-runtime.ts +967 -0
- package/src/runtime/read-only-diagnostics-runtime.ts +232 -0
- package/src/runtime/review-runtime.ts +44 -0
- package/src/runtime/revision-runtime.ts +107 -0
- package/src/runtime/session-capabilities.ts +138 -0
- package/src/runtime/surface-projection.ts +570 -0
- package/src/runtime/table-commands.ts +87 -0
- package/src/runtime/table-schema.ts +140 -0
- package/src/runtime/virtualized-rendering.ts +258 -0
- package/src/ui/README.md +30 -0
- package/src/ui/WordReviewEditor.tsx +1506 -0
- package/src/ui/comments/README.md +3 -0
- package/src/ui/compatibility/README.md +3 -0
- package/src/ui/editor-surface/README.md +3 -0
- package/src/ui/headless/comment-decoration-model.ts +124 -0
- package/src/ui/headless/revision-decoration-model.ts +128 -0
- package/src/ui/headless/selection-helpers.ts +34 -0
- package/src/ui/headless/use-editor-keyboard.ts +98 -0
- package/src/ui/review/README.md +3 -0
- package/src/ui/shared/revision-filters.ts +31 -0
- package/src/ui/status/README.md +3 -0
- package/src/ui/theme/README.md +3 -0
- package/src/ui/toolbar/README.md +3 -0
- package/src/ui-tailwind/chrome/tw-alert-banner.tsx +48 -0
- package/src/ui-tailwind/chrome/tw-selection-toolbar.tsx +44 -0
- package/src/ui-tailwind/chrome/tw-unsaved-modal.tsx +58 -0
- package/src/ui-tailwind/chrome/use-before-unload.ts +20 -0
- package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +139 -0
- package/src/ui-tailwind/editor-surface/pm-decorations.ts +98 -0
- package/src/ui-tailwind/editor-surface/pm-position-map.ts +123 -0
- package/src/ui-tailwind/editor-surface/pm-schema.ts +452 -0
- package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +327 -0
- package/src/ui-tailwind/editor-surface/search-plugin.ts +157 -0
- package/src/ui-tailwind/editor-surface/tw-caret.tsx +12 -0
- package/src/ui-tailwind/editor-surface/tw-editor-surface.tsx +150 -0
- package/src/ui-tailwind/editor-surface/tw-inline-token.tsx +118 -0
- package/src/ui-tailwind/editor-surface/tw-opaque-block.tsx +52 -0
- package/src/ui-tailwind/editor-surface/tw-paragraph-block.tsx +151 -0
- package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +215 -0
- package/src/ui-tailwind/editor-surface/tw-segment-view.tsx +111 -0
- package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +122 -0
- package/src/ui-tailwind/index.ts +61 -0
- package/src/ui-tailwind/review/tw-comment-sidebar.tsx +276 -0
- package/src/ui-tailwind/review/tw-health-panel.tsx +120 -0
- package/src/ui-tailwind/review/tw-review-rail.tsx +120 -0
- package/src/ui-tailwind/review/tw-revision-sidebar.tsx +164 -0
- package/src/ui-tailwind/status/tw-status-bar.tsx +58 -0
- package/src/ui-tailwind/theme/editor-theme.css +190 -0
- package/src/ui-tailwind/toolbar/tw-toolbar-icon-button.tsx +48 -0
- package/src/ui-tailwind/toolbar/tw-toolbar.tsx +231 -0
- package/src/ui-tailwind/tw-review-workspace.tsx +140 -0
- package/src/validation/README.md +3 -0
- package/src/validation/compatibility-engine.ts +317 -0
- package/src/validation/compatibility-report.ts +160 -0
- package/src/validation/diagnostics.ts +203 -0
- package/src/validation/import-diagnostics.ts +128 -0
- package/src/validation/low-priority-word-surfaces.ts +373 -0
- package/dist/chunk-32W6IVQE.js +0 -7725
- package/dist/chunk-32W6IVQE.js.map +0 -1
- package/dist/index.cjs +0 -23722
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -7
- package/dist/index.d.ts +0 -7
- package/dist/index.js +0 -16011
- package/dist/index.js.map +0 -1
- package/dist/public-types-DqCURAz8.d.cts +0 -1152
- package/dist/public-types-DqCURAz8.d.ts +0 -1152
- package/dist/tailwind.cjs +0 -8295
- package/dist/tailwind.cjs.map +0 -1
- package/dist/tailwind.d.cts +0 -323
- package/dist/tailwind.d.ts +0 -323
- package/dist/tailwind.js +0 -553
- package/dist/tailwind.js.map +0 -1
|
@@ -0,0 +1,580 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_BOUNDARY_ASSOC,
|
|
3
|
+
createDetachedAnchor,
|
|
4
|
+
createRangeAnchor,
|
|
5
|
+
type EditorAnchorProjection,
|
|
6
|
+
} from "../selection/mapping.ts";
|
|
7
|
+
import {
|
|
8
|
+
assertPersistedEditorSnapshot as assertModelPersistedEditorSnapshot,
|
|
9
|
+
createPersistedEditorSnapshot as createModelPersistedEditorSnapshot,
|
|
10
|
+
type PersistedEditorSnapshot as ModelPersistedEditorSnapshot,
|
|
11
|
+
} from "../../model/snapshot.ts";
|
|
12
|
+
import {
|
|
13
|
+
assertCanonicalDocument,
|
|
14
|
+
type CanonicalDocument,
|
|
15
|
+
type CommentEntry as ModelCommentEntry,
|
|
16
|
+
type CommentResolution as ModelCommentResolution,
|
|
17
|
+
type CommentThread as ModelCommentThread,
|
|
18
|
+
type RevisionMetadataRecord as ModelRevisionMetadataRecord,
|
|
19
|
+
type RevisionRecord as ModelRevisionRecord,
|
|
20
|
+
} from "../../model/canonical-document.ts";
|
|
21
|
+
|
|
22
|
+
export type RuntimePhase = "loading" | "ready" | "error";
|
|
23
|
+
export type EditorWarningCode =
|
|
24
|
+
| "unsupported_ooxml_preserved"
|
|
25
|
+
| "unsupported_ooxml_locked"
|
|
26
|
+
| "import_normalized"
|
|
27
|
+
| "export_roundtrip_risk"
|
|
28
|
+
| "comment_anchor_detached"
|
|
29
|
+
| "revision_anchor_detached"
|
|
30
|
+
| "large_document_degraded"
|
|
31
|
+
| "font_substitution"
|
|
32
|
+
| "image_missing";
|
|
33
|
+
|
|
34
|
+
export interface EditorWarning {
|
|
35
|
+
warningId: string;
|
|
36
|
+
code: EditorWarningCode;
|
|
37
|
+
severity: "info" | "warning";
|
|
38
|
+
message: string;
|
|
39
|
+
source:
|
|
40
|
+
| "import"
|
|
41
|
+
| "runtime"
|
|
42
|
+
| "review"
|
|
43
|
+
| "preservation"
|
|
44
|
+
| "validation"
|
|
45
|
+
| "export";
|
|
46
|
+
affectedAnchor?: EditorAnchorProjection;
|
|
47
|
+
featureEntryId?: string;
|
|
48
|
+
details?: Record<string, unknown>;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface EditorError {
|
|
52
|
+
errorId: string;
|
|
53
|
+
code:
|
|
54
|
+
| "import_failed"
|
|
55
|
+
| "export_failed"
|
|
56
|
+
| "package_corrupt"
|
|
57
|
+
| "validation_failed"
|
|
58
|
+
| "datastore_failed"
|
|
59
|
+
| "internal_invariant";
|
|
60
|
+
message: string;
|
|
61
|
+
isFatal: boolean;
|
|
62
|
+
source: "import" | "runtime" | "validation" | "datastore" | "export";
|
|
63
|
+
details?: Record<string, unknown>;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export type CompatibilityFeatureClass =
|
|
67
|
+
| "supported-roundtrip"
|
|
68
|
+
| "preserve-only"
|
|
69
|
+
| "unsupported-fatal";
|
|
70
|
+
|
|
71
|
+
export interface CompatibilityFeatureEntry {
|
|
72
|
+
featureEntryId: string;
|
|
73
|
+
featureKey: string;
|
|
74
|
+
featureClass: CompatibilityFeatureClass;
|
|
75
|
+
message: string;
|
|
76
|
+
affectedAnchor?: EditorAnchorProjection;
|
|
77
|
+
details?: Record<string, unknown>;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface CompatibilityReport {
|
|
81
|
+
reportVersion: "compatibility-report/1";
|
|
82
|
+
generatedAt: string;
|
|
83
|
+
blockExport: boolean;
|
|
84
|
+
featureEntries: CompatibilityFeatureEntry[];
|
|
85
|
+
warnings: EditorWarning[];
|
|
86
|
+
errors: EditorError[];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export type CommentEntryRecord = ModelCommentEntry;
|
|
90
|
+
export type CommentResolutionRecord = ModelCommentResolution;
|
|
91
|
+
export type CommentThreadRecord = ModelCommentThread;
|
|
92
|
+
export type RevisionMetadataRecord = ModelRevisionMetadataRecord;
|
|
93
|
+
export type RevisionRecord = ModelRevisionRecord;
|
|
94
|
+
export type ReviewStore = CanonicalDocument["review"];
|
|
95
|
+
export type CanonicalDocumentEnvelope = CanonicalDocument;
|
|
96
|
+
|
|
97
|
+
export interface SelectionSnapshot {
|
|
98
|
+
anchor: number;
|
|
99
|
+
head: number;
|
|
100
|
+
isCollapsed: boolean;
|
|
101
|
+
activeRange: EditorAnchorProjection;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface DocumentStats {
|
|
105
|
+
paragraphCount: number;
|
|
106
|
+
wordCount: number;
|
|
107
|
+
characterCount: number;
|
|
108
|
+
commentCount: number;
|
|
109
|
+
revisionCount: number;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export interface CommentSidebarSnapshot {
|
|
113
|
+
activeCommentId?: string;
|
|
114
|
+
openThreadCount: number;
|
|
115
|
+
resolvedThreadCount: number;
|
|
116
|
+
threads: CommentThreadRecord[];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export interface TrackedChangesSnapshot {
|
|
120
|
+
totalCount: number;
|
|
121
|
+
pendingCount: number;
|
|
122
|
+
acceptedCount: number;
|
|
123
|
+
rejectedCount: number;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export interface CompatibilityPanelSnapshot {
|
|
127
|
+
report: CompatibilityReport;
|
|
128
|
+
blockExport: boolean;
|
|
129
|
+
totalEntries: number;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export interface CommandStateSnapshot {
|
|
133
|
+
canUndo: boolean;
|
|
134
|
+
canRedo: boolean;
|
|
135
|
+
canAddComment: boolean;
|
|
136
|
+
canAcceptAllChanges: boolean;
|
|
137
|
+
canRejectAllChanges: boolean;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export interface RuntimeRenderSnapshot {
|
|
141
|
+
documentId: string;
|
|
142
|
+
sessionId: string;
|
|
143
|
+
sourceLabel?: string;
|
|
144
|
+
revisionToken: string;
|
|
145
|
+
isReady: boolean;
|
|
146
|
+
isDirty: boolean;
|
|
147
|
+
readOnly: boolean;
|
|
148
|
+
selection: SelectionSnapshot;
|
|
149
|
+
documentStats: DocumentStats;
|
|
150
|
+
comments: CommentSidebarSnapshot;
|
|
151
|
+
trackedChanges: TrackedChangesSnapshot;
|
|
152
|
+
compatibility: CompatibilityPanelSnapshot;
|
|
153
|
+
warnings: EditorWarning[];
|
|
154
|
+
fatalError?: EditorError;
|
|
155
|
+
commandState: CommandStateSnapshot;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export interface PersistedEditorSnapshot
|
|
159
|
+
extends Omit<
|
|
160
|
+
ModelPersistedEditorSnapshot,
|
|
161
|
+
"canonicalDocument" | "compatibility" | "warningLog"
|
|
162
|
+
> {
|
|
163
|
+
canonicalDocument: CanonicalDocumentEnvelope;
|
|
164
|
+
compatibility: CompatibilityReport;
|
|
165
|
+
warningLog: EditorWarning[];
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export interface EditorRuntimeState {
|
|
169
|
+
hasFocus: boolean;
|
|
170
|
+
activeCommentId?: string;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export interface EditorState {
|
|
174
|
+
phase: RuntimePhase;
|
|
175
|
+
documentId: string;
|
|
176
|
+
sessionId: string;
|
|
177
|
+
sourceLabel?: string;
|
|
178
|
+
revision: number;
|
|
179
|
+
revisionToken: string;
|
|
180
|
+
isDirty: boolean;
|
|
181
|
+
readOnly: boolean;
|
|
182
|
+
document: CanonicalDocumentEnvelope;
|
|
183
|
+
selection: SelectionSnapshot;
|
|
184
|
+
warnings: EditorWarning[];
|
|
185
|
+
compatibility: CompatibilityReport;
|
|
186
|
+
fatalError?: EditorError;
|
|
187
|
+
runtime: EditorRuntimeState;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export interface CreateEditorStateOptions {
|
|
191
|
+
documentId: string;
|
|
192
|
+
sessionId: string;
|
|
193
|
+
sourceLabel?: string;
|
|
194
|
+
readOnly?: boolean;
|
|
195
|
+
canonicalDocument?: CanonicalDocumentEnvelope;
|
|
196
|
+
persistedSnapshot?: PersistedEditorSnapshot;
|
|
197
|
+
compatibility?: CompatibilityReport;
|
|
198
|
+
warnings?: EditorWarning[];
|
|
199
|
+
fatalError?: EditorError;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export function createEmptyReviewStore(): ReviewStore {
|
|
203
|
+
return {
|
|
204
|
+
comments: {},
|
|
205
|
+
revisions: {},
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export function createDefaultCanonicalDocument(
|
|
210
|
+
documentId: string,
|
|
211
|
+
timestamp: string,
|
|
212
|
+
): CanonicalDocumentEnvelope {
|
|
213
|
+
return {
|
|
214
|
+
schemaVersion: "cds/1.0.0",
|
|
215
|
+
docId: createCanonicalDocumentId(documentId),
|
|
216
|
+
createdAt: timestamp,
|
|
217
|
+
updatedAt: timestamp,
|
|
218
|
+
metadata: {
|
|
219
|
+
customProperties: {},
|
|
220
|
+
},
|
|
221
|
+
styles: {
|
|
222
|
+
paragraphs: {},
|
|
223
|
+
characters: {},
|
|
224
|
+
tables: {},
|
|
225
|
+
},
|
|
226
|
+
numbering: {
|
|
227
|
+
abstractDefinitions: {},
|
|
228
|
+
instances: {},
|
|
229
|
+
},
|
|
230
|
+
media: {
|
|
231
|
+
items: {},
|
|
232
|
+
},
|
|
233
|
+
content: {
|
|
234
|
+
type: "doc",
|
|
235
|
+
children: [{ type: "paragraph", children: [] }],
|
|
236
|
+
},
|
|
237
|
+
review: createEmptyReviewStore(),
|
|
238
|
+
preservation: {
|
|
239
|
+
opaqueFragments: {},
|
|
240
|
+
packageParts: {},
|
|
241
|
+
},
|
|
242
|
+
diagnostics: {
|
|
243
|
+
warnings: [],
|
|
244
|
+
errors: [],
|
|
245
|
+
},
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export function createSelectionSnapshot(anchor = 0, head = anchor): SelectionSnapshot {
|
|
250
|
+
return {
|
|
251
|
+
anchor,
|
|
252
|
+
head,
|
|
253
|
+
isCollapsed: anchor === head,
|
|
254
|
+
activeRange: createRangeAnchor(anchor, head, DEFAULT_BOUNDARY_ASSOC),
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export function createEmptyCompatibilityReport(generatedAt: string): CompatibilityReport {
|
|
259
|
+
return {
|
|
260
|
+
reportVersion: "compatibility-report/1",
|
|
261
|
+
generatedAt,
|
|
262
|
+
blockExport: false,
|
|
263
|
+
featureEntries: [],
|
|
264
|
+
warnings: [],
|
|
265
|
+
errors: [],
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export function createEditorState(options: CreateEditorStateOptions): EditorState {
|
|
270
|
+
const timestamp = new Date(0).toISOString();
|
|
271
|
+
if (options.persistedSnapshot) {
|
|
272
|
+
assertModelPersistedEditorSnapshot(options.persistedSnapshot as unknown);
|
|
273
|
+
}
|
|
274
|
+
if (options.canonicalDocument) {
|
|
275
|
+
assertCanonicalDocument(options.canonicalDocument as unknown);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const normalizedDocument = options.persistedSnapshot
|
|
279
|
+
? structuredClone(options.persistedSnapshot.canonicalDocument)
|
|
280
|
+
: options.canonicalDocument
|
|
281
|
+
? structuredClone(options.canonicalDocument)
|
|
282
|
+
: createDefaultCanonicalDocument(options.documentId, timestamp);
|
|
283
|
+
const warnings = options.persistedSnapshot?.warningLog ?? options.warnings ?? [];
|
|
284
|
+
const compatibility =
|
|
285
|
+
options.persistedSnapshot?.compatibility ??
|
|
286
|
+
options.compatibility ??
|
|
287
|
+
createEmptyCompatibilityReport(normalizedDocument.updatedAt);
|
|
288
|
+
|
|
289
|
+
return {
|
|
290
|
+
phase: options.fatalError ? "error" : "ready",
|
|
291
|
+
documentId: options.documentId,
|
|
292
|
+
sessionId: options.sessionId,
|
|
293
|
+
sourceLabel: options.sourceLabel,
|
|
294
|
+
revision: 0,
|
|
295
|
+
revisionToken: `${options.sessionId}:0`,
|
|
296
|
+
isDirty: false,
|
|
297
|
+
readOnly: options.readOnly ?? false,
|
|
298
|
+
document: normalizedDocument,
|
|
299
|
+
selection: createSelectionSnapshot(),
|
|
300
|
+
warnings,
|
|
301
|
+
compatibility,
|
|
302
|
+
fatalError: options.fatalError,
|
|
303
|
+
runtime: {
|
|
304
|
+
hasFocus: false,
|
|
305
|
+
},
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
export function deriveDocumentStats(state: Pick<EditorState, "document">): DocumentStats {
|
|
310
|
+
const serializedContent = extractText(state.document.content);
|
|
311
|
+
|
|
312
|
+
return {
|
|
313
|
+
paragraphCount: estimateParagraphCount(state.document.content),
|
|
314
|
+
wordCount: serializedContent.trim().length === 0 ? 0 : serializedContent.trim().split(/\s+/u).length,
|
|
315
|
+
characterCount: Array.from(serializedContent).length,
|
|
316
|
+
commentCount: Object.keys(state.document.review.comments).length,
|
|
317
|
+
revisionCount: Object.keys(state.document.review.revisions).length,
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
export function deriveRenderSnapshot(
|
|
322
|
+
state: EditorState,
|
|
323
|
+
history: { canUndo: boolean; canRedo: boolean },
|
|
324
|
+
): RuntimeRenderSnapshot {
|
|
325
|
+
const comments = Object.values(state.document.review.comments).sort((left, right) =>
|
|
326
|
+
left.createdAt.localeCompare(right.createdAt),
|
|
327
|
+
);
|
|
328
|
+
const revisions = Object.values(state.document.review.revisions);
|
|
329
|
+
|
|
330
|
+
return {
|
|
331
|
+
documentId: state.documentId,
|
|
332
|
+
sessionId: state.sessionId,
|
|
333
|
+
sourceLabel: state.sourceLabel,
|
|
334
|
+
revisionToken: state.revisionToken,
|
|
335
|
+
isReady: state.phase === "ready",
|
|
336
|
+
isDirty: state.isDirty,
|
|
337
|
+
readOnly: state.readOnly,
|
|
338
|
+
selection: state.selection,
|
|
339
|
+
documentStats: deriveDocumentStats(state),
|
|
340
|
+
comments: {
|
|
341
|
+
activeCommentId: state.runtime.activeCommentId,
|
|
342
|
+
openThreadCount: comments.filter((comment) => comment.status === "open").length,
|
|
343
|
+
resolvedThreadCount: comments.filter((comment) => comment.status === "resolved").length,
|
|
344
|
+
threads: comments,
|
|
345
|
+
},
|
|
346
|
+
trackedChanges: {
|
|
347
|
+
totalCount: revisions.length,
|
|
348
|
+
pendingCount: revisions.filter((revision) => revision.status === "open").length,
|
|
349
|
+
acceptedCount: revisions.filter((revision) => revision.status === "accepted").length,
|
|
350
|
+
rejectedCount: revisions.filter((revision) => revision.status === "rejected").length,
|
|
351
|
+
},
|
|
352
|
+
compatibility: {
|
|
353
|
+
report: state.compatibility,
|
|
354
|
+
blockExport: state.compatibility.blockExport,
|
|
355
|
+
totalEntries: state.compatibility.featureEntries.length,
|
|
356
|
+
},
|
|
357
|
+
warnings: state.warnings,
|
|
358
|
+
fatalError: state.fatalError,
|
|
359
|
+
commandState: {
|
|
360
|
+
canUndo: history.canUndo,
|
|
361
|
+
canRedo: history.canRedo,
|
|
362
|
+
canAddComment: !state.readOnly,
|
|
363
|
+
canAcceptAllChanges: revisions.some((revision) => revision.status === "open"),
|
|
364
|
+
canRejectAllChanges: revisions.some((revision) => revision.status === "open"),
|
|
365
|
+
},
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
export function createPersistedEditorSnapshot(
|
|
370
|
+
state: EditorState,
|
|
371
|
+
options: {
|
|
372
|
+
editorBuild: string;
|
|
373
|
+
savedAt: string;
|
|
374
|
+
compatibility?: CompatibilityReport;
|
|
375
|
+
},
|
|
376
|
+
): PersistedEditorSnapshot {
|
|
377
|
+
const snapshot = createModelPersistedEditorSnapshot({
|
|
378
|
+
documentId: state.documentId,
|
|
379
|
+
savedAt: options.savedAt,
|
|
380
|
+
editorBuild: options.editorBuild,
|
|
381
|
+
canonicalDocument: state.document,
|
|
382
|
+
compatibility: (options.compatibility ?? state.compatibility) as never,
|
|
383
|
+
warningLog: state.warnings as never,
|
|
384
|
+
});
|
|
385
|
+
return snapshot as PersistedEditorSnapshot;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function estimateParagraphCount(content: unknown): number {
|
|
389
|
+
if (Array.isArray(content)) {
|
|
390
|
+
return content.length;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (content && typeof content === "object" && Array.isArray((content as { blocks?: unknown[] }).blocks)) {
|
|
394
|
+
return ((content as { blocks: unknown[] }).blocks).length;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
return extractText(content).length > 0 ? 1 : 0;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function extractText(value: unknown): string {
|
|
401
|
+
if (typeof value === "string") {
|
|
402
|
+
return value;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (Array.isArray(value)) {
|
|
406
|
+
return value.map((item) => extractText(item)).join(" ");
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
if (!value || typeof value !== "object") {
|
|
410
|
+
return "";
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
return Object.values(value as Record<string, unknown>)
|
|
414
|
+
.map((item) => extractText(item))
|
|
415
|
+
.filter(Boolean)
|
|
416
|
+
.join(" ");
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
420
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
export function createCanonicalDocumentId(documentId: string): string {
|
|
424
|
+
const hashWord = (seed: string): string => {
|
|
425
|
+
let hash = 0x811c9dc5;
|
|
426
|
+
for (const char of seed) {
|
|
427
|
+
hash ^= char.charCodeAt(0);
|
|
428
|
+
hash = Math.imul(hash, 0x01000193);
|
|
429
|
+
}
|
|
430
|
+
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
const raw =
|
|
434
|
+
hashWord(`${documentId}:0`) +
|
|
435
|
+
hashWord(`${documentId}:1`) +
|
|
436
|
+
hashWord(`${documentId}:2`) +
|
|
437
|
+
hashWord(`${documentId}:3`);
|
|
438
|
+
|
|
439
|
+
return [
|
|
440
|
+
raw.slice(0, 8),
|
|
441
|
+
raw.slice(8, 12),
|
|
442
|
+
`4${raw.slice(13, 16)}`,
|
|
443
|
+
`8${raw.slice(17, 20)}`,
|
|
444
|
+
raw.slice(20, 32),
|
|
445
|
+
].join("-");
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
export function normalizeCommentThreadRecord(value: unknown): CommentThreadRecord {
|
|
449
|
+
const record = isRecord(value) ? value : {};
|
|
450
|
+
const authorId =
|
|
451
|
+
typeof record.createdBy === "string" && record.createdBy.length > 0
|
|
452
|
+
? record.createdBy
|
|
453
|
+
: typeof record.authorId === "string" && record.authorId.length > 0
|
|
454
|
+
? record.authorId
|
|
455
|
+
: "unknown";
|
|
456
|
+
const createdAt =
|
|
457
|
+
typeof record.createdAt === "string" && record.createdAt.length > 0
|
|
458
|
+
? record.createdAt
|
|
459
|
+
: new Date(0).toISOString();
|
|
460
|
+
const entries = Array.isArray(record.entries)
|
|
461
|
+
? record.entries
|
|
462
|
+
.filter((entry): entry is Record<string, unknown> => isRecord(entry))
|
|
463
|
+
.map((entry, index) => ({
|
|
464
|
+
entryId:
|
|
465
|
+
typeof entry.entryId === "string" && entry.entryId.length > 0
|
|
466
|
+
? entry.entryId
|
|
467
|
+
: `${String(record.commentId ?? "comment")}-entry-${index + 1}`,
|
|
468
|
+
authorId:
|
|
469
|
+
typeof entry.authorId === "string" && entry.authorId.length > 0
|
|
470
|
+
? entry.authorId
|
|
471
|
+
: authorId,
|
|
472
|
+
body: typeof entry.body === "string" ? entry.body : "",
|
|
473
|
+
createdAt:
|
|
474
|
+
typeof entry.createdAt === "string" && entry.createdAt.length > 0
|
|
475
|
+
? entry.createdAt
|
|
476
|
+
: createdAt,
|
|
477
|
+
metadata: isRecord(entry.metadata)
|
|
478
|
+
? {
|
|
479
|
+
ooxmlCommentId:
|
|
480
|
+
typeof entry.metadata.ooxmlCommentId === "string"
|
|
481
|
+
? entry.metadata.ooxmlCommentId
|
|
482
|
+
: undefined,
|
|
483
|
+
paraId:
|
|
484
|
+
typeof entry.metadata.paraId === "string"
|
|
485
|
+
? entry.metadata.paraId
|
|
486
|
+
: undefined,
|
|
487
|
+
parentParaId:
|
|
488
|
+
typeof entry.metadata.parentParaId === "string"
|
|
489
|
+
? entry.metadata.parentParaId
|
|
490
|
+
: undefined,
|
|
491
|
+
durableId:
|
|
492
|
+
typeof entry.metadata.durableId === "string"
|
|
493
|
+
? entry.metadata.durableId
|
|
494
|
+
: undefined,
|
|
495
|
+
initials:
|
|
496
|
+
typeof entry.metadata.initials === "string"
|
|
497
|
+
? entry.metadata.initials
|
|
498
|
+
: undefined,
|
|
499
|
+
}
|
|
500
|
+
: undefined,
|
|
501
|
+
}))
|
|
502
|
+
: [
|
|
503
|
+
{
|
|
504
|
+
entryId: `${String(record.commentId ?? "comment")}-entry-1`,
|
|
505
|
+
authorId,
|
|
506
|
+
body: typeof record.body === "string" ? record.body : "",
|
|
507
|
+
createdAt,
|
|
508
|
+
},
|
|
509
|
+
];
|
|
510
|
+
const resolution = isRecord(record.resolution)
|
|
511
|
+
? {
|
|
512
|
+
resolvedAt:
|
|
513
|
+
typeof record.resolution.resolvedAt === "string"
|
|
514
|
+
? record.resolution.resolvedAt
|
|
515
|
+
: typeof record.resolvedAt === "string"
|
|
516
|
+
? record.resolvedAt
|
|
517
|
+
: createdAt,
|
|
518
|
+
resolvedBy:
|
|
519
|
+
typeof record.resolution.resolvedBy === "string" &&
|
|
520
|
+
record.resolution.resolvedBy.length > 0
|
|
521
|
+
? record.resolution.resolvedBy
|
|
522
|
+
: authorId,
|
|
523
|
+
}
|
|
524
|
+
: typeof record.resolvedAt === "string"
|
|
525
|
+
? {
|
|
526
|
+
resolvedAt: record.resolvedAt,
|
|
527
|
+
resolvedBy: authorId,
|
|
528
|
+
}
|
|
529
|
+
: undefined;
|
|
530
|
+
const normalizedStatus =
|
|
531
|
+
typeof record.status === "string"
|
|
532
|
+
? record.status
|
|
533
|
+
: record.anchor && isRecord(record.anchor) && record.anchor.kind === "detached"
|
|
534
|
+
? "detached"
|
|
535
|
+
: resolution || record.isResolved
|
|
536
|
+
? "resolved"
|
|
537
|
+
: "open";
|
|
538
|
+
|
|
539
|
+
return {
|
|
540
|
+
commentId:
|
|
541
|
+
typeof record.commentId === "string" && record.commentId.length > 0
|
|
542
|
+
? record.commentId
|
|
543
|
+
: "comment-generated",
|
|
544
|
+
anchor:
|
|
545
|
+
isRecord(record.anchor) && typeof record.anchor.kind === "string"
|
|
546
|
+
? (record.anchor as unknown as EditorAnchorProjection)
|
|
547
|
+
: createDetachedAnchor({ from: 0, to: 0 }, "importAmbiguity"),
|
|
548
|
+
createdAt,
|
|
549
|
+
createdBy: authorId,
|
|
550
|
+
authorId,
|
|
551
|
+
body: entries.map((entry) => entry.body).join("\n"),
|
|
552
|
+
entries,
|
|
553
|
+
status:
|
|
554
|
+
normalizedStatus === "resolved" || normalizedStatus === "detached"
|
|
555
|
+
? normalizedStatus
|
|
556
|
+
: "open",
|
|
557
|
+
resolution,
|
|
558
|
+
resolvedAt: resolution?.resolvedAt,
|
|
559
|
+
warningIds: Array.isArray(record.warningIds)
|
|
560
|
+
? record.warningIds.filter((warningId): warningId is string => typeof warningId === "string")
|
|
561
|
+
: [],
|
|
562
|
+
isResolved: normalizedStatus === "resolved",
|
|
563
|
+
metadata: isRecord(record.metadata)
|
|
564
|
+
? {
|
|
565
|
+
source:
|
|
566
|
+
record.metadata.source === "import" || record.metadata.source === "runtime"
|
|
567
|
+
? record.metadata.source
|
|
568
|
+
: undefined,
|
|
569
|
+
rootOoxmlCommentId:
|
|
570
|
+
typeof record.metadata.rootOoxmlCommentId === "string"
|
|
571
|
+
? record.metadata.rootOoxmlCommentId
|
|
572
|
+
: undefined,
|
|
573
|
+
rootParaId:
|
|
574
|
+
typeof record.metadata.rootParaId === "string"
|
|
575
|
+
? record.metadata.rootParaId
|
|
576
|
+
: undefined,
|
|
577
|
+
}
|
|
578
|
+
: undefined,
|
|
579
|
+
};
|
|
580
|
+
}
|