@wordinweb/agent 0.1.0
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 +296 -0
- package/dist/chunk-E7AFDS2O.js +34056 -0
- package/dist/chunk-E7AFDS2O.js.map +1 -0
- package/dist/cli.d.ts +10 -0
- package/dist/cli.js +555 -0
- package/dist/cli.js.map +1 -0
- package/dist/dist-4GR64XSW.js +4326 -0
- package/dist/dist-4GR64XSW.js.map +1 -0
- package/dist/index.d.ts +3092 -0
- package/dist/index.js +124 -0
- package/dist/index.js.map +1 -0
- package/dist/wmf-KUCU4S75.js +193 -0
- package/dist/wmf-KUCU4S75.js.map +1 -0
- package/package.json +50 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,3092 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal, fast XML parser producing a lightweight element tree.
|
|
3
|
+
*
|
|
4
|
+
* OOXML parts are machine-generated, namespace-prefixed, well-formed XML with
|
|
5
|
+
* no DTDs. This parser handles exactly that subset: elements, attributes,
|
|
6
|
+
* text, CDATA, comments, processing instructions, and the built-in + numeric
|
|
7
|
+
* character entities. Namespace prefixes are kept verbatim (`w:p`), and
|
|
8
|
+
* lookups match on either the full name or the local name, which is robust
|
|
9
|
+
* for every mainstream producer (Word, LibreOffice, Google Docs export).
|
|
10
|
+
*/
|
|
11
|
+
interface XmlElement {
|
|
12
|
+
name: string;
|
|
13
|
+
attrs: Record<string, string>;
|
|
14
|
+
children: XmlElement[];
|
|
15
|
+
/** Concatenated character data directly inside this element. */
|
|
16
|
+
text: string;
|
|
17
|
+
/** Editor placeholder retained in memory but omitted from XML while empty. */
|
|
18
|
+
omitWhenEmpty?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Typed document model produced by the parser and consumed by the layout
|
|
23
|
+
* engine. All lengths are CSS px (see units.ts) unless a field name says
|
|
24
|
+
* otherwise. Property bags are Partial-style: `undefined` means "not set at
|
|
25
|
+
* this level" so the style-inheritance merge can distinguish absence from an
|
|
26
|
+
* explicit value.
|
|
27
|
+
*
|
|
28
|
+
* Model nodes keep `src` references to the XML elements they were parsed
|
|
29
|
+
* from: the XML tree is the source of truth for editing — commands mutate it
|
|
30
|
+
* and the model is re-derived, which preserves round-trip fidelity for
|
|
31
|
+
* everything untouched.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
type BorderStyle = "none" | "single" | "double" | "dotted" | "dashed" | "thick" | "wave" | "dotDash" | "dotDotDash" | "thinThickSmallGap" | "triple";
|
|
35
|
+
interface Border {
|
|
36
|
+
style: BorderStyle;
|
|
37
|
+
/** Stroke width in px. */
|
|
38
|
+
width: number;
|
|
39
|
+
/** CSS color. */
|
|
40
|
+
color: string;
|
|
41
|
+
/** Gap between border and content in px (w:space, points in OOXML). */
|
|
42
|
+
space: number;
|
|
43
|
+
/** Declared stroke width in px BEFORE the 0.75px paint floor (w:sz/8 pt).
|
|
44
|
+
* Word's LAYOUT math (table row border share) uses this true width — a
|
|
45
|
+
* sz-4 rule contributes 0.5pt, not the floored 0.5625pt (phase23 p66:
|
|
46
|
+
* 45 rows drift 2.5px down without it). */
|
|
47
|
+
rawWidth?: number;
|
|
48
|
+
}
|
|
49
|
+
interface ParagraphBorders {
|
|
50
|
+
top?: Border;
|
|
51
|
+
bottom?: Border;
|
|
52
|
+
left?: Border;
|
|
53
|
+
right?: Border;
|
|
54
|
+
/** Drawn between consecutive paragraphs that both specify it. */
|
|
55
|
+
between?: Border;
|
|
56
|
+
}
|
|
57
|
+
type LineSpacingRule = "auto" | "atLeast" | "exact";
|
|
58
|
+
interface LineSpacing {
|
|
59
|
+
rule: LineSpacingRule;
|
|
60
|
+
/**
|
|
61
|
+
* For "auto": multiple of single line height (240ths in OOXML, stored here
|
|
62
|
+
* as the multiplier, e.g. 1.15). For atLeast/exact: px.
|
|
63
|
+
*/
|
|
64
|
+
value: number;
|
|
65
|
+
}
|
|
66
|
+
type Alignment = "left" | "center" | "right" | "justify";
|
|
67
|
+
interface TabStop {
|
|
68
|
+
/** px from the left text edge */
|
|
69
|
+
pos: number;
|
|
70
|
+
align: "left" | "center" | "right" | "decimal" | "bar";
|
|
71
|
+
leader: "none" | "dot" | "hyphen" | "underscore" | "middleDot";
|
|
72
|
+
/** w:val="clear": removes the inherited stop at this pos when tab lists
|
|
73
|
+
* merge down the style chain (never a live stop itself). */
|
|
74
|
+
clear?: boolean;
|
|
75
|
+
}
|
|
76
|
+
interface RunProps {
|
|
77
|
+
bold?: boolean;
|
|
78
|
+
italic?: boolean;
|
|
79
|
+
underline?: string;
|
|
80
|
+
strike?: boolean;
|
|
81
|
+
doubleStrike?: boolean;
|
|
82
|
+
/** Resolved primary font family name (ascii/hAnsi, theme-resolved). */
|
|
83
|
+
font?: string;
|
|
84
|
+
/** East Asian font (rFonts w:eastAsia): used for CJK codepoints. */
|
|
85
|
+
fontEastAsia?: string;
|
|
86
|
+
/** hAnsi font (rFonts w:hAnsi, theme-resolved): Word uses this channel for
|
|
87
|
+
* non-ASCII, non-CJK, non-complex characters (curly quotes, ≤, dashes). A
|
|
88
|
+
* run that declares only w:ascii leaves it inherited from the style chain. */
|
|
89
|
+
fontHAnsi?: string;
|
|
90
|
+
/** Complex-script font (rFonts w:cs): used for RTL/complex runs. */
|
|
91
|
+
fontComplex?: string;
|
|
92
|
+
/** w:rtl — this run's text is right-to-left (Arabic/Hebrew). */
|
|
93
|
+
rtl?: boolean;
|
|
94
|
+
/** Font size in px. */
|
|
95
|
+
size?: number;
|
|
96
|
+
/** CSS color; "auto" resolved to inherit/black by renderer. */
|
|
97
|
+
color?: string;
|
|
98
|
+
highlight?: string;
|
|
99
|
+
/** Character shading fill (w:shd). */
|
|
100
|
+
shading?: string;
|
|
101
|
+
/** Run border (w:bdr): a box painted around the run. Word merges adjacent
|
|
102
|
+
* runs with identical borders into one box; a run wrapping across lines
|
|
103
|
+
* closes the box on every line segment. */
|
|
104
|
+
border?: Border;
|
|
105
|
+
verticalAlign?: "baseline" | "superscript" | "subscript";
|
|
106
|
+
caps?: boolean;
|
|
107
|
+
smallCaps?: boolean;
|
|
108
|
+
/** Letter spacing px (w:spacing, twips in OOXML). */
|
|
109
|
+
letterSpacing?: number;
|
|
110
|
+
/** Minimum font size in px at which w:kern enables pair kerning; null is
|
|
111
|
+
* the explicit w:kern=0 override. */
|
|
112
|
+
kerningThreshold?: number | null;
|
|
113
|
+
/** Paint-only letter spacing when layout advances intentionally differ. */
|
|
114
|
+
paintLetterSpacing?: number;
|
|
115
|
+
/** w:w horizontal character scaling as a fraction (1.5 = 150%). */
|
|
116
|
+
textScale?: number;
|
|
117
|
+
/** w:fitText target width in px: the run's advances scale so its text
|
|
118
|
+
* occupies exactly this width (resolved to textScale at layout time). */
|
|
119
|
+
fitText?: number;
|
|
120
|
+
/** w:position baseline shift in px, positive = raised. */
|
|
121
|
+
raise?: number;
|
|
122
|
+
/** w:outline — hollow stroked glyphs. */
|
|
123
|
+
outline?: boolean;
|
|
124
|
+
/** w:emboss / w:imprint — Word triple-draws offset copies. */
|
|
125
|
+
emboss?: boolean;
|
|
126
|
+
imprint?: boolean;
|
|
127
|
+
vanish?: boolean;
|
|
128
|
+
/** Character style id (w:rStyle). */
|
|
129
|
+
styleId?: string;
|
|
130
|
+
lang?: string;
|
|
131
|
+
}
|
|
132
|
+
interface NumberingRef {
|
|
133
|
+
numId: number;
|
|
134
|
+
ilvl: number;
|
|
135
|
+
}
|
|
136
|
+
interface ParaProps {
|
|
137
|
+
styleId?: string;
|
|
138
|
+
alignment?: Alignment;
|
|
139
|
+
/** The exact OOXML w:jc value when it is a "justify" flavor whose behavior
|
|
140
|
+
* differs from plain "both": `distribute` also stretches the LAST line, and
|
|
141
|
+
* the Arabic `*Kashida` levels elongate glyphs (kashida) so lines pack fewer
|
|
142
|
+
* words and — at medium/high — wrap to more lines. Absent for plain "both".
|
|
143
|
+
* `alignment` stays "justify" for all of these. */
|
|
144
|
+
justifyKind?: "distribute" | "lowKashida" | "mediumKashida" | "highKashida";
|
|
145
|
+
/** w:bidi — right-to-left paragraph: lines assemble RTL and default
|
|
146
|
+
* alignment flips to the right edge. */
|
|
147
|
+
bidi?: boolean;
|
|
148
|
+
/** px */
|
|
149
|
+
indentLeft?: number;
|
|
150
|
+
indentRight?: number;
|
|
151
|
+
/** Positive px; mutually exclusive with hanging in effect. */
|
|
152
|
+
indentFirstLine?: number;
|
|
153
|
+
/** Positive px hanging indent. */
|
|
154
|
+
indentHanging?: number;
|
|
155
|
+
spacingBefore?: number;
|
|
156
|
+
spacingAfter?: number;
|
|
157
|
+
/** w:beforeAutospacing/afterAutospacing: HTML-style automatic paragraph
|
|
158
|
+
* spacing — Word ignores the literal before/after and inserts one blank
|
|
159
|
+
* line's worth of space. */
|
|
160
|
+
beforeAutospacing?: boolean;
|
|
161
|
+
afterAutospacing?: boolean;
|
|
162
|
+
/** Word's default when absent is auto/1.0 via docDefaults. */
|
|
163
|
+
lineSpacing?: LineSpacing;
|
|
164
|
+
/** w:snapToGrid: whether this paragraph's lines use the section docGrid. */
|
|
165
|
+
snapToGrid?: boolean;
|
|
166
|
+
contextualSpacing?: boolean;
|
|
167
|
+
keepNext?: boolean;
|
|
168
|
+
/** w:framePr w:dropCap: the paragraph is a drop-cap letter frame. */
|
|
169
|
+
dropCap?: {
|
|
170
|
+
mode: "drop" | "margin";
|
|
171
|
+
lines: number;
|
|
172
|
+
hSpace: number;
|
|
173
|
+
pageAnchored?: boolean;
|
|
174
|
+
};
|
|
175
|
+
/** w:framePr positioned text frame (absolute-positioned paragraph the body
|
|
176
|
+
* text wraps around). Geometry in px. Individual attributes are optional so a
|
|
177
|
+
* framePr merges attribute-by-attribute across the style cascade (a direct
|
|
178
|
+
* framePr that sets only h/x/y keeps the style framePr's width/anchor — IEEE
|
|
179
|
+
* authors); the engine normalizes defaults at layout time. */
|
|
180
|
+
frame?: {
|
|
181
|
+
w?: number;
|
|
182
|
+
h?: number;
|
|
183
|
+
hRule?: "auto" | "atLeast" | "exact";
|
|
184
|
+
x?: number;
|
|
185
|
+
y?: number;
|
|
186
|
+
hAnchor?: "page" | "margin" | "text" | "column";
|
|
187
|
+
vAnchor?: "page" | "margin" | "text" | "paragraph";
|
|
188
|
+
xAlign?: "left" | "center" | "right" | "inside" | "outside";
|
|
189
|
+
yAlign?: "top" | "center" | "bottom" | "inside" | "outside" | "inline";
|
|
190
|
+
wrap?: "around" | "auto" | "notBeside" | "through" | "tight" | "none";
|
|
191
|
+
/** w:hSpace / w:vSpace: horizontal/vertical margin around the frame (px). */
|
|
192
|
+
hSpace?: number;
|
|
193
|
+
vSpace?: number;
|
|
194
|
+
};
|
|
195
|
+
keepLines?: boolean;
|
|
196
|
+
pageBreakBefore?: boolean;
|
|
197
|
+
widowControl?: boolean;
|
|
198
|
+
borders?: ParagraphBorders;
|
|
199
|
+
/** Paragraph shading fill as CSS color. */
|
|
200
|
+
shading?: string;
|
|
201
|
+
numbering?: NumberingRef | null;
|
|
202
|
+
/** A numPr that carries ilvl but no numId (Heading3 basedOn Heading2)
|
|
203
|
+
* overrides only the list LEVEL, keeping the inherited numId; the style
|
|
204
|
+
* chain applies it to `numbering` on merge. */
|
|
205
|
+
numberingLevelOverride?: number;
|
|
206
|
+
tabs?: TabStop[];
|
|
207
|
+
outlineLevel?: number;
|
|
208
|
+
/** Run props declared on pPr/rPr — apply to the paragraph mark & numbering label. */
|
|
209
|
+
markRunProps?: RunProps;
|
|
210
|
+
/**
|
|
211
|
+
* styleId of the enclosing table (set on cell paragraphs at parse time).
|
|
212
|
+
* A table style's own pPr layers between docDefaults and the paragraph
|
|
213
|
+
* style, e.g. TableGrid's `spacing after=0 line=240` overrides docDefaults'
|
|
214
|
+
* `after=200 line=276` so list cells lay out compactly.
|
|
215
|
+
*/
|
|
216
|
+
tableStyleId?: string;
|
|
217
|
+
/**
|
|
218
|
+
* Grid position of the enclosing cell plus the table's tblLook (set on cell
|
|
219
|
+
* paragraphs at parse time, like tableStyleId). Lets run/paragraph
|
|
220
|
+
* resolution layer the applicable w:tblStylePr conditional formats (e.g.
|
|
221
|
+
* firstRow bold + white) between the table style's own rPr and the
|
|
222
|
+
* paragraph style chain.
|
|
223
|
+
*/
|
|
224
|
+
tableCellCond?: {
|
|
225
|
+
look?: TableLook;
|
|
226
|
+
rowIdx: number;
|
|
227
|
+
nRows: number;
|
|
228
|
+
colStart: number;
|
|
229
|
+
colSpan: number;
|
|
230
|
+
nCols: number;
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
interface TextContent {
|
|
234
|
+
kind: "text";
|
|
235
|
+
text: string;
|
|
236
|
+
/** Source w:t element inside the run, when this text came verbatim from one. */
|
|
237
|
+
srcT?: XmlElement;
|
|
238
|
+
/** When this text is the glyph of a modern checkbox content control, the
|
|
239
|
+
* source `w14:checkbox` element (in the enclosing w:sdt's sdtPr). Its
|
|
240
|
+
* presence makes the glyph a click-to-toggle target rather than plain text. */
|
|
241
|
+
checkbox?: XmlElement;
|
|
242
|
+
}
|
|
243
|
+
interface BreakContent {
|
|
244
|
+
kind: "break";
|
|
245
|
+
breakType: "line" | "page" | "column";
|
|
246
|
+
}
|
|
247
|
+
interface TabContent {
|
|
248
|
+
kind: "tab";
|
|
249
|
+
}
|
|
250
|
+
interface PTabContent {
|
|
251
|
+
kind: "ptab";
|
|
252
|
+
/** Absolute-position tab: jump to left/center/right of the base. */
|
|
253
|
+
alignment: "left" | "center" | "right";
|
|
254
|
+
relativeTo: "margin" | "indent";
|
|
255
|
+
}
|
|
256
|
+
interface ImageContent {
|
|
257
|
+
kind: "image";
|
|
258
|
+
/** Part path of the image inside the package. */
|
|
259
|
+
part: string;
|
|
260
|
+
width: number;
|
|
261
|
+
height: number;
|
|
262
|
+
/** True when the drawing is floating (wp:anchor); v1 lays it out inline. */
|
|
263
|
+
anchored?: boolean;
|
|
264
|
+
/** a:srcRect crop, fractions of the source bitmap. */
|
|
265
|
+
crop?: {
|
|
266
|
+
l: number;
|
|
267
|
+
t: number;
|
|
268
|
+
r: number;
|
|
269
|
+
b: number;
|
|
270
|
+
};
|
|
271
|
+
/** a:xfrm rotation, degrees clockwise. */
|
|
272
|
+
rotation?: number;
|
|
273
|
+
/** a:ln picture outline (Word draws it just outside the image). */
|
|
274
|
+
border?: {
|
|
275
|
+
color: string;
|
|
276
|
+
width: number;
|
|
277
|
+
};
|
|
278
|
+
/** Source w:drawing (or pict) element, for resize/move editing. */
|
|
279
|
+
srcDrawing?: XmlElement;
|
|
280
|
+
/** Native Office 3D model shown through its saved poster raster. */
|
|
281
|
+
model3D?: Model3DReference;
|
|
282
|
+
/** Word online-video metadata shown through its saved poster raster. */
|
|
283
|
+
webVideo?: WebVideoReference;
|
|
284
|
+
/** Embedded OLE package activated as a safe download in the browser. */
|
|
285
|
+
embeddedObject?: EmbeddedObjectReference;
|
|
286
|
+
}
|
|
287
|
+
interface Model3DReference {
|
|
288
|
+
part: string;
|
|
289
|
+
posterPart: string;
|
|
290
|
+
/** Native Office model orientation, in degrees around the X/Y/Z axes. */
|
|
291
|
+
rotation?: {
|
|
292
|
+
x: number;
|
|
293
|
+
y: number;
|
|
294
|
+
z: number;
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
interface WebVideoReference {
|
|
298
|
+
url: string;
|
|
299
|
+
embeddedHtml: string;
|
|
300
|
+
width: number;
|
|
301
|
+
height: number;
|
|
302
|
+
}
|
|
303
|
+
interface EmbeddedObjectReference {
|
|
304
|
+
part: string;
|
|
305
|
+
filename: string;
|
|
306
|
+
progId: string;
|
|
307
|
+
}
|
|
308
|
+
/** OMML equation node (subset: runs, scripts, fractions, radicals). */
|
|
309
|
+
type MathNode = {
|
|
310
|
+
t: "run";
|
|
311
|
+
text: string;
|
|
312
|
+
normal?: boolean;
|
|
313
|
+
/** m:func function name (cos, log, …): Word kerns a thin space on
|
|
314
|
+
* both sides of the name. */
|
|
315
|
+
fname?: boolean;
|
|
316
|
+
} | {
|
|
317
|
+
t: "sup" | "sub";
|
|
318
|
+
base: MathNode[];
|
|
319
|
+
script: MathNode[];
|
|
320
|
+
} | {
|
|
321
|
+
t: "frac";
|
|
322
|
+
num: MathNode[];
|
|
323
|
+
den: MathNode[];
|
|
324
|
+
bar?: boolean;
|
|
325
|
+
}
|
|
326
|
+
/** Radical; deg is the optional m:deg index (∛), absent when m:degHide. */
|
|
327
|
+
| {
|
|
328
|
+
t: "rad";
|
|
329
|
+
e: MathNode[];
|
|
330
|
+
deg?: MathNode[];
|
|
331
|
+
}
|
|
332
|
+
/** n-ary operator (sum/integral); chr defaults to the integral sign. */
|
|
333
|
+
| {
|
|
334
|
+
t: "nary";
|
|
335
|
+
chr: string;
|
|
336
|
+
sub: MathNode[];
|
|
337
|
+
sup: MathNode[];
|
|
338
|
+
e: MathNode[];
|
|
339
|
+
}
|
|
340
|
+
/** Delimiters grown to the content height; beg/end default to parens.
|
|
341
|
+
* An empty beg/end string means that side has no delimiter (cases "{"). */
|
|
342
|
+
| {
|
|
343
|
+
t: "dlm";
|
|
344
|
+
beg: string;
|
|
345
|
+
end: string;
|
|
346
|
+
e: MathNode[][];
|
|
347
|
+
}
|
|
348
|
+
/** Matrix: rows x cells. */
|
|
349
|
+
| {
|
|
350
|
+
t: "mat";
|
|
351
|
+
rows: MathNode[][][];
|
|
352
|
+
}
|
|
353
|
+
/** m:eqArr equation array (cases/piecewise rows). */
|
|
354
|
+
| {
|
|
355
|
+
t: "eqarr";
|
|
356
|
+
rows: MathNode[][];
|
|
357
|
+
}
|
|
358
|
+
/** m:acc combining accent (hat/bar/vector) over the base. */
|
|
359
|
+
| {
|
|
360
|
+
t: "acc";
|
|
361
|
+
chr: string;
|
|
362
|
+
e: MathNode[];
|
|
363
|
+
}
|
|
364
|
+
/** m:groupChr horizontal group character (over/under brace). */
|
|
365
|
+
| {
|
|
366
|
+
t: "grp";
|
|
367
|
+
chr: string;
|
|
368
|
+
pos: "top" | "bot";
|
|
369
|
+
vertJc: "top" | "bot";
|
|
370
|
+
e: MathNode[];
|
|
371
|
+
}
|
|
372
|
+
/** m:limLow / m:limUpp limit stacked under/over a text operator. */
|
|
373
|
+
| {
|
|
374
|
+
t: "lim";
|
|
375
|
+
pos: "low" | "upp";
|
|
376
|
+
e: MathNode[];
|
|
377
|
+
lim: MathNode[];
|
|
378
|
+
};
|
|
379
|
+
interface MathContent {
|
|
380
|
+
kind: "math";
|
|
381
|
+
nodes: MathNode[];
|
|
382
|
+
/** Source m:oMath element (math editing). */
|
|
383
|
+
src?: XmlElement;
|
|
384
|
+
/** Display equation (wrapped in m:oMathPara): centered on its own line with
|
|
385
|
+
* display-style layout - larger n-ary operators with limits stacked
|
|
386
|
+
* above/below, and full-size fraction numerators/denominators. */
|
|
387
|
+
display?: boolean;
|
|
388
|
+
/** Display group with several direct equations. Word leaves a small
|
|
389
|
+
* advance after script clusters in these grouped displays. */
|
|
390
|
+
multiEquationDisplay?: boolean;
|
|
391
|
+
/** m:oMathParaPr/m:jc - display-equation justification. Absent: the
|
|
392
|
+
* document default (settings m:mathPr/m:defJc, itself "centerGroup" when
|
|
393
|
+
* unset). */
|
|
394
|
+
jc?: "left" | "right" | "center" | "centerGroup";
|
|
395
|
+
}
|
|
396
|
+
interface FieldContent {
|
|
397
|
+
kind: "field";
|
|
398
|
+
/** Raw field instruction, e.g. ` PAGE \\* MERGEFORMAT `. */
|
|
399
|
+
instruction: string;
|
|
400
|
+
/** Last cached result text from the file, used for unsupported fields. */
|
|
401
|
+
cachedResult: string;
|
|
402
|
+
/** When this field is a legacy FORMCHECKBOX, the source `w:checkBox` element
|
|
403
|
+
* (in the fldChar begin's w:ffData). Its presence makes the rendered ballot
|
|
404
|
+
* box a click-to-toggle target; the glyph derives from its w:checked child. */
|
|
405
|
+
checkbox?: XmlElement;
|
|
406
|
+
}
|
|
407
|
+
/** What an anchored shape's coordinates are measured from. "char" (relH=
|
|
408
|
+
* "character") measures from the anchor run's pen position; "line" (relV=
|
|
409
|
+
* "line") from the top of the line holding the anchor — both resolved from
|
|
410
|
+
* the anchor paragraph's first-pass layout. */
|
|
411
|
+
type AnchorRel = "page" | "margin" | "text" | "column" | "char" | "line";
|
|
412
|
+
interface ShapeLine {
|
|
413
|
+
type: "line";
|
|
414
|
+
x1: number;
|
|
415
|
+
y1: number;
|
|
416
|
+
x2: number;
|
|
417
|
+
y2: number;
|
|
418
|
+
color: string;
|
|
419
|
+
/** Stroke weight px. */
|
|
420
|
+
weight: number;
|
|
421
|
+
style?: "single" | "dotted" | "dashed";
|
|
422
|
+
hRel: AnchorRel;
|
|
423
|
+
vRel: AnchorRel;
|
|
424
|
+
/** Source VML v:line for selection and save-back editing. */
|
|
425
|
+
src?: XmlElement;
|
|
426
|
+
}
|
|
427
|
+
interface ShapeTextbox {
|
|
428
|
+
type: "textbox";
|
|
429
|
+
x: number;
|
|
430
|
+
y: number;
|
|
431
|
+
width: number;
|
|
432
|
+
height: number;
|
|
433
|
+
hRel: AnchorRel;
|
|
434
|
+
vRel: AnchorRel;
|
|
435
|
+
blocks: Block[];
|
|
436
|
+
/** Background fill (CSS color) painted behind the text. */
|
|
437
|
+
fill?: string;
|
|
438
|
+
/** Outline. */
|
|
439
|
+
stroke?: {
|
|
440
|
+
color: string;
|
|
441
|
+
weight: number;
|
|
442
|
+
};
|
|
443
|
+
/** Alignment-based positioning (mso-position-horizontal/vertical). */
|
|
444
|
+
hAlign?: "left" | "center" | "right";
|
|
445
|
+
vAlign?: "top" | "center" | "bottom";
|
|
446
|
+
/** Percent-of-base geometry, 0..1 (mso-*-percent / wp14 pct offsets).
|
|
447
|
+
* Bases: pctWidthRel/pctHeightRel say page vs margin. */
|
|
448
|
+
pctX?: number;
|
|
449
|
+
pctY?: number;
|
|
450
|
+
pctWidth?: number;
|
|
451
|
+
pctHeight?: number;
|
|
452
|
+
pctWidthRel?: "page" | "margin";
|
|
453
|
+
pctHeightRel?: "page" | "margin";
|
|
454
|
+
/** Vertical anchoring of the text INSIDE the box (v-text-anchor). */
|
|
455
|
+
textAnchor?: "top" | "middle" | "bottom";
|
|
456
|
+
/** How body text flows around a DrawingML textbox (wp:wrap*). */
|
|
457
|
+
wrap?: WrapMode;
|
|
458
|
+
/** behindDoc: paint under the body text, never displace it. */
|
|
459
|
+
behind?: boolean;
|
|
460
|
+
/** wp:anchor @allowOverlap="0": Word shifts this shape clear of earlier
|
|
461
|
+
* overlapping floats rather than letting them overlap. Default true. */
|
|
462
|
+
allowOverlap?: boolean;
|
|
463
|
+
/** Wrap distances px (wp:anchor distT/B/L/R). */
|
|
464
|
+
dist?: {
|
|
465
|
+
t: number;
|
|
466
|
+
b: number;
|
|
467
|
+
l: number;
|
|
468
|
+
r: number;
|
|
469
|
+
};
|
|
470
|
+
/** a:xfrm rotation, degrees clockwise (rotates the whole box). */
|
|
471
|
+
rotation?: number;
|
|
472
|
+
/** Text insets px (bodyPr lIns/tIns/rIns/bIns); default 9.6/4.8. For
|
|
473
|
+
* non-rect preset geometries these INCLUDE the geometry's text-rectangle
|
|
474
|
+
* insets (ellipse: inscribed rect; diamond: middle-half rect). */
|
|
475
|
+
insets?: {
|
|
476
|
+
l: number;
|
|
477
|
+
t: number;
|
|
478
|
+
r: number;
|
|
479
|
+
b: number;
|
|
480
|
+
};
|
|
481
|
+
/** Non-rect preset geometry: paint this outline (in a viewW x viewH space
|
|
482
|
+
* scaled to the shape box) instead of a rectangle. */
|
|
483
|
+
geom?: {
|
|
484
|
+
d: string;
|
|
485
|
+
viewW: number;
|
|
486
|
+
viewH: number;
|
|
487
|
+
};
|
|
488
|
+
/** bodyPr a:noAutofit: the box does NOT grow with its text — Word hides
|
|
489
|
+
* whole lines that stick out past the shape bottom (phase23 p12 ovals:
|
|
490
|
+
* "Was 0 / B" visible, the wrapped tail rows hidden). */
|
|
491
|
+
clipText?: boolean;
|
|
492
|
+
/** bodyPr a:spAutoFit: the box grows in height to exactly fit its laid text
|
|
493
|
+
* plus the top/bottom insets (the stored cy is only Word's last cached
|
|
494
|
+
* value). Width is fixed. */
|
|
495
|
+
autofitHeight?: boolean;
|
|
496
|
+
/** Linked text-box chain id (wps:txbx/@id or wps:linkedTxbx/@id): boxes with
|
|
497
|
+
* the same id form one story. The seq-0 box (wps:txbx) holds the content;
|
|
498
|
+
* later boxes (wps:linkedTxbx, chainSeq>0) are empty sinks that continue the
|
|
499
|
+
* overflow. */
|
|
500
|
+
chainId?: string;
|
|
501
|
+
/** Position in the linked chain (0 = the content box). */
|
|
502
|
+
chainSeq?: number;
|
|
503
|
+
/** Source w:drawing element, attached at parse time so the shape's fill can
|
|
504
|
+
* be an interactive hit target (select the shape instead of the body text
|
|
505
|
+
* behind it). */
|
|
506
|
+
srcDrawing?: XmlElement;
|
|
507
|
+
/** Header/footer-owned textbox whose text is edited as an independent story. */
|
|
508
|
+
textboxStory?: boolean;
|
|
509
|
+
/** DrawingML WordArt, including the identity textNoShape preset. */
|
|
510
|
+
wordArt?: boolean;
|
|
511
|
+
/** WordArt glyph fill from w14:textFill or the fallback run color. */
|
|
512
|
+
wordArtFill?: string;
|
|
513
|
+
/** WordArt glyph alpha, 0..1. */
|
|
514
|
+
wordArtOpacity?: number;
|
|
515
|
+
/** bodyPr a:prstTxWarp preset name (textArchUp, textWave1, textChevron,
|
|
516
|
+
* textCirclePour, …): the shape's text is bent onto the preset's envelope
|
|
517
|
+
* rather than flowed as ordinary lines. "textNoShape" (no warp) is dropped. */
|
|
518
|
+
warp?: string;
|
|
519
|
+
}
|
|
520
|
+
/** WordArt (VML v:textpath, e.g. a "CONFIDENTIAL" watermark): text scaled to
|
|
521
|
+
* fill a box, optionally rotated, painted semi-transparent behind the body. */
|
|
522
|
+
interface ShapeWordArt {
|
|
523
|
+
type: "wordart";
|
|
524
|
+
text: string;
|
|
525
|
+
fontFamily: string;
|
|
526
|
+
bold?: boolean;
|
|
527
|
+
italic?: boolean;
|
|
528
|
+
/** CSS fill color. */
|
|
529
|
+
fill: string;
|
|
530
|
+
/** 0..1 alpha. */
|
|
531
|
+
opacity: number;
|
|
532
|
+
x: number;
|
|
533
|
+
y: number;
|
|
534
|
+
width: number;
|
|
535
|
+
height: number;
|
|
536
|
+
hRel: AnchorRel;
|
|
537
|
+
vRel: AnchorRel;
|
|
538
|
+
hAlign?: "left" | "center" | "right";
|
|
539
|
+
vAlign?: "top" | "center" | "bottom";
|
|
540
|
+
/** Clockwise degrees. */
|
|
541
|
+
rotation: number;
|
|
542
|
+
behind?: boolean;
|
|
543
|
+
/** The source v:textpath font-size (px). */
|
|
544
|
+
fontSize?: number;
|
|
545
|
+
/** The referenced v:shapetype has a malformed text-guide path (missing
|
|
546
|
+
* coordinates), so Word collapses its horizontal glyph outlines into a thin
|
|
547
|
+
* vertical band instead of painting a box-filling watermark. */
|
|
548
|
+
noFit?: boolean;
|
|
549
|
+
/** Source VML shape element (v:shape / v:rect) for interactive editing:
|
|
550
|
+
* the v:textpath string, fill/opacity, and rotation live under it. */
|
|
551
|
+
src?: XmlElement;
|
|
552
|
+
}
|
|
553
|
+
interface ShapeArt {
|
|
554
|
+
type: "art";
|
|
555
|
+
srcDrawing?: XmlElement;
|
|
556
|
+
/** A freehand stroke, selectable by the Draw ribbon's stroke eraser. */
|
|
557
|
+
ink?: boolean;
|
|
558
|
+
x: number;
|
|
559
|
+
y: number;
|
|
560
|
+
/** Percent-of-page offsets (wp14:pctPos*Offset), 0..1. */
|
|
561
|
+
pctX?: number;
|
|
562
|
+
pctY?: number;
|
|
563
|
+
width: number;
|
|
564
|
+
height: number;
|
|
565
|
+
hRel: AnchorRel;
|
|
566
|
+
vRel: AnchorRel;
|
|
567
|
+
hAlign?: "left" | "center" | "right";
|
|
568
|
+
vAlign?: "top" | "center" | "bottom";
|
|
569
|
+
behind?: boolean;
|
|
570
|
+
/** a:xfrm rotation, degrees clockwise. */
|
|
571
|
+
rotation?: number;
|
|
572
|
+
lines: DrawingLine[];
|
|
573
|
+
images: DrawingImage[];
|
|
574
|
+
paths: DrawingPath[];
|
|
575
|
+
/** Positioned text bodies inside the group (wps textboxes, dsp:sp txBody). */
|
|
576
|
+
texts?: DrawingTextShape[];
|
|
577
|
+
}
|
|
578
|
+
/** How text interacts with a floating image. */
|
|
579
|
+
type WrapMode = "square" | "topAndBottom" | "none";
|
|
580
|
+
interface ShapeImage {
|
|
581
|
+
type: "image";
|
|
582
|
+
part: string;
|
|
583
|
+
/** Offset from the anchor origin, px. */
|
|
584
|
+
x: number;
|
|
585
|
+
y: number;
|
|
586
|
+
width: number;
|
|
587
|
+
height: number;
|
|
588
|
+
hRel: AnchorRel;
|
|
589
|
+
vRel: AnchorRel;
|
|
590
|
+
/** Horizontal alignment when the file uses wp:align instead of an offset. */
|
|
591
|
+
hAlign?: "left" | "center" | "right";
|
|
592
|
+
/** Vertical alignment keyword (VML mso-position-vertical; watermarks center). */
|
|
593
|
+
vAlign?: "top" | "center" | "bottom";
|
|
594
|
+
wrap: WrapMode;
|
|
595
|
+
/** behindDoc anchors render under the text and never displace it. */
|
|
596
|
+
behind?: boolean;
|
|
597
|
+
/** Wrap distances px (wp:anchor distT/B/L/R); text clears the image by these. */
|
|
598
|
+
dist?: {
|
|
599
|
+
t: number;
|
|
600
|
+
b: number;
|
|
601
|
+
l: number;
|
|
602
|
+
r: number;
|
|
603
|
+
};
|
|
604
|
+
crop?: {
|
|
605
|
+
l: number;
|
|
606
|
+
t: number;
|
|
607
|
+
r: number;
|
|
608
|
+
b: number;
|
|
609
|
+
};
|
|
610
|
+
rotation?: number;
|
|
611
|
+
/** Watermark "washout" recolor (VML v:imagedata gain/blacklevel, 0..1). */
|
|
612
|
+
washout?: {
|
|
613
|
+
gain: number;
|
|
614
|
+
blacklevel: number;
|
|
615
|
+
};
|
|
616
|
+
/** Source w:drawing element (editing). */
|
|
617
|
+
srcDrawing?: XmlElement;
|
|
618
|
+
model3D?: Model3DReference;
|
|
619
|
+
webVideo?: WebVideoReference;
|
|
620
|
+
embeddedObject?: EmbeddedObjectReference;
|
|
621
|
+
}
|
|
622
|
+
type Shape = (ShapeLine | ShapeTextbox | ShapeImage | ShapeArt | ShapeWordArt) & {
|
|
623
|
+
/** wp:anchor relativeHeight, used for object stacking order. */
|
|
624
|
+
z?: number;
|
|
625
|
+
};
|
|
626
|
+
/**
|
|
627
|
+
* Floating/anchored object: does not occupy inline space; positioned against
|
|
628
|
+
* page/margin/paragraph during layout. (How classic pleading paper draws its
|
|
629
|
+
* margin line numbers and vertical rules.)
|
|
630
|
+
*/
|
|
631
|
+
interface AnchorContent {
|
|
632
|
+
kind: "anchor";
|
|
633
|
+
shape: Shape;
|
|
634
|
+
}
|
|
635
|
+
/** A stroked segment inside a composite drawing, px relative to its box. */
|
|
636
|
+
interface DrawingLine {
|
|
637
|
+
x1: number;
|
|
638
|
+
y1: number;
|
|
639
|
+
x2: number;
|
|
640
|
+
y2: number;
|
|
641
|
+
color: string;
|
|
642
|
+
weight: number;
|
|
643
|
+
style?: "single" | "dotted" | "dashed";
|
|
644
|
+
}
|
|
645
|
+
interface DrawingImage {
|
|
646
|
+
part: string;
|
|
647
|
+
x: number;
|
|
648
|
+
y: number;
|
|
649
|
+
width: number;
|
|
650
|
+
height: number;
|
|
651
|
+
crop?: {
|
|
652
|
+
l: number;
|
|
653
|
+
t: number;
|
|
654
|
+
r: number;
|
|
655
|
+
b: number;
|
|
656
|
+
};
|
|
657
|
+
rotation?: number;
|
|
658
|
+
/** a:ln picture outline (Word draws it just outside the image). */
|
|
659
|
+
border?: {
|
|
660
|
+
color: string;
|
|
661
|
+
width: number;
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
/**
|
|
665
|
+
* Composite inline drawing (DrawingML groups): vector lines + placed images
|
|
666
|
+
* inside a width×height box that flows like an image.
|
|
667
|
+
*/
|
|
668
|
+
interface DrawingContent {
|
|
669
|
+
kind: "drawing";
|
|
670
|
+
width: number;
|
|
671
|
+
height: number;
|
|
672
|
+
lines: DrawingLine[];
|
|
673
|
+
images: DrawingImage[];
|
|
674
|
+
/** Native ChartML chart data resolved from the related chart part. */
|
|
675
|
+
chart?: ChartData;
|
|
676
|
+
/** Native SmartArt diagram data resolved from its diagram parts. */
|
|
677
|
+
smartArt?: SmartArtData;
|
|
678
|
+
/** Freeform vector shapes (a:custGeom), as SVG path data. */
|
|
679
|
+
paths?: DrawingPath[];
|
|
680
|
+
/** An INLINE wps text box (wp:inline wps:txbx): a fixed-extent box that
|
|
681
|
+
* flows in the text (occupying its width x height like an inline image) and
|
|
682
|
+
* carries a fill/border + its own block content. Distinct from the floating
|
|
683
|
+
* ShapeTextbox, which is absolutely placed via a wp:anchor. */
|
|
684
|
+
textbox?: {
|
|
685
|
+
blocks: Block[];
|
|
686
|
+
fill?: string;
|
|
687
|
+
stroke?: {
|
|
688
|
+
color: string;
|
|
689
|
+
weight: number;
|
|
690
|
+
};
|
|
691
|
+
insets?: {
|
|
692
|
+
l: number;
|
|
693
|
+
t: number;
|
|
694
|
+
r: number;
|
|
695
|
+
b: number;
|
|
696
|
+
};
|
|
697
|
+
textAnchor?: "top" | "middle" | "bottom";
|
|
698
|
+
};
|
|
699
|
+
/** Source w:drawing element (select/move as a group). */
|
|
700
|
+
srcDrawing?: XmlElement;
|
|
701
|
+
/** Positioned text bodies inside the drawing (multi-textbox groups and
|
|
702
|
+
* SmartArt cached-drawing shapes). Painted above lines/paths. */
|
|
703
|
+
texts?: DrawingTextShape[];
|
|
704
|
+
}
|
|
705
|
+
type ChartType = "column" | "bar" | "line" | "pie";
|
|
706
|
+
interface ChartSeries {
|
|
707
|
+
name: string;
|
|
708
|
+
values: number[];
|
|
709
|
+
}
|
|
710
|
+
interface ChartData {
|
|
711
|
+
type: ChartType;
|
|
712
|
+
title?: string;
|
|
713
|
+
categories: string[];
|
|
714
|
+
series: ChartSeries[];
|
|
715
|
+
}
|
|
716
|
+
type SmartArtLayout = "process" | "cycle" | "hierarchy" | "list";
|
|
717
|
+
interface SmartArtData {
|
|
718
|
+
layout: SmartArtLayout;
|
|
719
|
+
items: string[];
|
|
720
|
+
}
|
|
721
|
+
/** A text body positioned inside a composite drawing (a wps textbox in a
|
|
722
|
+
* group, or a SmartArt dsp:sp txBody), px relative to the drawing's box. */
|
|
723
|
+
interface DrawingTextShape {
|
|
724
|
+
x: number;
|
|
725
|
+
y: number;
|
|
726
|
+
width: number;
|
|
727
|
+
height: number;
|
|
728
|
+
blocks: Block[];
|
|
729
|
+
/** Background fill painted behind the text box. */
|
|
730
|
+
fill?: string;
|
|
731
|
+
/** Outline. */
|
|
732
|
+
stroke?: {
|
|
733
|
+
color: string;
|
|
734
|
+
weight: number;
|
|
735
|
+
};
|
|
736
|
+
/** Text insets px (bodyPr lIns/tIns/rIns/bIns). */
|
|
737
|
+
insets: {
|
|
738
|
+
l: number;
|
|
739
|
+
t: number;
|
|
740
|
+
r: number;
|
|
741
|
+
b: number;
|
|
742
|
+
};
|
|
743
|
+
/** Vertical anchoring of the text inside the box (bodyPr anchor). */
|
|
744
|
+
textAnchor?: "top" | "middle" | "bottom";
|
|
745
|
+
/** DrawingML cached text paint-only baseline adjustment in px. */
|
|
746
|
+
paintOffsetY?: number;
|
|
747
|
+
}
|
|
748
|
+
interface DrawingPath {
|
|
749
|
+
/** Position/size inside the drawing, px. */
|
|
750
|
+
x: number;
|
|
751
|
+
y: number;
|
|
752
|
+
width: number;
|
|
753
|
+
height: number;
|
|
754
|
+
/** SVG path in the `viewW x viewH` source coordinate space. */
|
|
755
|
+
d: string;
|
|
756
|
+
viewW: number;
|
|
757
|
+
viewH: number;
|
|
758
|
+
fill?: string;
|
|
759
|
+
stroke?: {
|
|
760
|
+
color: string;
|
|
761
|
+
width: number;
|
|
762
|
+
opacity?: number;
|
|
763
|
+
};
|
|
764
|
+
/** Zero-based visible SmartArt node this path paints. */
|
|
765
|
+
smartArtNodeIndex?: number;
|
|
766
|
+
}
|
|
767
|
+
/**
|
|
768
|
+
* Footnote/endnote reference mark. In body text (w:footnoteReference /
|
|
769
|
+
* w:endnoteReference) `id` points into the notes part. Inside a note body,
|
|
770
|
+
* w:footnoteRef / w:endnoteRef render the note's own mark: `self` is true and
|
|
771
|
+
* `id` is meaningless.
|
|
772
|
+
*/
|
|
773
|
+
interface NoteRefContent {
|
|
774
|
+
kind: "noteRef";
|
|
775
|
+
noteType: "footnote" | "endnote";
|
|
776
|
+
id: number;
|
|
777
|
+
self?: boolean;
|
|
778
|
+
/** The document supplies the visible mark in the following run content. */
|
|
779
|
+
customMarkFollows?: boolean;
|
|
780
|
+
}
|
|
781
|
+
/** w:ruby — an East-Asian ruby (furigana) cluster: an annotation run (w:rt)
|
|
782
|
+
* riding above a base run (w:rubyBase). Both sides render as their own runs;
|
|
783
|
+
* the annotation is centered over the base and raised above its baseline. */
|
|
784
|
+
interface RubyContent {
|
|
785
|
+
kind: "ruby";
|
|
786
|
+
base: Run;
|
|
787
|
+
rt: Run;
|
|
788
|
+
/** w:rubyPr/w:hpsRaise — annotation baseline raise above the base baseline,
|
|
789
|
+
* half-points. */
|
|
790
|
+
hpsRaise?: number;
|
|
791
|
+
/** w:rubyPr/w:rubyAlign — how the annotation distributes over the base. */
|
|
792
|
+
align?: "center" | "distributeLetter" | "distributeSpace" | "left" | "right" | "rightVertical";
|
|
793
|
+
}
|
|
794
|
+
type RunContent = MathContent | TextContent | BreakContent | TabContent | PTabContent | ImageContent | FieldContent | AnchorContent | DrawingContent | NoteRefContent | RubyContent;
|
|
795
|
+
interface Run {
|
|
796
|
+
type: "run";
|
|
797
|
+
props: RunProps;
|
|
798
|
+
content: RunContent[];
|
|
799
|
+
/** Source w:r element. */
|
|
800
|
+
src?: XmlElement;
|
|
801
|
+
/** Element whose children array contains src (w:p, w:hyperlink, …). */
|
|
802
|
+
srcParent?: XmlElement;
|
|
803
|
+
}
|
|
804
|
+
interface Hyperlink {
|
|
805
|
+
type: "hyperlink";
|
|
806
|
+
href?: string;
|
|
807
|
+
anchor?: string;
|
|
808
|
+
runs: Run[];
|
|
809
|
+
}
|
|
810
|
+
type ParaChild = Run | Hyperlink;
|
|
811
|
+
interface Paragraph {
|
|
812
|
+
type: "paragraph";
|
|
813
|
+
props: ParaProps;
|
|
814
|
+
children: ParaChild[];
|
|
815
|
+
/** Section break attached to this paragraph's pPr (ends a section). */
|
|
816
|
+
sectionBreak?: SectionProps;
|
|
817
|
+
/** w:bookmarkStart names in this paragraph (PAGEREF targets). */
|
|
818
|
+
bookmarks?: string[];
|
|
819
|
+
/** Final revision view: the paragraph mark AND all content are tracked
|
|
820
|
+
* deletions — the paragraph does not exist (no line, no numbering). */
|
|
821
|
+
revisionHidden?: boolean;
|
|
822
|
+
/** Source w:p element. */
|
|
823
|
+
src?: XmlElement;
|
|
824
|
+
}
|
|
825
|
+
interface TableCellProps {
|
|
826
|
+
/** Preferred width px (from tcW when dxa). */
|
|
827
|
+
width?: number;
|
|
828
|
+
/** The source explicitly declares tcW type="auto" (distinct from no tcW). */
|
|
829
|
+
widthAuto?: boolean;
|
|
830
|
+
gridSpan: number;
|
|
831
|
+
vMerge?: "restart" | "continue";
|
|
832
|
+
borders?: {
|
|
833
|
+
top?: Border;
|
|
834
|
+
bottom?: Border;
|
|
835
|
+
left?: Border;
|
|
836
|
+
right?: Border;
|
|
837
|
+
tl2br?: Border;
|
|
838
|
+
tr2bl?: Border;
|
|
839
|
+
};
|
|
840
|
+
shading?: string;
|
|
841
|
+
/** Cell margins px. */
|
|
842
|
+
margins?: {
|
|
843
|
+
top?: number;
|
|
844
|
+
right?: number;
|
|
845
|
+
bottom?: number;
|
|
846
|
+
left?: number;
|
|
847
|
+
};
|
|
848
|
+
verticalAlign?: "top" | "center" | "bottom";
|
|
849
|
+
textDirection?: "btLr" | "tbRl";
|
|
850
|
+
}
|
|
851
|
+
interface TableCell {
|
|
852
|
+
props: TableCellProps;
|
|
853
|
+
blocks: Block[];
|
|
854
|
+
}
|
|
855
|
+
interface TableRowProps {
|
|
856
|
+
/** px; undefined = auto */
|
|
857
|
+
height?: number;
|
|
858
|
+
heightRule?: "auto" | "atLeast" | "exact";
|
|
859
|
+
cantSplit?: boolean;
|
|
860
|
+
/** Repeat as header row on each page. */
|
|
861
|
+
tblHeader?: boolean;
|
|
862
|
+
}
|
|
863
|
+
interface TableRow {
|
|
864
|
+
props: TableRowProps;
|
|
865
|
+
cells: TableCell[];
|
|
866
|
+
}
|
|
867
|
+
interface TableProps {
|
|
868
|
+
styleId?: string;
|
|
869
|
+
/** px table indent from left margin. */
|
|
870
|
+
indent?: number;
|
|
871
|
+
alignment?: Alignment;
|
|
872
|
+
/** w:bidiVisual — RTL table: column order reverses and the table hugs the
|
|
873
|
+
* right margin. */
|
|
874
|
+
bidiVisual?: boolean;
|
|
875
|
+
borders?: {
|
|
876
|
+
top?: Border;
|
|
877
|
+
bottom?: Border;
|
|
878
|
+
left?: Border;
|
|
879
|
+
right?: Border;
|
|
880
|
+
insideH?: Border;
|
|
881
|
+
insideV?: Border;
|
|
882
|
+
};
|
|
883
|
+
/** Default cell margins px. */
|
|
884
|
+
cellMargins?: {
|
|
885
|
+
top?: number;
|
|
886
|
+
right?: number;
|
|
887
|
+
bottom?: number;
|
|
888
|
+
left?: number;
|
|
889
|
+
};
|
|
890
|
+
/** w:tblCellSpacing px — old-style separated cell borders: every cell gets
|
|
891
|
+
* its own border box inset by this much from the grid slot on all sides
|
|
892
|
+
* (adjacent cells end up 2x apart), and the table outline is a separate box
|
|
893
|
+
* around everything. */
|
|
894
|
+
cellSpacing?: number;
|
|
895
|
+
/** w:tblpPr — floating table: absolutely positioned against page/margin/
|
|
896
|
+
* column, painted over an opaque white sheet, with body text (including
|
|
897
|
+
* text EARLIER in the flow on the same page) wrapping square around it. */
|
|
898
|
+
floating?: {
|
|
899
|
+
hAnchor: "page" | "margin" | "text";
|
|
900
|
+
vAnchor: "page" | "margin" | "text";
|
|
901
|
+
/** tblpX/tblpY px (absent when an alignment keyword is used). */
|
|
902
|
+
x?: number;
|
|
903
|
+
y?: number;
|
|
904
|
+
xAlign?: "left" | "center" | "right";
|
|
905
|
+
yAlign?: "top" | "center" | "bottom";
|
|
906
|
+
/** Wrap distances px (leftFromText, …). */
|
|
907
|
+
dist: {
|
|
908
|
+
l: number;
|
|
909
|
+
r: number;
|
|
910
|
+
t: number;
|
|
911
|
+
b: number;
|
|
912
|
+
};
|
|
913
|
+
/** w:tblOverlap "never": shift clear of earlier floating tables. */
|
|
914
|
+
allowOverlap: boolean;
|
|
915
|
+
};
|
|
916
|
+
/** Preferred total width px (tblW dxa) or undefined for auto. */
|
|
917
|
+
width?: number;
|
|
918
|
+
/** Preferred total width as a fraction of available width (tblW pct). */
|
|
919
|
+
widthPct?: number;
|
|
920
|
+
layout?: "fixed" | "autofit";
|
|
921
|
+
/** w:tblLook flags controlling which conditional formats apply. */
|
|
922
|
+
tblLook?: TableLook;
|
|
923
|
+
}
|
|
924
|
+
/** w:tblLook flags controlling which conditional table-style formats apply. */
|
|
925
|
+
interface TableLook {
|
|
926
|
+
firstRow: boolean;
|
|
927
|
+
lastRow: boolean;
|
|
928
|
+
firstColumn: boolean;
|
|
929
|
+
lastColumn: boolean;
|
|
930
|
+
noHBand: boolean;
|
|
931
|
+
noVBand: boolean;
|
|
932
|
+
}
|
|
933
|
+
interface Table {
|
|
934
|
+
type: "table";
|
|
935
|
+
props: TableProps;
|
|
936
|
+
/** Column grid widths px (tblGrid). */
|
|
937
|
+
grid: number[];
|
|
938
|
+
rows: TableRow[];
|
|
939
|
+
/** Source w:tbl element. */
|
|
940
|
+
src?: XmlElement;
|
|
941
|
+
}
|
|
942
|
+
type Block = Paragraph | Table;
|
|
943
|
+
interface HeaderFooterRefs {
|
|
944
|
+
default?: string;
|
|
945
|
+
first?: string;
|
|
946
|
+
even?: string;
|
|
947
|
+
}
|
|
948
|
+
interface ColumnSpec {
|
|
949
|
+
count: number;
|
|
950
|
+
/** Space between columns px. */
|
|
951
|
+
space: number;
|
|
952
|
+
/** Explicit widths px when equalWidth=false. */
|
|
953
|
+
widths?: number[];
|
|
954
|
+
/** Per-column trailing space px (w:col w:space), when explicit w:col
|
|
955
|
+
* entries are present. spaces[i] separates column i from column i+1. */
|
|
956
|
+
spaces?: number[];
|
|
957
|
+
/** w:cols w:sep: paint a vertical rule centered in each inter-column gap. */
|
|
958
|
+
sep?: boolean;
|
|
959
|
+
}
|
|
960
|
+
interface SectionProps {
|
|
961
|
+
pageWidth: number;
|
|
962
|
+
pageHeight: number;
|
|
963
|
+
marginTop: number;
|
|
964
|
+
marginRight: number;
|
|
965
|
+
marginBottom: number;
|
|
966
|
+
marginLeft: number;
|
|
967
|
+
/** Distance of header top from page top, px (w:headerReference distance). */
|
|
968
|
+
headerDistance: number;
|
|
969
|
+
footerDistance: number;
|
|
970
|
+
gutter: number;
|
|
971
|
+
headerRefs: HeaderFooterRefs;
|
|
972
|
+
footerRefs: HeaderFooterRefs;
|
|
973
|
+
/** Different first-page header/footer enabled. */
|
|
974
|
+
titlePage: boolean;
|
|
975
|
+
/** Page numbering restart value, if set. */
|
|
976
|
+
pageNumberStart?: number;
|
|
977
|
+
pageNumberFormat?: string;
|
|
978
|
+
columns: ColumnSpec;
|
|
979
|
+
/** w:docGrid type=lines/linesAndChars: minimum single-line height (px) that
|
|
980
|
+
* the line-spacing multiplier is applied over. Word snaps every line's font
|
|
981
|
+
* height up to this grid pitch (CJK documents). */
|
|
982
|
+
docGridLinePitch?: number;
|
|
983
|
+
/** Present w:docGrid type; omitted w:type means "default". */
|
|
984
|
+
docGridType?: "default" | "lines" | "linesAndChars" | "snapToChars";
|
|
985
|
+
/** w:docGrid type="charsAndLines": a combined char+line grid that (in compat
|
|
986
|
+
* 15) keeps natural East-Asian line pitch. Drives the CJK line-height
|
|
987
|
+
* correction during measurement. */
|
|
988
|
+
docGridCharGrid?: boolean;
|
|
989
|
+
type?: "nextPage" | "continuous" | "evenPage" | "oddPage" | "nextColumn";
|
|
990
|
+
/** Vertical alignment of page content. */
|
|
991
|
+
vAlign?: "top" | "center" | "both" | "bottom";
|
|
992
|
+
/** w:pgBorders. Offsets (border.space, px) measure from text or page edge. */
|
|
993
|
+
pageBorders?: {
|
|
994
|
+
top?: Border;
|
|
995
|
+
bottom?: Border;
|
|
996
|
+
left?: Border;
|
|
997
|
+
right?: Border;
|
|
998
|
+
offsetFrom: "text" | "page";
|
|
999
|
+
};
|
|
1000
|
+
/** w:lnNumType: margin line numbering. distance px from the text edge. */
|
|
1001
|
+
lineNumbering?: {
|
|
1002
|
+
countBy: number;
|
|
1003
|
+
start: number;
|
|
1004
|
+
distance: number;
|
|
1005
|
+
restart: "continuous" | "newPage" | "newSection";
|
|
1006
|
+
};
|
|
1007
|
+
/** Footnote/endnote mark numbering (w:footnotePr / w:endnotePr). */
|
|
1008
|
+
footnoteNumFmt?: string;
|
|
1009
|
+
footnoteNumStart?: number;
|
|
1010
|
+
endnoteNumFmt?: string;
|
|
1011
|
+
endnoteNumStart?: number;
|
|
1012
|
+
/** w:textDirection tbRl: the whole section flows as East-Asian vertical
|
|
1013
|
+
* writing — lines run top-to-bottom, progressing right-to-left. */
|
|
1014
|
+
textDirection?: "tbRl";
|
|
1015
|
+
}
|
|
1016
|
+
interface Section {
|
|
1017
|
+
props: SectionProps;
|
|
1018
|
+
blocks: Block[];
|
|
1019
|
+
}
|
|
1020
|
+
/** A review comment from word/comments.xml. */
|
|
1021
|
+
interface DocComment {
|
|
1022
|
+
id: string;
|
|
1023
|
+
author: string;
|
|
1024
|
+
initials?: string;
|
|
1025
|
+
/** ISO timestamp from w:date, verbatim. */
|
|
1026
|
+
date?: string;
|
|
1027
|
+
/** Plain text of the comment body (paragraphs joined with newlines). */
|
|
1028
|
+
text: string;
|
|
1029
|
+
/** w14:paraId of the comment's last body paragraph (threading key). */
|
|
1030
|
+
paraId?: string;
|
|
1031
|
+
/** Parent comment id when this comment is a reply (commentsExtended). */
|
|
1032
|
+
parentId?: string;
|
|
1033
|
+
}
|
|
1034
|
+
interface HeaderFooter {
|
|
1035
|
+
blocks: Block[];
|
|
1036
|
+
}
|
|
1037
|
+
/** One w:tblStylePr conditional-formatting block (firstRow, band1Horz, …). */
|
|
1038
|
+
interface TableCondFormat {
|
|
1039
|
+
/** Cell shading fill as CSS color. */
|
|
1040
|
+
shd?: string;
|
|
1041
|
+
/** Conditional cell borders. */
|
|
1042
|
+
borders?: {
|
|
1043
|
+
top?: Border;
|
|
1044
|
+
bottom?: Border;
|
|
1045
|
+
left?: Border;
|
|
1046
|
+
right?: Border;
|
|
1047
|
+
insideH?: Border;
|
|
1048
|
+
insideV?: Border;
|
|
1049
|
+
};
|
|
1050
|
+
/** Conditional run bold (firstRow/firstCol headers). */
|
|
1051
|
+
bold?: boolean;
|
|
1052
|
+
/** Full conditional run props (w:tblStylePr > w:rPr). */
|
|
1053
|
+
rPr?: RunProps;
|
|
1054
|
+
}
|
|
1055
|
+
type TableCondType = "wholeTable" | "band1Vert" | "band2Vert" | "band1Horz" | "band2Horz" | "firstRow" | "lastRow" | "firstCol" | "lastCol" | "nwCell" | "neCell" | "swCell" | "seCell";
|
|
1056
|
+
interface Style {
|
|
1057
|
+
id: string;
|
|
1058
|
+
type: "paragraph" | "character" | "table" | "numbering";
|
|
1059
|
+
name?: string;
|
|
1060
|
+
basedOn?: string;
|
|
1061
|
+
isDefault?: boolean;
|
|
1062
|
+
pPr?: ParaProps;
|
|
1063
|
+
rPr?: RunProps;
|
|
1064
|
+
tblPr?: TableProps;
|
|
1065
|
+
/** w:tblStylePr conditional formats, by type (table styles only). */
|
|
1066
|
+
condFormats?: Map<TableCondType, TableCondFormat>;
|
|
1067
|
+
/** w:tblStyleRowBandSize / ColBandSize (default 1). */
|
|
1068
|
+
rowBandSize?: number;
|
|
1069
|
+
colBandSize?: number;
|
|
1070
|
+
}
|
|
1071
|
+
interface Styles {
|
|
1072
|
+
byId: Map<string, Style>;
|
|
1073
|
+
defaultParagraphStyle?: string;
|
|
1074
|
+
defaultRPr: RunProps;
|
|
1075
|
+
defaultPPr: ParaProps;
|
|
1076
|
+
}
|
|
1077
|
+
interface NumberingLevel {
|
|
1078
|
+
ilvl: number;
|
|
1079
|
+
start: number;
|
|
1080
|
+
format: string;
|
|
1081
|
+
/** Template like "%1." */
|
|
1082
|
+
text: string;
|
|
1083
|
+
alignment: Alignment;
|
|
1084
|
+
/** Paragraph props contributed by the level (indents). */
|
|
1085
|
+
pPr?: ParaProps;
|
|
1086
|
+
rPr?: RunProps;
|
|
1087
|
+
suffix: "tab" | "space" | "nothing";
|
|
1088
|
+
restartAfter?: number;
|
|
1089
|
+
}
|
|
1090
|
+
interface AbstractNum {
|
|
1091
|
+
id: number;
|
|
1092
|
+
levels: Map<number, NumberingLevel>;
|
|
1093
|
+
numStyleLink?: string;
|
|
1094
|
+
}
|
|
1095
|
+
interface NumInstance {
|
|
1096
|
+
numId: number;
|
|
1097
|
+
abstractNumId: number;
|
|
1098
|
+
overrides: Map<number, {
|
|
1099
|
+
startOverride?: number;
|
|
1100
|
+
level?: NumberingLevel;
|
|
1101
|
+
}>;
|
|
1102
|
+
}
|
|
1103
|
+
interface Numbering {
|
|
1104
|
+
abstract: Map<number, AbstractNum>;
|
|
1105
|
+
instances: Map<number, NumInstance>;
|
|
1106
|
+
}
|
|
1107
|
+
interface Theme {
|
|
1108
|
+
majorFont: string;
|
|
1109
|
+
minorFont: string;
|
|
1110
|
+
majorBidiFont?: string;
|
|
1111
|
+
minorBidiFont?: string;
|
|
1112
|
+
/** East Asian faces from theme <a:ea> (fontScheme major/minorFont). Word's
|
|
1113
|
+
* eastAsiaTheme="minor/majorEastAsia" resolves through these, NOT the Latin
|
|
1114
|
+
* minor/major font — routing a CJK run's theme reference to the Latin face
|
|
1115
|
+
* (Calibri) leaves East Asian text in a glyphless Latin font. */
|
|
1116
|
+
majorEastAsiaFont?: string;
|
|
1117
|
+
minorEastAsiaFont?: string;
|
|
1118
|
+
colors: Map<string, string>;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
/** A read-only view over the OPC (zip) package inside a .docx file. */
|
|
1122
|
+
declare class Package {
|
|
1123
|
+
private files;
|
|
1124
|
+
constructor(data: Uint8Array);
|
|
1125
|
+
static from(data: ArrayBuffer | Uint8Array): Package;
|
|
1126
|
+
has(name: string): boolean;
|
|
1127
|
+
binary(name: string): Uint8Array | undefined;
|
|
1128
|
+
text(name: string): string | undefined;
|
|
1129
|
+
names(): string[];
|
|
1130
|
+
/** Raw entry map (shared, do not mutate) — used for write-back. */
|
|
1131
|
+
raw(): Record<string, Uint8Array>;
|
|
1132
|
+
/** OPC part names never start with '/' inside the zip; tolerate both. */
|
|
1133
|
+
private normalize;
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
/**
|
|
1137
|
+
* Stable node identity for replicated editing.
|
|
1138
|
+
*
|
|
1139
|
+
* Positions on the wire cannot be object references, and numeric child paths
|
|
1140
|
+
* shift under concurrent structural edits — so blocks (w:p, w:tbl) and runs
|
|
1141
|
+
* (w:r) get stable numeric ids held in an in-memory side table. The table is
|
|
1142
|
+
* identity-keyed and NEVER serialized into the XML: writing ids as attributes
|
|
1143
|
+
* would dirty every part on open and break the byte-identical round-trip
|
|
1144
|
+
* guarantee for untouched parts.
|
|
1145
|
+
*
|
|
1146
|
+
* Assignment is deterministic: a document-order walk over the given roots,
|
|
1147
|
+
* so two replicas that parse the same document derive the same table. Nodes
|
|
1148
|
+
* created later by edits get ids explicitly (locally via `assign`, or from a
|
|
1149
|
+
* replicated edit that carries the originating client's allocation) — a
|
|
1150
|
+
* re-walk after edits only fills gaps and never renumbers survivors, because
|
|
1151
|
+
* the table is keyed by element identity and in-place XML mutation preserves
|
|
1152
|
+
* identity across `refresh()`.
|
|
1153
|
+
*/
|
|
1154
|
+
type StableId$1 = number;
|
|
1155
|
+
interface EncodedCaret {
|
|
1156
|
+
blockId: StableId$1;
|
|
1157
|
+
runId: StableId$1;
|
|
1158
|
+
/** Offset in the run's WIRE space: cumulative through the run's inline
|
|
1159
|
+
* content in document order, where each w:t contributes its text length
|
|
1160
|
+
* and each inline separator (w:tab / w:br / w:cr) contributes ONE unit.
|
|
1161
|
+
* Counting separators makes encoding ONE-TO-ONE: a caret at the end of
|
|
1162
|
+
* the w:t before a tab and one at the start of the w:t after it are
|
|
1163
|
+
* different physical positions and get different wire offsets — without
|
|
1164
|
+
* the separator unit both collapsed to the same number and the decoder
|
|
1165
|
+
* had to guess (review bug: boundary intents applied into the wrong w:t
|
|
1166
|
+
* on remote replicas, and boundary-starting ranges always rejected). */
|
|
1167
|
+
offset: number;
|
|
1168
|
+
}
|
|
1169
|
+
declare class StableIds {
|
|
1170
|
+
private byEl;
|
|
1171
|
+
private byId;
|
|
1172
|
+
private next;
|
|
1173
|
+
/** Document-order assignment over the given roots (typically
|
|
1174
|
+
* `doc.editableRoots()`). Idempotent: elements that already have ids keep
|
|
1175
|
+
* them; untracked ids are assigned in walk order. Call after load and
|
|
1176
|
+
* after any edit that created tracked nodes without explicit ids. */
|
|
1177
|
+
assignFromRoots(roots: XmlElement[]): void;
|
|
1178
|
+
/**
|
|
1179
|
+
* Assign ids inside the given subtrees only — the scoped counterpart of
|
|
1180
|
+
* assignFromRoots, for an edit that is known to have created nodes in one
|
|
1181
|
+
* or two paragraphs (dirty-scoped reconciliation, perf B9/B10).
|
|
1182
|
+
*
|
|
1183
|
+
* EQUIVALENCE (the property the scoped hot path rests on): this produces
|
|
1184
|
+
* the same table a full assignFromRoots would, PROVIDED every tracked node
|
|
1185
|
+
* outside the subtrees already has an id. Assignment is order-dependent —
|
|
1186
|
+
* fresh nodes take sequential numbers from `next` in walk order — and a
|
|
1187
|
+
* subtree walk visits exactly a contiguous slice of the document-order
|
|
1188
|
+
* walk, in the same order. So the only way the two can disagree is an
|
|
1189
|
+
* un-id'd node elsewhere that the full walk would have numbered first.
|
|
1190
|
+
* That invariant holds inductively: load/importSidecar ids everything, and
|
|
1191
|
+
* every apply either ids the nodes it creates (carried ids), reports
|
|
1192
|
+
* document scope (full refresh + full assign), or creates nodes only
|
|
1193
|
+
* inside the subtrees passed here. Callers that cannot establish it must
|
|
1194
|
+
* fall back to assignFromRoots.
|
|
1195
|
+
*/
|
|
1196
|
+
assignFromSubtrees(subtrees: XmlElement[]): void;
|
|
1197
|
+
private walk;
|
|
1198
|
+
/** Explicitly assign an id to a newly created node. Local edits allocate
|
|
1199
|
+
* (`assign(el)`); applying a replicated edit installs the carried value
|
|
1200
|
+
* (`assign(el, carriedId)`). Carried ids must not collide. */
|
|
1201
|
+
assign(el: XmlElement, id?: StableId$1): StableId$1;
|
|
1202
|
+
/** Force `el` to carry `id`, replacing any id it already has (e.g. one
|
|
1203
|
+
* auto-assigned by a refresh() before a carried id could be installed).
|
|
1204
|
+
* The previous id is retired. Throws if `id` is held by a different element. */
|
|
1205
|
+
reassign(el: XmlElement, id: StableId$1): void;
|
|
1206
|
+
private install;
|
|
1207
|
+
idOf(el: XmlElement): StableId$1 | undefined;
|
|
1208
|
+
elOf(id: StableId$1): XmlElement | undefined;
|
|
1209
|
+
/** Drop mappings for elements no longer reachable from the given roots
|
|
1210
|
+
* (deleted content). Keeps the table from growing across long sessions.
|
|
1211
|
+
* Ids of dropped elements are retired, never reused. */
|
|
1212
|
+
prune(roots: XmlElement[]): void;
|
|
1213
|
+
size(): number;
|
|
1214
|
+
/** Snapshot the table as [id, element] pairs against a parallel clone of
|
|
1215
|
+
* the tree: `pairs` maps originals→clones (as produced by walking original
|
|
1216
|
+
* and cloned roots in step). Used by the reconciliation snapshot (plan
|
|
1217
|
+
* doc 03) so a restore re-keys the table to the restored elements. */
|
|
1218
|
+
captureForClone(originalToClone: Map<XmlElement, XmlElement>): Map<StableId$1, XmlElement>;
|
|
1219
|
+
/** Replace the table wholesale from a captured mapping (restore path). */
|
|
1220
|
+
restore(fromCapture: Map<StableId$1, XmlElement>, nextId: StableId$1): void;
|
|
1221
|
+
nextId(): StableId$1;
|
|
1222
|
+
/**
|
|
1223
|
+
* Export the table as `(id, path)` pairs, where a path is the structural
|
|
1224
|
+
* location of the id'd element within the given roots: `[rootIndex,
|
|
1225
|
+
* childIndex, childIndex, …]`. This is the checkpoint ID sidecar (plan doc
|
|
1226
|
+
* 03): it lets a replica that reloads a snapshot reproduce the exact id
|
|
1227
|
+
* table — parse-order re-derivation cannot, because split-created nodes
|
|
1228
|
+
* carry non-sequential ids. Also carries `next` so id allocation resumes
|
|
1229
|
+
* consistently.
|
|
1230
|
+
*/
|
|
1231
|
+
exportSidecar(roots: XmlElement[]): {
|
|
1232
|
+
next: StableId$1;
|
|
1233
|
+
entries: [StableId$1, number[]][];
|
|
1234
|
+
};
|
|
1235
|
+
/** Rebuild the table from a sidecar against freshly parsed roots (the
|
|
1236
|
+
* snapshot the sidecar was exported from). Replaces any current mappings. */
|
|
1237
|
+
importSidecar(roots: XmlElement[], sidecar: {
|
|
1238
|
+
next: StableId$1;
|
|
1239
|
+
entries: [StableId$1, number[]][];
|
|
1240
|
+
}): void;
|
|
1241
|
+
/** Encode a caret as wire-stable addresses. `t` is the w:t (or other text
|
|
1242
|
+
* holder) the caret sits in; the run is its nearest tracked ancestor run,
|
|
1243
|
+
* the block the nearest tracked block above that. Returns null when the
|
|
1244
|
+
* position isn't inside id-tracked content (e.g. math internals) — such
|
|
1245
|
+
* positions are not yet addressable on the wire. */
|
|
1246
|
+
encodeCaret(t: XmlElement, offset: number, parentOf: (el: XmlElement) => XmlElement | null): EncodedCaret | null;
|
|
1247
|
+
/** Resolve an encoded caret back to a concrete (w:t, offset) in THIS
|
|
1248
|
+
* table's tree — the inverse of encodeCaret, for restoring a caret across
|
|
1249
|
+
* a reconciliation reload (the ids survive via the sidecar; the node
|
|
1250
|
+
* references do not). When the exact run is gone (deleted or replaced by
|
|
1251
|
+
* a concurrent edit) the caret falls back to the block's first text; null
|
|
1252
|
+
* when nothing addressable remains. */
|
|
1253
|
+
decodeCaret(pos: EncodedCaret): {
|
|
1254
|
+
t: XmlElement;
|
|
1255
|
+
offset: number;
|
|
1256
|
+
} | null;
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
interface Relationship {
|
|
1260
|
+
id: string;
|
|
1261
|
+
type: string;
|
|
1262
|
+
target: string;
|
|
1263
|
+
external: boolean;
|
|
1264
|
+
}
|
|
1265
|
+
type Relationships = Map<string, Relationship>;
|
|
1266
|
+
|
|
1267
|
+
/**
|
|
1268
|
+
* A fully parsed .docx: sections of blocks, styles, numbering, theme, and
|
|
1269
|
+
* header/footer parts, with helpers to resolve effective formatting.
|
|
1270
|
+
*/
|
|
1271
|
+
declare class DocxDocument {
|
|
1272
|
+
/** Changes whenever refresh() rebuilds the parsed model. Plain in-place text
|
|
1273
|
+
* edits can keep this stable so incremental layout reuses model-only caches. */
|
|
1274
|
+
private _modelVersion;
|
|
1275
|
+
private _packageResourceVersion;
|
|
1276
|
+
get modelVersion(): number;
|
|
1277
|
+
/** Invalidate layout derived from related parts such as ChartML. */
|
|
1278
|
+
markPackageResourceChanged(): void;
|
|
1279
|
+
readonly pkg: Package;
|
|
1280
|
+
readonly theme: Theme;
|
|
1281
|
+
styles: Styles;
|
|
1282
|
+
numbering: Numbering;
|
|
1283
|
+
sections: Section[];
|
|
1284
|
+
/** Header/footer parts keyed by relationship id from document.xml.rels. */
|
|
1285
|
+
readonly headers: Map<string, HeaderFooter>;
|
|
1286
|
+
readonly footers: Map<string, HeaderFooter>;
|
|
1287
|
+
/** Note content by note id (render-only; sources stripped). */
|
|
1288
|
+
readonly footnotes: Map<number, Block[]>;
|
|
1289
|
+
readonly endnotes: Map<number, Block[]>;
|
|
1290
|
+
/** The separator paragraph controls the gap between its rule and the first
|
|
1291
|
+
* footnote. */
|
|
1292
|
+
readonly footnoteSeparator: Block[];
|
|
1293
|
+
/** `_Ref` cross-reference bookmark ranges (name → captured runs). REF
|
|
1294
|
+
* fields re-render the referenced text from these — Word recomputes REF on
|
|
1295
|
+
* open, so the cached field result in the file is stale. */
|
|
1296
|
+
refBookmarks: Map<string, Run[]>;
|
|
1297
|
+
readonly documentRels: Relationships;
|
|
1298
|
+
/** settings.xml w:evenAndOddHeaders — enables the "even" header/footer variants. */
|
|
1299
|
+
readonly evenAndOddHeaders: boolean;
|
|
1300
|
+
/** settings.xml w:mirrorMargins — facing-page (book fold) margins: even
|
|
1301
|
+
* (verso) pages swap the left/right margins and place the gutter on the
|
|
1302
|
+
* inside (right) edge so the binding margin stays on the inner side of
|
|
1303
|
+
* each spread. */
|
|
1304
|
+
readonly mirrorMargins: boolean;
|
|
1305
|
+
/** settings.xml w:defaultTabStop in px (Word default 0.5"). */
|
|
1306
|
+
readonly defaultTabStop: number;
|
|
1307
|
+
/** settings.xml w:compat compatibilityMode (12=Word2007, 14=Word2010,
|
|
1308
|
+
* 15=Word2013+). Word 2013 (mode 15) introduced suppressing a paragraph's
|
|
1309
|
+
* space-before when it lands at the top of a page; mode 14 and earlier keep
|
|
1310
|
+
* it (nccih: a Heading1/2 after a page break sits at margin + its before).
|
|
1311
|
+
* Absent → treated as current (15). */
|
|
1312
|
+
readonly compatibilityMode: number;
|
|
1313
|
+
/** settings.xml m:mathPr/m:defJc — default justification for display
|
|
1314
|
+
* equations whose m:oMathParaPr carries no explicit m:jc (Word default:
|
|
1315
|
+
* centerGroup — the rows of a broken equation left-align to each other and
|
|
1316
|
+
* the group is centered in the column). */
|
|
1317
|
+
readonly mathDefJc: "left" | "right" | "center" | "centerGroup";
|
|
1318
|
+
/** settings.xml m:mathPr/m:wrapIndent in px (Word default 1440tw = 1"):
|
|
1319
|
+
* indent of auto-wrapped display-equation continuation rows from the
|
|
1320
|
+
* equation group's left edge (dense p13: the "+Dc(...)" continuations sit
|
|
1321
|
+
* exactly 72pt right of the explicit rows). */
|
|
1322
|
+
readonly mathWrapIndent: number;
|
|
1323
|
+
/** Review comments from word/comments.xml (empty when the part is absent).
|
|
1324
|
+
* Re-derived from the retained comments XML on every refresh(). */
|
|
1325
|
+
comments: DocComment[];
|
|
1326
|
+
/** Retained comments.xml tree (editing + save round-trip), when present. */
|
|
1327
|
+
private commentsPart;
|
|
1328
|
+
private commentsRoot;
|
|
1329
|
+
/** Retained commentsExtended.xml tree (comment threading), when present. */
|
|
1330
|
+
private commentsExtPart;
|
|
1331
|
+
private commentsExtRoot;
|
|
1332
|
+
private commentsExtDirty;
|
|
1333
|
+
/** Conditional table formats per table style id, keyed by the Styles object
|
|
1334
|
+
* so re-parsing styles.xml (edits) naturally invalidates the cache. */
|
|
1335
|
+
private tableCondCache;
|
|
1336
|
+
/** Retained styles.xml tree (built-in style injection + save). */
|
|
1337
|
+
private stylesPart;
|
|
1338
|
+
private stylesRoot;
|
|
1339
|
+
/** Retained numbering.xml tree (list creation + save round-trip). */
|
|
1340
|
+
private numberingPart;
|
|
1341
|
+
private numberingRoot;
|
|
1342
|
+
private numberingDirty;
|
|
1343
|
+
/** Retained footnotes.xml tree (footnote insertion + save round-trip). */
|
|
1344
|
+
private footnotesPart;
|
|
1345
|
+
private footnotesRoot;
|
|
1346
|
+
private footnotesDirty;
|
|
1347
|
+
private footnotesRels;
|
|
1348
|
+
/** Serialize retained optional parts only once actually mutated, keeping
|
|
1349
|
+
* untouched parts byte-identical through save(). */
|
|
1350
|
+
private stylesDirty;
|
|
1351
|
+
private commentsDirty;
|
|
1352
|
+
/** Retained XML roots — source of truth for editing and save(). */
|
|
1353
|
+
private readonly docPart;
|
|
1354
|
+
/** Retained settings.xml tree. A synthetic empty root keeps history root
|
|
1355
|
+
* indices stable for documents that did not originally contain the part. */
|
|
1356
|
+
private readonly settingsPart;
|
|
1357
|
+
private readonly settingsRoot;
|
|
1358
|
+
private settingsDirty;
|
|
1359
|
+
/** Parsed document.xml root (read-only outside the class; the layout engine
|
|
1360
|
+
* scans it for incremental-reuse eligibility, tests walk it). */
|
|
1361
|
+
readonly docRoot: XmlElement;
|
|
1362
|
+
private readonly hfParts;
|
|
1363
|
+
private readonly ctxBase;
|
|
1364
|
+
/** Tracked-changes display mode; refresh() re-derives after changes. */
|
|
1365
|
+
revisionView: "final" | "markup";
|
|
1366
|
+
private readonly relsPath;
|
|
1367
|
+
private relsRoot;
|
|
1368
|
+
private contentTypesRoot;
|
|
1369
|
+
/** Canonical XML as first parsed from each always-modeled package part.
|
|
1370
|
+
* If the retained tree still matches on save, keep the part's original
|
|
1371
|
+
* bytes instead of replacing producer formatting such as CRLF line ends. */
|
|
1372
|
+
private readonly originalModeledXml;
|
|
1373
|
+
private docPrIdCounter;
|
|
1374
|
+
/** Transient layout state: set by the engine while laying out a docGrid
|
|
1375
|
+
* type="charsAndLines" section so line measurement can give East-Asian
|
|
1376
|
+
* glyphs their true (uninflated) grid line height. Off outside such a
|
|
1377
|
+
* section. Safe as document-scoped mutable state because layout is
|
|
1378
|
+
* single-threaded and sequential per section. */
|
|
1379
|
+
charGridEa: boolean;
|
|
1380
|
+
private constructor();
|
|
1381
|
+
/** Resolve content controls mapped to standard package core properties.
|
|
1382
|
+
* Word refreshes these bindings on open, so the serialized sdtContent can
|
|
1383
|
+
* be stale even though the visible value comes from docProps/core.xml. */
|
|
1384
|
+
private hydrateCorePropertyControls;
|
|
1385
|
+
/** Repair only objects emitted by older WordInWeb builds that Word rejects. */
|
|
1386
|
+
private repairLegacyWordInWebObjects;
|
|
1387
|
+
/**
|
|
1388
|
+
* Re-derive the document model from the retained XML trees. Called after
|
|
1389
|
+
* edit commands mutate the XML.
|
|
1390
|
+
*/
|
|
1391
|
+
/** Switch tracked-changes display and re-derive the model. */
|
|
1392
|
+
setRevisionView(view: "final" | "markup"): void;
|
|
1393
|
+
/** Invalidated on refresh; see layoutGlobalSig. */
|
|
1394
|
+
private _layoutGlobalSig;
|
|
1395
|
+
/** Signature of everything OUTSIDE a paragraph's own XML that affects how it
|
|
1396
|
+
* breaks into lines: style + numbering definitions, doc-level layout scalars,
|
|
1397
|
+
* and the tracked-changes view mode. The line-break cache (layout/inline.ts)
|
|
1398
|
+
* combines this with a paragraph's own content signature so a style/numbering/
|
|
1399
|
+
* settings edit invalidates cached breaks even though the paragraph XML is
|
|
1400
|
+
* unchanged. Memoized until the next refresh() (styles/numbering trees are
|
|
1401
|
+
* stable across a plain text edit). */
|
|
1402
|
+
layoutGlobalSig(): string;
|
|
1403
|
+
refresh(): void;
|
|
1404
|
+
/** Stable node-id side table for replicated editing. Null (and zero cost)
|
|
1405
|
+
* for local-only documents; call `enableStableIds()` to populate and
|
|
1406
|
+
* maintain it. Kept in memory only — never serialized into the XML. */
|
|
1407
|
+
stableIds: StableIds | null;
|
|
1408
|
+
/** Populate the stable-id table from current content and keep it updated
|
|
1409
|
+
* on every subsequent refresh(). Idempotent. */
|
|
1410
|
+
enableStableIds(): StableIds;
|
|
1411
|
+
/** Reparse the two sibling body-story paragraphs created by Enter without
|
|
1412
|
+
* rebuilding the complete document model. Paragraphs nested in table cells
|
|
1413
|
+
* are included because legal documents spend most of their body inside
|
|
1414
|
+
* tables; revisions, bookmarks, fields, and section breaks use refresh(). */
|
|
1415
|
+
reparseDirectBodyParagraphSplit(beforeSource: XmlElement, afterSource: XmlElement): {
|
|
1416
|
+
before: Paragraph;
|
|
1417
|
+
after: Paragraph;
|
|
1418
|
+
} | null;
|
|
1419
|
+
/**
|
|
1420
|
+
* The parsed body-story block list holding the paragraph parsed from
|
|
1421
|
+
* `source`, and its index in it — searching sections and, recursively,
|
|
1422
|
+
* table cells. Null when the model doesn't hold that paragraph (it lives in
|
|
1423
|
+
* a header/footer/footnote part, or the model predates its creation), which
|
|
1424
|
+
* is every targeted-reparse helper's signal to fall back to a full
|
|
1425
|
+
* refresh(). Shared by those helpers and by paragraphBySource.
|
|
1426
|
+
*/
|
|
1427
|
+
private locateParagraph;
|
|
1428
|
+
private _paraLoc;
|
|
1429
|
+
/** The parsed Paragraph for a retained w:p in the body story (table cells
|
|
1430
|
+
* included), or null when the model doesn't hold it. Lets a caller that
|
|
1431
|
+
* already knows which paragraph an edit addresses reach that paragraph's
|
|
1432
|
+
* runs without walking the whole model. */
|
|
1433
|
+
paragraphBySource(source: XmlElement): Paragraph | null;
|
|
1434
|
+
/** Insert a new paragraph immediately before a retained body paragraph
|
|
1435
|
+
* without rebuilding the complete document model. Used by Enter at the
|
|
1436
|
+
* exact paragraph start, where the existing paragraph itself is unchanged. */
|
|
1437
|
+
insertDirectBodyParagraphBefore(referenceSource: XmlElement, insertedSource: XmlElement): Paragraph | null;
|
|
1438
|
+
/** Reparse a body paragraph plus several new siblings created by
|
|
1439
|
+
* click-and-type without rebuilding the complete document model. */
|
|
1440
|
+
reparseDirectBodyParagraphSplits(beforeSource: XmlElement, afterSources: XmlElement[]): Paragraph[] | null;
|
|
1441
|
+
/** Reparse one retained body-story paragraph after a structural edit that
|
|
1442
|
+
* leaves its surrounding block list unchanged, such as inserting ink. */
|
|
1443
|
+
reparseBodyParagraph(source: XmlElement): Paragraph | null;
|
|
1444
|
+
/** Reparse two sibling body-story paragraphs after Backspace/Delete merged
|
|
1445
|
+
* their XML into one. Keeps the parsed model generation stable so long
|
|
1446
|
+
* documents can use incremental layout instead of repaginating in full. */
|
|
1447
|
+
reparseDirectBodyParagraphMerge(beforeSource: XmlElement, afterSource: XmlElement, survivorSource: XmlElement): Paragraph | null;
|
|
1448
|
+
private deriveComments;
|
|
1449
|
+
/** Retained comments tree for edit commands (null when the doc has none). */
|
|
1450
|
+
/**
|
|
1451
|
+
* Retained comments tree. With create=true, a missing comments.xml part is
|
|
1452
|
+
* created and registered (content type + document relationship) so newly
|
|
1453
|
+
* added comments serialize and round-trip through Word.
|
|
1454
|
+
*/
|
|
1455
|
+
commentsTree(create?: boolean): XmlElement | null;
|
|
1456
|
+
/**
|
|
1457
|
+
* Make sure a paragraph style is usable: Word ships built-in definitions
|
|
1458
|
+
* for Heading 1-6/Title even when a file doesn't declare them, so applying
|
|
1459
|
+
* one to such a file must inject a standard definition (otherwise the
|
|
1460
|
+
* paragraph would reference an undefined style and render as Normal).
|
|
1461
|
+
*/
|
|
1462
|
+
ensureParagraphStyle(styleId: string): boolean;
|
|
1463
|
+
/**
|
|
1464
|
+
* Retained numbering tree. With create=true, a missing numbering.xml part
|
|
1465
|
+
* is created and registered (content type + document relationship) so list
|
|
1466
|
+
* definitions added by editing serialize and round-trip.
|
|
1467
|
+
*/
|
|
1468
|
+
numberingTree(create?: boolean): XmlElement | null;
|
|
1469
|
+
markNumberingChanged(): void;
|
|
1470
|
+
/**
|
|
1471
|
+
* Retained footnotes tree. With create=true, a missing footnotes.xml part
|
|
1472
|
+
* is created and registered (with Word's required separator footnotes) so
|
|
1473
|
+
* inserted footnotes serialize and round-trip.
|
|
1474
|
+
*/
|
|
1475
|
+
footnotesTree(create?: boolean): XmlElement | null;
|
|
1476
|
+
/**
|
|
1477
|
+
* Create an empty header/footer part (with a default-type reference in
|
|
1478
|
+
* every sectPr) when the document has none - Word does this implicitly the
|
|
1479
|
+
* first time you edit the header area. Returns the part's root.
|
|
1480
|
+
*/
|
|
1481
|
+
/** Whether the document declares any section properties at all. A blank
|
|
1482
|
+
* minimal document has none; see ensureHfPart. */
|
|
1483
|
+
private hasSectPr;
|
|
1484
|
+
/** Whether a header (or footer) part already exists — the precondition
|
|
1485
|
+
* `ensureHfPart` tests internally, exposed so a caller can tell a real
|
|
1486
|
+
* creation from a no-op before mutating (the collab apply needs to know
|
|
1487
|
+
* whether an ensureHeaderFooter intent has anything to do). */
|
|
1488
|
+
hasHfPart(kind: "header" | "footer"): boolean;
|
|
1489
|
+
ensureHfPart(kind: "header" | "footer"): XmlElement;
|
|
1490
|
+
markFootnotesChanged(): void;
|
|
1491
|
+
/** Called by comment edit commands after mutating the comments tree. */
|
|
1492
|
+
markCommentsChanged(): void;
|
|
1493
|
+
/**
|
|
1494
|
+
* Retained commentsExtended tree (threading). With create=true, a missing
|
|
1495
|
+
* part is created and registered (content type + document relationship) so
|
|
1496
|
+
* Word picks up reply threading.
|
|
1497
|
+
*/
|
|
1498
|
+
commentsExtendedTree(create?: boolean): XmlElement | null;
|
|
1499
|
+
markCommentsExtendedChanged(): void;
|
|
1500
|
+
/**
|
|
1501
|
+
* The w:t elements covered by each comment's range, in document order.
|
|
1502
|
+
* Point comments (a bare commentReference with no range) anchor to the
|
|
1503
|
+
* nearest preceding w:t.
|
|
1504
|
+
*/
|
|
1505
|
+
commentAnchors(): Map<string, XmlElement[]>;
|
|
1506
|
+
/** Flag the footnotes part dirty when `t` lives inside it, so save()
|
|
1507
|
+
* re-serializes footnotes.xml. Called by the editor after a text edit; a
|
|
1508
|
+
* no-op for body/header/footer targets. */
|
|
1509
|
+
markDirtyIfFootnote(t: XmlElement): void;
|
|
1510
|
+
/** The mutable XML roots (document body, related modeled parts, settings).
|
|
1511
|
+
* settingsRoot is always second and always present so its history snapshot
|
|
1512
|
+
* index stays stable even when optional related roots are created later. */
|
|
1513
|
+
editableRoots(): XmlElement[];
|
|
1514
|
+
/** Toggle the document-global facing-page margin mode in settings.xml. */
|
|
1515
|
+
setMirrorMargins(enabled: boolean): void;
|
|
1516
|
+
/**
|
|
1517
|
+
* Find the parent element of `target` in any modeled XML tree (document
|
|
1518
|
+
* body, headers, footers). Linear scan — documents are small and this only
|
|
1519
|
+
* runs on structural edits (Enter, paragraph merge).
|
|
1520
|
+
*/
|
|
1521
|
+
/** XML roots that can carry tracked changes: body, headers/footers, footnotes. */
|
|
1522
|
+
revisionRoots(): XmlElement[];
|
|
1523
|
+
/**
|
|
1524
|
+
* Memoized child→parent links. Nothing invalidates this map — the tree is
|
|
1525
|
+
* spliced constantly — so every answer is RE-DERIVED before it is returned:
|
|
1526
|
+
* the memoized parent must still list the target among its children, and
|
|
1527
|
+
* must still hang off a root (see memoIsLive). A stale entry can then only
|
|
1528
|
+
* cost a cache miss, never a wrong answer.
|
|
1529
|
+
*
|
|
1530
|
+
* Both halves are needed. Containment alone is not proof of a live parent:
|
|
1531
|
+
* a run split for formatting is spliced OUT of its paragraph while its own
|
|
1532
|
+
* `children` array still lists the elements that moved into the replacement
|
|
1533
|
+
* runs, so a containment-only check would hand back the detached run where a
|
|
1534
|
+
* walk from the roots finds the new one.
|
|
1535
|
+
*/
|
|
1536
|
+
private _parentMemo;
|
|
1537
|
+
private memoIsLive;
|
|
1538
|
+
findParentOf(target: XmlElement): XmlElement | undefined;
|
|
1539
|
+
/** Record a parent link the caller just created (a splice), so the next
|
|
1540
|
+
* lookup skips the full-document walk. Advisory only — findParentOf
|
|
1541
|
+
* verifies every memo against the live tree before trusting it. */
|
|
1542
|
+
noteParent(child: XmlElement, parent: XmlElement): void;
|
|
1543
|
+
/**
|
|
1544
|
+
* Serialize the (possibly edited) document back to .docx bytes. Only the
|
|
1545
|
+
* XML parts we model are re-serialized; every other part round-trips
|
|
1546
|
+
* byte-for-byte.
|
|
1547
|
+
*/
|
|
1548
|
+
private rememberOriginalXml;
|
|
1549
|
+
private writeModeledXml;
|
|
1550
|
+
/**
|
|
1551
|
+
* Canonicalize producer shorthand that Google Docs otherwise interprets as
|
|
1552
|
+
* a fixed, few-twip table. Word treats `tblW="100%"` plus a placeholder
|
|
1553
|
+
* grid as autofit; Google needs the standard pct value and a usable cached
|
|
1554
|
+
* grid. The cached widths follow the same content-dominant shape and do not
|
|
1555
|
+
* change Word's autofit result.
|
|
1556
|
+
*/
|
|
1557
|
+
/** Undo closures recorded by save-time fixups while `saveJournal` is
|
|
1558
|
+
* active, so `save()` can revert every live-tree mutation and remain
|
|
1559
|
+
* side-effect-free. Collaborative checkpoints re-serialize the
|
|
1560
|
+
* authoritative document repeatedly; a save that mutated the tree would
|
|
1561
|
+
* change its hash outside the intent stream and desync the fleet. */
|
|
1562
|
+
private saveJournal;
|
|
1563
|
+
private journalSetAttr;
|
|
1564
|
+
private normalizePercentageTableGrids;
|
|
1565
|
+
save(): Uint8Array;
|
|
1566
|
+
saveAsync(): Promise<Uint8Array>;
|
|
1567
|
+
private buildPackage;
|
|
1568
|
+
private buildPackageFiles;
|
|
1569
|
+
/** Fresh unique docPr id for inserted drawings. Seeded once past the
|
|
1570
|
+
* highest id already present in any editable root (floor 1000, matching
|
|
1571
|
+
* the historical seed for documents with no drawings) so a document that
|
|
1572
|
+
* already carries drawings never gets a colliding id. */
|
|
1573
|
+
nextDrawingId(): number;
|
|
1574
|
+
/** Next unused revision id (w:id on w:ins/w:del). Seeded once past the
|
|
1575
|
+
* highest id already present in any editable root so a document that
|
|
1576
|
+
* already has tracked changes never collides. */
|
|
1577
|
+
private revIdCounter;
|
|
1578
|
+
nextRevisionId(): number;
|
|
1579
|
+
/**
|
|
1580
|
+
* Add image bytes as a new media part + relationship (+ content-type
|
|
1581
|
+
* default). Returns the relationship id for use in a w:drawing.
|
|
1582
|
+
*/
|
|
1583
|
+
private ensureRelsRoot;
|
|
1584
|
+
/** Register an external hyperlink relationship and return its rId. */
|
|
1585
|
+
addHyperlinkRel(url: string): string;
|
|
1586
|
+
/** Retarget an existing external relationship (hyperlink href edit). */
|
|
1587
|
+
setRelTarget(relId: string, url: string): boolean;
|
|
1588
|
+
private addImageResourceAt;
|
|
1589
|
+
addImageResource(bytes: Uint8Array, ext: string): string;
|
|
1590
|
+
/** Add a GLB model part and its Office 2019 model3d relationship. */
|
|
1591
|
+
addModel3DResource(bytes: Uint8Array): {
|
|
1592
|
+
relId: string;
|
|
1593
|
+
part: string;
|
|
1594
|
+
};
|
|
1595
|
+
/** Add an OLE package part used by a Word w:object. */
|
|
1596
|
+
addEmbeddedObjectResource(bytes: Uint8Array): {
|
|
1597
|
+
relId: string;
|
|
1598
|
+
part: string;
|
|
1599
|
+
};
|
|
1600
|
+
/** Add a DOCX package embedded as an activatable Word.Document.12 object. */
|
|
1601
|
+
addEmbeddedWordDocumentResource(bytes: Uint8Array): {
|
|
1602
|
+
relId: string;
|
|
1603
|
+
part: string;
|
|
1604
|
+
};
|
|
1605
|
+
/** Add a native ChartML part and its embedded editable workbook. */
|
|
1606
|
+
addChartResource(chartXml: string, workbook: Uint8Array): {
|
|
1607
|
+
relId: string;
|
|
1608
|
+
part: string;
|
|
1609
|
+
};
|
|
1610
|
+
/** Add the SmartArt data/layout/style/color parts and its cached diagram drawing. */
|
|
1611
|
+
addSmartArtResources(layoutXml: string, styleXml: string, colorsXml: string, drawingXml: string, dataXml: (drawingRelId: string) => string): {
|
|
1612
|
+
dataRelId: string;
|
|
1613
|
+
layoutRelId: string;
|
|
1614
|
+
styleRelId: string;
|
|
1615
|
+
colorsRelId: string;
|
|
1616
|
+
drawingRelId: string;
|
|
1617
|
+
};
|
|
1618
|
+
static load(data: ArrayBuffer | Uint8Array): DocxDocument;
|
|
1619
|
+
media(part: string): Uint8Array | undefined;
|
|
1620
|
+
/**
|
|
1621
|
+
* Pending-media registry (plan doc 05 change 1 / doc 16 §6): parts whose
|
|
1622
|
+
* XML registration (rels + content-type + extent geometry) exists but
|
|
1623
|
+
* whose BYTES have not arrived yet — the out-of-band media model. Layout
|
|
1624
|
+
* needs no bytes (extents live in the XML), so a doc with pending parts
|
|
1625
|
+
* lays out pixel-identically; the renderer shows a placeholder until
|
|
1626
|
+
* `installMedia`. Keyed by part name; the value is the doc-16 §5.3
|
|
1627
|
+
* metadata (declared sha + optional E2EE iv/epoch for re-supply).
|
|
1628
|
+
*/
|
|
1629
|
+
readonly pendingMedia: Map<string, {
|
|
1630
|
+
sha: string;
|
|
1631
|
+
iv?: string;
|
|
1632
|
+
genesisId?: string;
|
|
1633
|
+
}>;
|
|
1634
|
+
/** DISPLAY-ONLY transfer state for a pending part (doc 16 §5.2 step 4), so
|
|
1635
|
+
* the skeleton can say "fetching" versus "nobody online has this yet".
|
|
1636
|
+
* Written by the media transfer layer, read by the renderer; never part of
|
|
1637
|
+
* the document's identity and never serialized. */
|
|
1638
|
+
readonly mediaTransferState: Map<string, "fetching" | "waiting" | "unavailable">;
|
|
1639
|
+
/** Per-part media metadata that PERSISTS after install (doc 16 §5.3):
|
|
1640
|
+
* holder duty needs the sha (and E2EE iv/epoch) of READY parts to answer
|
|
1641
|
+
* re-supply requests; pendingMedia above only tracks not-yet-arrived. */
|
|
1642
|
+
readonly mediaMeta: Map<string, {
|
|
1643
|
+
sha: string;
|
|
1644
|
+
iv?: string;
|
|
1645
|
+
genesisId?: string;
|
|
1646
|
+
}>;
|
|
1647
|
+
/** "ready" = bytes present; "pending" = registered, bytes absent (doc 05).
|
|
1648
|
+
* Unregistered parts report "pending" too — a rel pointing at a missing
|
|
1649
|
+
* zip entry after a save/parse round-trip IS the pending state (a hole is
|
|
1650
|
+
* detectable, never corrupt — doc 16 §6 round-trip rule). */
|
|
1651
|
+
mediaStatus(part: string): "ready" | "pending";
|
|
1652
|
+
/**
|
|
1653
|
+
* Register an image part + relationship WITHOUT bytes (doc 16 §2: the
|
|
1654
|
+
* intent carries the sha; bytes travel out of band). Same deterministic
|
|
1655
|
+
* naming/rId scan as addImageResource so every replica applying the same
|
|
1656
|
+
* canonical intent derives identical registration.
|
|
1657
|
+
*/
|
|
1658
|
+
registerPendingImage(sha: string, ext: string, meta?: {
|
|
1659
|
+
iv?: string;
|
|
1660
|
+
genesisId?: string;
|
|
1661
|
+
}, source?: XmlElement): string;
|
|
1662
|
+
/** Install fetched bytes into a pending part (doc 05). The caller has
|
|
1663
|
+
* ALREADY verified the sha against the intent's declaration (the
|
|
1664
|
+
* reservation is the hash commitment — doc 16 §1.1); this installs and
|
|
1665
|
+
* clears the pending record. Returns false for unknown parts. */
|
|
1666
|
+
installMedia(part: string, bytes: Uint8Array): boolean;
|
|
1667
|
+
/** Effective paragraph properties: docDefaults → table style → style chain → direct. */
|
|
1668
|
+
effectiveParaProps(para: Paragraph): ParaProps;
|
|
1669
|
+
/**
|
|
1670
|
+
* Run props contributed by the enclosing table style's conditional
|
|
1671
|
+
* w:tblStylePr blocks for this paragraph's cell (undefined when the
|
|
1672
|
+
* paragraph isn't in a styled table cell or nothing applies).
|
|
1673
|
+
*/
|
|
1674
|
+
private tableCondRPr;
|
|
1675
|
+
/** Effective run properties for a run inside a paragraph. */
|
|
1676
|
+
effectiveRunProps(para: Paragraph, runProps: RunProps): RunProps;
|
|
1677
|
+
numberingLevel(numId: number, ilvl: number): NumberingLevel | undefined;
|
|
1678
|
+
numberingInstance(numId: number): NumInstance | undefined;
|
|
1679
|
+
private findDocumentPart;
|
|
1680
|
+
private readXmlOptional;
|
|
1681
|
+
}
|
|
1682
|
+
|
|
1683
|
+
/**
|
|
1684
|
+
* Wire intents for replicated editing.
|
|
1685
|
+
*
|
|
1686
|
+
* Positions address content by stable id (plan doc 02): `{ blockId, runId,
|
|
1687
|
+
* offset }`, where offset is a character offset within the run's text. Ids
|
|
1688
|
+
* come from the core StableIds side table; the server validates every
|
|
1689
|
+
* client-supplied id before applying (validate-then-install, doc 11) — the
|
|
1690
|
+
* types here are the transport shape, not a trust boundary.
|
|
1691
|
+
*
|
|
1692
|
+
* `base` is the last server sequence number the originating client had
|
|
1693
|
+
* applied when it produced the intent; the server transforms the intent
|
|
1694
|
+
* against everything sequenced in `(base, seq)` before applying and
|
|
1695
|
+
* broadcasting the canonical form (doc 03).
|
|
1696
|
+
*/
|
|
1697
|
+
type StableId = number;
|
|
1698
|
+
/** A caret/endpoint position within a run. */
|
|
1699
|
+
interface Position {
|
|
1700
|
+
blockId: StableId;
|
|
1701
|
+
runId: StableId;
|
|
1702
|
+
offset: number;
|
|
1703
|
+
}
|
|
1704
|
+
interface IntentBase {
|
|
1705
|
+
/** Originating client (authenticated identity; the server never trusts a
|
|
1706
|
+
* claimed id — see doc 11). */
|
|
1707
|
+
clientId: string;
|
|
1708
|
+
/** Per-client monotonic counter; `(clientId, clientSeq)` is the idempotency
|
|
1709
|
+
* key that dedups re-sends after reconnect (doc 03). */
|
|
1710
|
+
clientSeq: number;
|
|
1711
|
+
/** Last applied server seq at production time. */
|
|
1712
|
+
base: number;
|
|
1713
|
+
}
|
|
1714
|
+
/**
|
|
1715
|
+
* Tracked-change marks (plan doc 14 §3 L2): strike text ranges as w:del
|
|
1716
|
+
* revisions and/or mark paragraph glyphs (split "ins" marks, merge "del"
|
|
1717
|
+
* suggestions) — the SUGGESTING counterparts of deleteText/mergeParagraph.
|
|
1718
|
+
* Nothing is removed: Word keeps both sides until accept/reject (the
|
|
1719
|
+
* already-collab-wired accept/reject revision intents).
|
|
1720
|
+
* Author/date travel IN the intent (doc 05 rule a: nondeterministic values
|
|
1721
|
+
* are generated once by the originator); revision w:ids are scan-derived
|
|
1722
|
+
* from identical tree state on every replica. Positional offsets were
|
|
1723
|
+
* client-resolved (rule b — no Intl re-derivation at apply).
|
|
1724
|
+
*/
|
|
1725
|
+
interface SuggestRevisionIntent extends IntentBase {
|
|
1726
|
+
kind: "suggestRevision";
|
|
1727
|
+
ranges?: {
|
|
1728
|
+
blockId: StableId;
|
|
1729
|
+
runId: StableId;
|
|
1730
|
+
start: number;
|
|
1731
|
+
end: number;
|
|
1732
|
+
}[];
|
|
1733
|
+
marks?: {
|
|
1734
|
+
blockId: StableId;
|
|
1735
|
+
glyph: "ins" | "del";
|
|
1736
|
+
}[];
|
|
1737
|
+
suggest: {
|
|
1738
|
+
author: string;
|
|
1739
|
+
date: string;
|
|
1740
|
+
};
|
|
1741
|
+
}
|
|
1742
|
+
/** Insert `text` at a position. With `suggest`, the insertion is recorded as
|
|
1743
|
+
* a tracked change (w:ins) carrying the author + date (revision tracking /
|
|
1744
|
+
* suggesting mode), rather than a plain insert. */
|
|
1745
|
+
interface InsertTextIntent extends IntentBase {
|
|
1746
|
+
kind: "insertText";
|
|
1747
|
+
at: Position;
|
|
1748
|
+
text: string;
|
|
1749
|
+
/** Tracked-change (suggesting) metadata; omit for a plain insert. */
|
|
1750
|
+
suggest?: {
|
|
1751
|
+
author: string;
|
|
1752
|
+
date: string;
|
|
1753
|
+
};
|
|
1754
|
+
}
|
|
1755
|
+
/** Delete `[start, end)` characters within a single run. */
|
|
1756
|
+
interface DeleteTextIntent extends IntentBase {
|
|
1757
|
+
kind: "deleteText";
|
|
1758
|
+
blockId: StableId;
|
|
1759
|
+
runId: StableId;
|
|
1760
|
+
start: number;
|
|
1761
|
+
end: number;
|
|
1762
|
+
}
|
|
1763
|
+
/**
|
|
1764
|
+
* Split a paragraph at a position. Text after `at.offset` in run `at.runId`
|
|
1765
|
+
* (and following runs) moves to a new paragraph. The originating client
|
|
1766
|
+
* allocates the ids for the new paragraph and the new run holding the moved
|
|
1767
|
+
* tail; every replica installs these recorded values (doc 03), and they also
|
|
1768
|
+
* let the transform remap concurrent positions that fall in the moved tail.
|
|
1769
|
+
*/
|
|
1770
|
+
interface SplitParagraphIntent extends IntentBase {
|
|
1771
|
+
kind: "splitParagraph";
|
|
1772
|
+
at: Position;
|
|
1773
|
+
newBlockId: StableId;
|
|
1774
|
+
newRunId: StableId;
|
|
1775
|
+
/** With metadata, Enter remains a tracked paragraph-break suggestion. */
|
|
1776
|
+
suggest?: {
|
|
1777
|
+
author: string;
|
|
1778
|
+
date: string;
|
|
1779
|
+
};
|
|
1780
|
+
}
|
|
1781
|
+
/**
|
|
1782
|
+
* Character-format an entire run (bold/italic/underline/…). Whole-run only:
|
|
1783
|
+
* it mutates the run's w:rPr in place, so no run splits, no new ids, and the
|
|
1784
|
+
* run id is preserved — which makes its transform identity (formatting moves
|
|
1785
|
+
* no text). Sub-range formatting splits the run into up to three, needing the
|
|
1786
|
+
* run-split id-inheritance + position remapping (plan doc 03 F3); that is a
|
|
1787
|
+
* documented extension, not implemented here.
|
|
1788
|
+
*/
|
|
1789
|
+
interface FormatRunIntent extends IntentBase {
|
|
1790
|
+
kind: "formatRun";
|
|
1791
|
+
blockId: StableId;
|
|
1792
|
+
runId: StableId;
|
|
1793
|
+
/** RunFormatPatch (bold/italic/underline/strike/color/…). Structural shape
|
|
1794
|
+
* mirrors @wordinweb/core's RunFormatPatch; carried verbatim. */
|
|
1795
|
+
patch: Record<string, unknown>;
|
|
1796
|
+
}
|
|
1797
|
+
/**
|
|
1798
|
+
* Paragraph-level formatting: alignment and/or paragraph style. Block-level —
|
|
1799
|
+
* it mutates the paragraph's w:pPr, creates no tracked nodes, and moves no
|
|
1800
|
+
* text, so the block id is preserved and its transform is identity.
|
|
1801
|
+
*/
|
|
1802
|
+
interface FormatParagraphIntent extends IntentBase {
|
|
1803
|
+
kind: "formatParagraph";
|
|
1804
|
+
blockId: StableId;
|
|
1805
|
+
align?: "left" | "center" | "right" | "justify";
|
|
1806
|
+
/** Paragraph style id; null clears to Normal. Omit to leave unchanged. */
|
|
1807
|
+
styleId?: string | null;
|
|
1808
|
+
}
|
|
1809
|
+
/**
|
|
1810
|
+
* Turn a paragraph into a bullet/numbered list item, or clear its list
|
|
1811
|
+
* formatting (kind null). Block-level: mutates w:pPr/numbering, preserves the
|
|
1812
|
+
* block id, moves no text — transform identity.
|
|
1813
|
+
*/
|
|
1814
|
+
interface SetListTypeIntent extends IntentBase {
|
|
1815
|
+
kind: "setListType";
|
|
1816
|
+
blockId: StableId;
|
|
1817
|
+
listKind: "bullet" | "number" | null;
|
|
1818
|
+
}
|
|
1819
|
+
/**
|
|
1820
|
+
* Format a character sub-range of a single run (plan doc 03 F3). The run is
|
|
1821
|
+
* split into up to three pieces — before [0,start), middle [start,end)
|
|
1822
|
+
* (formatted), after [end,len) — replacing the original run. The originating
|
|
1823
|
+
* client allocates ids for the pieces that exist and carries them so every
|
|
1824
|
+
* replica addresses the pieces identically; the transform remaps any
|
|
1825
|
+
* concurrent position in the old run into the correct piece.
|
|
1826
|
+
*/
|
|
1827
|
+
interface FormatRangeIntent extends IntentBase {
|
|
1828
|
+
kind: "formatRange";
|
|
1829
|
+
blockId: StableId;
|
|
1830
|
+
runId: StableId;
|
|
1831
|
+
start: number;
|
|
1832
|
+
end: number;
|
|
1833
|
+
patch: Record<string, unknown>;
|
|
1834
|
+
/** Piece ids, present iff the piece exists: before when start>0, after when
|
|
1835
|
+
* end<runLen. middle always. */
|
|
1836
|
+
beforeId?: StableId;
|
|
1837
|
+
middleId: StableId;
|
|
1838
|
+
afterId?: StableId;
|
|
1839
|
+
}
|
|
1840
|
+
/**
|
|
1841
|
+
* A table operation that does NOT create new tracked nodes (so no carried ids
|
|
1842
|
+
* are needed and the transform is identity): delete row/column/table, cell
|
|
1843
|
+
* shading, cell vertical align. The target cell is addressed by the stable id
|
|
1844
|
+
* of a paragraph inside it. Row/column INSERTION (which creates cells with new
|
|
1845
|
+
* paragraphs and runs needing carried ids) is a documented harder extension.
|
|
1846
|
+
*/
|
|
1847
|
+
interface TableOpIntent extends IntentBase {
|
|
1848
|
+
/** Stable id of a paragraph inside the target cell. */
|
|
1849
|
+
cellParagraphId: StableId;
|
|
1850
|
+
kind: "tableOp";
|
|
1851
|
+
op: "deleteRow" | "deleteCol" | "deleteTable" | "rowAbove" | "rowBelow" | "colLeft" | "colRight" | {
|
|
1852
|
+
kind: "cellShading";
|
|
1853
|
+
fill: string | null;
|
|
1854
|
+
} | {
|
|
1855
|
+
kind: "cellVAlign";
|
|
1856
|
+
v: "top" | "center" | "bottom";
|
|
1857
|
+
} | {
|
|
1858
|
+
kind: "textWrapping";
|
|
1859
|
+
wrapping: "none" | "around";
|
|
1860
|
+
xPx: number;
|
|
1861
|
+
yPx: number;
|
|
1862
|
+
};
|
|
1863
|
+
/** For INSERT ops (rowAbove/rowBelow/colLeft/colRight): carried ids for the
|
|
1864
|
+
* new tracked nodes (p / r) in document order, so replicas address them
|
|
1865
|
+
* alike. */
|
|
1866
|
+
nodeIds?: StableId[];
|
|
1867
|
+
}
|
|
1868
|
+
/**
|
|
1869
|
+
* Merge a paragraph into its predecessor (Backspace at paragraph start). The
|
|
1870
|
+
* paragraph's runs MOVE into the previous paragraph (element identity
|
|
1871
|
+
* preserved), so run-addressed positions survive unchanged — an identity
|
|
1872
|
+
* transform. The merged paragraph's block id is retired.
|
|
1873
|
+
*/
|
|
1874
|
+
interface MergeParagraphIntent extends IntentBase {
|
|
1875
|
+
kind: "mergeParagraph";
|
|
1876
|
+
/** The paragraph to merge into the one before it. */
|
|
1877
|
+
blockId: StableId;
|
|
1878
|
+
}
|
|
1879
|
+
/**
|
|
1880
|
+
* Add a review comment anchored to an entire run. Comment markers
|
|
1881
|
+
* (commentRangeStart/End + a commentReference run) are inserted as run
|
|
1882
|
+
* siblings and the comment body goes into comments.xml — no commented run's
|
|
1883
|
+
* text moves, so the transform is identity. The nondeterministic values
|
|
1884
|
+
* (w14:paraId, w:date) are generated once by the originating client and
|
|
1885
|
+
* carried here (plan doc 05) so every replica writes identical XML. Sub-range
|
|
1886
|
+
* comments (splitting the run) are the documented harder extension.
|
|
1887
|
+
*/
|
|
1888
|
+
interface CommentRunIntent extends IntentBase {
|
|
1889
|
+
kind: "commentRun";
|
|
1890
|
+
runId: StableId;
|
|
1891
|
+
text: string;
|
|
1892
|
+
author: string;
|
|
1893
|
+
initials?: string;
|
|
1894
|
+
/** Carried provenance for deterministic XML across replicas. */
|
|
1895
|
+
date: string;
|
|
1896
|
+
paraId: string;
|
|
1897
|
+
}
|
|
1898
|
+
/**
|
|
1899
|
+
* Rich paste: splice validated OOXML paragraph blocks after a target
|
|
1900
|
+
* paragraph. The pasting client converts clipboard HTML to OOXML locally
|
|
1901
|
+
* (browser-only, engine-dependent — doc 02 M4) and carries the serialized
|
|
1902
|
+
* blocks; the server VALIDATES them against the positive allowlist before
|
|
1903
|
+
* applying (doc 11 gate 2). `nodeIds` are carried ids for the new tracked
|
|
1904
|
+
* nodes (p / r) in document order, so every replica addresses them alike.
|
|
1905
|
+
* Inserting separate blocks shifts no existing run's offsets — identity
|
|
1906
|
+
* transform.
|
|
1907
|
+
*/
|
|
1908
|
+
interface PasteBlocksIntent extends IntentBase {
|
|
1909
|
+
kind: "pasteBlocks";
|
|
1910
|
+
/** Paragraph after which to insert the pasted blocks. */
|
|
1911
|
+
afterBlockId: StableId;
|
|
1912
|
+
/** Serialized OOXML block list (w:p elements), validated at apply. */
|
|
1913
|
+
blocksXml: string;
|
|
1914
|
+
/** Carried ids for the new p/r nodes, in document order. */
|
|
1915
|
+
nodeIds: StableId[];
|
|
1916
|
+
}
|
|
1917
|
+
/**
|
|
1918
|
+
* Insert an image at a run (as a sibling drawing run — no text split, identity
|
|
1919
|
+
* transform). The plan's media design carries bytes out-of-band via presigned
|
|
1920
|
+
* upload with the intent carrying (part, extents, sha) — modeled here with the
|
|
1921
|
+
* bytes inline (base64), which is correct for small images and keeps the whole
|
|
1922
|
+
* flow testable headlessly; the out-of-band path is a transport optimization
|
|
1923
|
+
* over the same convergence. Client-measured dimensions (widthPx/heightPx) are
|
|
1924
|
+
* carried so layout reserves space deterministically. `nodeIds` are carried
|
|
1925
|
+
* ids for the new drawing run(s).
|
|
1926
|
+
*/
|
|
1927
|
+
interface InsertImageIntent extends IntentBase {
|
|
1928
|
+
kind: "insertImage";
|
|
1929
|
+
runId: StableId;
|
|
1930
|
+
/**
|
|
1931
|
+
* sha256 hex of the BLOB (plan doc 16 §2): plaintext bytes in plaintext
|
|
1932
|
+
* mode, ciphertext in E2EE mode. This is the reservation's hash
|
|
1933
|
+
* COMMITMENT — every replica registers the part pending and verifies any
|
|
1934
|
+
* later-arriving bytes against it (the swap-proofing trust chain, doc 16
|
|
1935
|
+
* §1.1). Bytes NEVER ride the intent (doc 06: sequencer bandwidth is
|
|
1936
|
+
* proportional to typing, not content).
|
|
1937
|
+
*/
|
|
1938
|
+
blobSha: string;
|
|
1939
|
+
/** Blob length in bytes — validate.ts bounds it (doc 13 blocker 3). */
|
|
1940
|
+
bytesLen: number;
|
|
1941
|
+
/** File extension without dot (png/jpg/gif…) — drives the content type. */
|
|
1942
|
+
ext: string;
|
|
1943
|
+
/** E2EE only: base64 12-byte GCM IV, recorded so any holder can re-seal
|
|
1944
|
+
* byte-identically for re-supply (doc 16 §5.3). */
|
|
1945
|
+
iv?: string;
|
|
1946
|
+
widthPx: number;
|
|
1947
|
+
heightPx: number;
|
|
1948
|
+
nodeIds: StableId[];
|
|
1949
|
+
}
|
|
1950
|
+
/**
|
|
1951
|
+
* Insert a page/column break at the END of a run (inserts sibling break + tail
|
|
1952
|
+
* runs — no text split, identity transform). Mid-run breaks (which split the
|
|
1953
|
+
* run) follow the carried-id-split pattern (formatRange) and are the
|
|
1954
|
+
* documented extension. `nodeIds` are carried ids for the new runs.
|
|
1955
|
+
*/
|
|
1956
|
+
interface InsertBreakIntent extends IntentBase {
|
|
1957
|
+
kind: "insertBreak";
|
|
1958
|
+
runId: StableId;
|
|
1959
|
+
breakKind: "page" | "column";
|
|
1960
|
+
nodeIds: StableId[];
|
|
1961
|
+
}
|
|
1962
|
+
/**
|
|
1963
|
+
* Insert a math (OMML) formula from a linear expression at the end of a run
|
|
1964
|
+
* (sibling insertion — identity transform). `nodeIds` for any new tracked
|
|
1965
|
+
* nodes.
|
|
1966
|
+
*/
|
|
1967
|
+
interface InsertMathIntent extends IntentBase {
|
|
1968
|
+
kind: "insertMath";
|
|
1969
|
+
runId: StableId;
|
|
1970
|
+
mathText: string;
|
|
1971
|
+
nodeIds: StableId[];
|
|
1972
|
+
}
|
|
1973
|
+
/** Insert a shape/textbox drawing at the end of a run (sibling — identity). */
|
|
1974
|
+
interface InsertShapeIntent extends IntentBase {
|
|
1975
|
+
kind: "insertShape";
|
|
1976
|
+
runId: StableId;
|
|
1977
|
+
preset: "line" | "verticalLine" | "rectangle" | "roundedRectangle" | "ellipse" | "diamond" | "textBox";
|
|
1978
|
+
text?: string;
|
|
1979
|
+
nodeIds: StableId[];
|
|
1980
|
+
}
|
|
1981
|
+
/**
|
|
1982
|
+
* Reply to an existing comment (threading). Addressed by the parent comment's
|
|
1983
|
+
* id (a deterministic string). Carries provenance (w14:paraId candidates in
|
|
1984
|
+
* consumption order + the w:date) so every replica writes identical XML. No
|
|
1985
|
+
* document run's text moves — identity transform.
|
|
1986
|
+
*/
|
|
1987
|
+
interface ReplyCommentIntent extends IntentBase {
|
|
1988
|
+
kind: "replyComment";
|
|
1989
|
+
parentId: string;
|
|
1990
|
+
text: string;
|
|
1991
|
+
author: string;
|
|
1992
|
+
initials?: string;
|
|
1993
|
+
date: string;
|
|
1994
|
+
/** paraId candidates in the order replyToComment consumes them: the reply's
|
|
1995
|
+
* paraId, preceded by the parent's if the parent lacks one. */
|
|
1996
|
+
paraIds: string[];
|
|
1997
|
+
}
|
|
1998
|
+
/** Adjust a paragraph's indent (Tab/Shift-Tab). Block-level, identity. */
|
|
1999
|
+
interface AdjustIndentIntent extends IntentBase {
|
|
2000
|
+
kind: "adjustIndent";
|
|
2001
|
+
blockId: StableId;
|
|
2002
|
+
direction: 1 | -1;
|
|
2003
|
+
}
|
|
2004
|
+
/** Set paragraph line/before/after spacing. Block-level, identity. */
|
|
2005
|
+
interface SetSpacingIntent extends IntentBase {
|
|
2006
|
+
kind: "setSpacing";
|
|
2007
|
+
blockId: StableId;
|
|
2008
|
+
/** ParagraphSpacingPatch (before/after/line/lineRule) — carried verbatim. */
|
|
2009
|
+
patch: Record<string, unknown>;
|
|
2010
|
+
}
|
|
2011
|
+
/** Insert a page-number field at the end of a run (sibling insertion,
|
|
2012
|
+
* identity). Page fields are deterministic (no clock). */
|
|
2013
|
+
interface InsertPageFieldIntent extends IntentBase {
|
|
2014
|
+
kind: "insertPageField";
|
|
2015
|
+
runId: StableId;
|
|
2016
|
+
fieldKind: "page" | "pageOfTotal";
|
|
2017
|
+
nodeIds: StableId[];
|
|
2018
|
+
}
|
|
2019
|
+
/** Wrap a run in a hyperlink to `url`. The url is scheme-validated at apply
|
|
2020
|
+
* (rejects javascript:/data: etc. — doc 11 gate 1). Run-level, identity. */
|
|
2021
|
+
interface SetLinkIntent extends IntentBase {
|
|
2022
|
+
kind: "setLink";
|
|
2023
|
+
runId: StableId;
|
|
2024
|
+
url: string;
|
|
2025
|
+
nodeIds: StableId[];
|
|
2026
|
+
}
|
|
2027
|
+
/** Insert a footnote reference at the end of a run + its footnote text. */
|
|
2028
|
+
interface InsertFootnoteIntent extends IntentBase {
|
|
2029
|
+
kind: "insertFootnote";
|
|
2030
|
+
runId: StableId;
|
|
2031
|
+
text: string;
|
|
2032
|
+
nodeIds: StableId[];
|
|
2033
|
+
}
|
|
2034
|
+
/** Set/clear a drop cap on a paragraph. Block-level. */
|
|
2035
|
+
interface SetDropCapIntent extends IntentBase {
|
|
2036
|
+
kind: "setDropCap";
|
|
2037
|
+
blockId: StableId;
|
|
2038
|
+
mode: "drop" | "margin" | null;
|
|
2039
|
+
nodeIds: StableId[];
|
|
2040
|
+
}
|
|
2041
|
+
/** Set/clear a paragraph divider (horizontal rule). Block-level, identity. */
|
|
2042
|
+
interface SetDividerIntent extends IntentBase {
|
|
2043
|
+
kind: "setDivider";
|
|
2044
|
+
blockId: StableId;
|
|
2045
|
+
divider: Record<string, unknown> | null;
|
|
2046
|
+
}
|
|
2047
|
+
/** Insert a bookmark anchor at the end of a run. */
|
|
2048
|
+
interface InsertBookmarkIntent extends IntentBase {
|
|
2049
|
+
kind: "insertBookmark";
|
|
2050
|
+
runId: StableId;
|
|
2051
|
+
name: string;
|
|
2052
|
+
}
|
|
2053
|
+
type Intent = InsertTextIntent | DeleteTextIntent | SplitParagraphIntent | FormatRunIntent | FormatParagraphIntent | SetListTypeIntent | FormatRangeIntent | TableOpIntent | MergeParagraphIntent | CommentRunIntent | PasteBlocksIntent | InsertImageIntent | SuggestRevisionIntent | InsertBreakIntent | InsertMathIntent | InsertShapeIntent | ReplyCommentIntent | AdjustIndentIntent | SetSpacingIntent | InsertPageFieldIntent | SetLinkIntent | InsertFootnoteIntent | SetDropCapIntent | SetDividerIntent | InsertBookmarkIntent | InsertBlankPageIntent | InsertSectionBreakIntent | InsertCrossRefIntent | InsertCoverPageIntent | SetPageLayoutIntent | SetListLevelIntent | InsertWordArtIntent | InsertChartIntent | InsertSmartArtIntent | SetLineNumberingIntent | InsertDateTimeFieldIntent | InsertFieldIntent | SetDrawingRotationIntent | SetDrawingFillIntent | SetChartDataIntent | SetSmartArtNodeTextIntent | SetDrawingWordArtTextIntent | SetDrawingWordArtStyleIntent | SetDrawingLineStyleIntent | SetImageAltTextIntent | RemoveLinkIntent | SetImageWrapIntent | SetDrawingOrderIntent | SetSmartArtDataIntent | SetSmartArtFillIntent | SetSmartArtTextFormatIntent | SetFloatingPagePositionIntent | ResizeDrawingIntent | ResizeTableColumnIntent | ResizeTableRowIntent | MoveTableIntent | RemoveDrawingIntent | SetMathLinearIntent | DeleteMathIntent | MoveMathIntent | EnsureHeaderFooterIntent | DeleteCommentIntent | InsertBookmarkRangeIntent | ToggleCheckboxIntent | AcceptRevisionIntent | RejectRevisionIntent | AcceptAllRevisionsIntent | RejectAllRevisionsIntent | InsertTableIntent;
|
|
2054
|
+
/** Insert a blank page at the end of a run. */
|
|
2055
|
+
interface InsertBlankPageIntent extends IntentBase {
|
|
2056
|
+
kind: "insertBlankPage";
|
|
2057
|
+
runId: StableId;
|
|
2058
|
+
nodeIds: StableId[];
|
|
2059
|
+
}
|
|
2060
|
+
/** Insert a section break at the end of a run. */
|
|
2061
|
+
interface InsertSectionBreakIntent extends IntentBase {
|
|
2062
|
+
kind: "insertSectionBreak";
|
|
2063
|
+
runId: StableId;
|
|
2064
|
+
breakType: "nextPage" | "continuous";
|
|
2065
|
+
nodeIds: StableId[];
|
|
2066
|
+
}
|
|
2067
|
+
/** Insert a cross-reference to a bookmark at the end of a run. */
|
|
2068
|
+
interface InsertCrossRefIntent extends IntentBase {
|
|
2069
|
+
kind: "insertCrossRef";
|
|
2070
|
+
runId: StableId;
|
|
2071
|
+
bookmark: string;
|
|
2072
|
+
refKind: "text" | "page";
|
|
2073
|
+
nodeIds: StableId[];
|
|
2074
|
+
}
|
|
2075
|
+
/** Insert a cover page (document-level). */
|
|
2076
|
+
interface InsertCoverPageIntent extends IntentBase {
|
|
2077
|
+
kind: "insertCoverPage";
|
|
2078
|
+
/** CoverPageContent ({title, subtitle?, author?, …}) — carried verbatim. */
|
|
2079
|
+
content: Record<string, unknown>;
|
|
2080
|
+
nodeIds: StableId[];
|
|
2081
|
+
}
|
|
2082
|
+
/** Update page setup: margins/size/orientation/columns/borders. When target is
|
|
2083
|
+
* omitted it applies to every section; document-level, identity transform. */
|
|
2084
|
+
interface SetPageLayoutIntent extends IntentBase {
|
|
2085
|
+
kind: "setPageLayout";
|
|
2086
|
+
/** PageLayoutPatch ({margins?, size?, orientation?, columns?, …}) — carried
|
|
2087
|
+
* verbatim; validated against a shape+range allowlist. */
|
|
2088
|
+
patch: Record<string, unknown>;
|
|
2089
|
+
}
|
|
2090
|
+
/** Indent (+1) or outdent (-1) a paragraph's list nesting level. Block-level. */
|
|
2091
|
+
interface SetListLevelIntent extends IntentBase {
|
|
2092
|
+
kind: "setListLevel";
|
|
2093
|
+
blockId: StableId;
|
|
2094
|
+
delta: 1 | -1;
|
|
2095
|
+
}
|
|
2096
|
+
/** Insert decorative WordArt (a text drawing) at the end of a run. */
|
|
2097
|
+
interface InsertWordArtIntent extends IntentBase {
|
|
2098
|
+
kind: "insertWordArt";
|
|
2099
|
+
runId: StableId;
|
|
2100
|
+
text: string;
|
|
2101
|
+
preset: "plain" | "archUp" | "archDown" | "wave" | "chevron";
|
|
2102
|
+
nodeIds: StableId[];
|
|
2103
|
+
}
|
|
2104
|
+
/** Insert a data chart (column/bar/line/pie) at the end of a run. The chart
|
|
2105
|
+
* data is carried verbatim; the workbook part is generated deterministically. */
|
|
2106
|
+
interface InsertChartIntent extends IntentBase {
|
|
2107
|
+
kind: "insertChart";
|
|
2108
|
+
runId: StableId;
|
|
2109
|
+
chart: {
|
|
2110
|
+
type: "column" | "bar" | "line" | "pie";
|
|
2111
|
+
title?: string;
|
|
2112
|
+
categories: string[];
|
|
2113
|
+
series: {
|
|
2114
|
+
name: string;
|
|
2115
|
+
values: number[];
|
|
2116
|
+
}[];
|
|
2117
|
+
};
|
|
2118
|
+
nodeIds: StableId[];
|
|
2119
|
+
}
|
|
2120
|
+
/** Insert a SmartArt diagram (process/cycle/hierarchy/list) at end of a run. */
|
|
2121
|
+
interface InsertSmartArtIntent extends IntentBase {
|
|
2122
|
+
kind: "insertSmartArt";
|
|
2123
|
+
runId: StableId;
|
|
2124
|
+
smartArt: {
|
|
2125
|
+
layout: "process" | "cycle" | "hierarchy" | "list";
|
|
2126
|
+
items: string[];
|
|
2127
|
+
};
|
|
2128
|
+
nodeIds: StableId[];
|
|
2129
|
+
}
|
|
2130
|
+
/** Toggle/configure margin line numbering for the section(s). Document-level. */
|
|
2131
|
+
interface SetLineNumberingIntent extends IntentBase {
|
|
2132
|
+
kind: "setLineNumbering";
|
|
2133
|
+
patch: {
|
|
2134
|
+
enabled: boolean;
|
|
2135
|
+
countBy?: number;
|
|
2136
|
+
restart?: "continuous" | "newPage" | "newSection";
|
|
2137
|
+
start?: number;
|
|
2138
|
+
};
|
|
2139
|
+
}
|
|
2140
|
+
/** Insert an auto-updating DATE or TIME field at the end of a run. The picture
|
|
2141
|
+
* (format string) is carried so every replica renders identical field XML. */
|
|
2142
|
+
interface InsertDateTimeFieldIntent extends IntentBase {
|
|
2143
|
+
kind: "insertDateTimeField";
|
|
2144
|
+
runId: StableId;
|
|
2145
|
+
dtKind: "date" | "time";
|
|
2146
|
+
picture: string;
|
|
2147
|
+
nodeIds: StableId[];
|
|
2148
|
+
}
|
|
2149
|
+
/** Insert a Word field (e.g. PAGE, NUMPAGES, REF) at the end of a run. The
|
|
2150
|
+
* instruction is restricted to a safe positive allowlist (no INCLUDETEXT/DDE/
|
|
2151
|
+
* LINK external-content fields). */
|
|
2152
|
+
interface InsertFieldIntent extends IntentBase {
|
|
2153
|
+
kind: "insertField";
|
|
2154
|
+
runId: StableId;
|
|
2155
|
+
instruction: string;
|
|
2156
|
+
cachedResult?: string;
|
|
2157
|
+
nodeIds: StableId[];
|
|
2158
|
+
}
|
|
2159
|
+
interface DrawingTarget {
|
|
2160
|
+
runId: StableId;
|
|
2161
|
+
/** Parsed run-content index. It disambiguates several drawings carried by one run. */
|
|
2162
|
+
objectIndex?: number;
|
|
2163
|
+
}
|
|
2164
|
+
/** Rotate the drawing carried by a run. Identity transform (run-addressed). */
|
|
2165
|
+
interface SetDrawingRotationIntent extends IntentBase, DrawingTarget {
|
|
2166
|
+
kind: "setDrawingRotation";
|
|
2167
|
+
runId: StableId;
|
|
2168
|
+
degrees: number;
|
|
2169
|
+
}
|
|
2170
|
+
/** Set/clear the solid fill of the drawing carried by a run. `color` is a
|
|
2171
|
+
* 6-hex-digit RGB (no #) or null to clear. */
|
|
2172
|
+
interface SetDrawingFillIntent extends IntentBase, DrawingTarget {
|
|
2173
|
+
kind: "setDrawingFill";
|
|
2174
|
+
runId: StableId;
|
|
2175
|
+
color: string | null;
|
|
2176
|
+
}
|
|
2177
|
+
/** Replace the data of the chart carried by a run (same shape as insertChart's
|
|
2178
|
+
* chart). Edits an existing chart in place. */
|
|
2179
|
+
interface SetChartDataIntent extends IntentBase, DrawingTarget {
|
|
2180
|
+
kind: "setChartData";
|
|
2181
|
+
runId: StableId;
|
|
2182
|
+
chart: {
|
|
2183
|
+
type: "column" | "bar" | "line" | "pie";
|
|
2184
|
+
title?: string;
|
|
2185
|
+
categories: string[];
|
|
2186
|
+
series: {
|
|
2187
|
+
name: string;
|
|
2188
|
+
values: number[];
|
|
2189
|
+
}[];
|
|
2190
|
+
};
|
|
2191
|
+
}
|
|
2192
|
+
/** Set the text of one node of the SmartArt diagram carried by a run. */
|
|
2193
|
+
interface SetSmartArtNodeTextIntent extends IntentBase, DrawingTarget {
|
|
2194
|
+
kind: "setSmartArtNodeText";
|
|
2195
|
+
runId: StableId;
|
|
2196
|
+
index: number;
|
|
2197
|
+
text: string;
|
|
2198
|
+
}
|
|
2199
|
+
/** Replace the text of the WordArt drawing carried by a run. */
|
|
2200
|
+
interface SetDrawingWordArtTextIntent extends IntentBase, DrawingTarget {
|
|
2201
|
+
kind: "setDrawingWordArtText";
|
|
2202
|
+
runId: StableId;
|
|
2203
|
+
text: string;
|
|
2204
|
+
}
|
|
2205
|
+
/** Set the glyph fill and alpha of the WordArt drawing carried by a run. */
|
|
2206
|
+
interface SetDrawingWordArtStyleIntent extends IntentBase, DrawingTarget {
|
|
2207
|
+
kind: "setDrawingWordArtStyle";
|
|
2208
|
+
runId: StableId;
|
|
2209
|
+
color: string;
|
|
2210
|
+
opacity: number;
|
|
2211
|
+
}
|
|
2212
|
+
/** Set or clear the outline of the drawing carried by a run. */
|
|
2213
|
+
type SetDrawingLineStyleIntent = IntentBase & DrawingTarget & {
|
|
2214
|
+
kind: "setDrawingLineStyle";
|
|
2215
|
+
runId: StableId;
|
|
2216
|
+
} & ({
|
|
2217
|
+
color: null;
|
|
2218
|
+
widthPx?: number;
|
|
2219
|
+
dash?: "solid" | "dashed" | "dotted";
|
|
2220
|
+
} | {
|
|
2221
|
+
color: string;
|
|
2222
|
+
widthPx: number;
|
|
2223
|
+
dash: "solid" | "dashed" | "dotted";
|
|
2224
|
+
});
|
|
2225
|
+
/** Set/clear the alt text (accessibility description) of the image/drawing
|
|
2226
|
+
* carried by a run. Empty string clears it. */
|
|
2227
|
+
interface SetImageAltTextIntent extends IntentBase, DrawingTarget {
|
|
2228
|
+
kind: "setImageAltText";
|
|
2229
|
+
runId: StableId;
|
|
2230
|
+
alt: string;
|
|
2231
|
+
}
|
|
2232
|
+
/** Remove the hyperlink wrapping a run's text (inverse of setLink). */
|
|
2233
|
+
interface RemoveLinkIntent extends IntentBase {
|
|
2234
|
+
kind: "removeLink";
|
|
2235
|
+
runId: StableId;
|
|
2236
|
+
}
|
|
2237
|
+
/** Set the text-wrap mode of the drawing carried by a run. A floating mode
|
|
2238
|
+
* converts an inline drawing to an anchor. */
|
|
2239
|
+
interface SetImageWrapIntent extends IntentBase, DrawingTarget {
|
|
2240
|
+
kind: "setImageWrap";
|
|
2241
|
+
runId: StableId;
|
|
2242
|
+
mode: "inline" | "square" | "topAndBottom" | "none" | "behind";
|
|
2243
|
+
}
|
|
2244
|
+
/** Bring the (floating) drawing carried by a run to front/back. */
|
|
2245
|
+
interface SetDrawingOrderIntent extends IntentBase, DrawingTarget {
|
|
2246
|
+
kind: "setDrawingOrder";
|
|
2247
|
+
runId: StableId;
|
|
2248
|
+
order: "front" | "back";
|
|
2249
|
+
}
|
|
2250
|
+
/** Replace the whole SmartArt diagram (layout + items) carried by a run. */
|
|
2251
|
+
interface SetSmartArtDataIntent extends IntentBase, DrawingTarget {
|
|
2252
|
+
kind: "setSmartArtData";
|
|
2253
|
+
runId: StableId;
|
|
2254
|
+
smartArt: {
|
|
2255
|
+
layout: "process" | "cycle" | "hierarchy" | "list";
|
|
2256
|
+
items: string[];
|
|
2257
|
+
};
|
|
2258
|
+
}
|
|
2259
|
+
/** Set/clear the fill of a SmartArt node (or all nodes when nodeIndex omitted).
|
|
2260
|
+
* `color` is 6-hex RGB (no #) or null to clear. */
|
|
2261
|
+
interface SetSmartArtFillIntent extends IntentBase, DrawingTarget {
|
|
2262
|
+
kind: "setSmartArtFill";
|
|
2263
|
+
runId: StableId;
|
|
2264
|
+
color: string | null;
|
|
2265
|
+
nodeIndex?: number;
|
|
2266
|
+
}
|
|
2267
|
+
/** Set the text format of a SmartArt node (or all nodes). */
|
|
2268
|
+
interface SetSmartArtTextFormatIntent extends IntentBase, DrawingTarget {
|
|
2269
|
+
kind: "setSmartArtTextFormat";
|
|
2270
|
+
runId: StableId;
|
|
2271
|
+
format: {
|
|
2272
|
+
fontFamily: string;
|
|
2273
|
+
fontSizePt: number;
|
|
2274
|
+
color: string;
|
|
2275
|
+
bold: boolean;
|
|
2276
|
+
italic: boolean;
|
|
2277
|
+
alignment: "left" | "center" | "right";
|
|
2278
|
+
};
|
|
2279
|
+
nodeIndex?: number;
|
|
2280
|
+
}
|
|
2281
|
+
/** Position the (floating) drawing carried by a run relative to the page. */
|
|
2282
|
+
interface SetFloatingPagePositionIntent extends IntentBase, DrawingTarget {
|
|
2283
|
+
kind: "setFloatingPagePosition";
|
|
2284
|
+
runId: StableId;
|
|
2285
|
+
xPx: number;
|
|
2286
|
+
yPx: number;
|
|
2287
|
+
}
|
|
2288
|
+
/** Resize the drawing carried by a run (extent in px; the mutation clamps to
|
|
2289
|
+
* a 1px-EMU floor and keeps line geometry degenerate on its minor axis). */
|
|
2290
|
+
interface ResizeDrawingIntent extends IntentBase, DrawingTarget {
|
|
2291
|
+
kind: "resizeDrawing";
|
|
2292
|
+
runId: StableId;
|
|
2293
|
+
widthPx: number;
|
|
2294
|
+
heightPx: number;
|
|
2295
|
+
}
|
|
2296
|
+
/** Drag-resize a table column boundary. Addressed like tableOp: a paragraph
|
|
2297
|
+
* inside the table. `renderedWidths` (the dragger's measured column widths)
|
|
2298
|
+
* rides as DATA so every replica applies the identical mutation. */
|
|
2299
|
+
interface ResizeTableColumnIntent extends IntentBase {
|
|
2300
|
+
kind: "resizeTableColumn";
|
|
2301
|
+
cellParagraphId: StableId;
|
|
2302
|
+
boundary: number;
|
|
2303
|
+
deltaPx: number;
|
|
2304
|
+
renderedWidths?: number[];
|
|
2305
|
+
}
|
|
2306
|
+
/** Drag-resize a table row's height (trHeight atLeast). */
|
|
2307
|
+
interface ResizeTableRowIntent extends IntentBase {
|
|
2308
|
+
kind: "resizeTableRow";
|
|
2309
|
+
cellParagraphId: StableId;
|
|
2310
|
+
rowIdx: number;
|
|
2311
|
+
heightPx: number;
|
|
2312
|
+
}
|
|
2313
|
+
/** Position a table at page coordinates (converts inline to float). */
|
|
2314
|
+
interface MoveTableIntent extends IntentBase {
|
|
2315
|
+
kind: "moveTable";
|
|
2316
|
+
cellParagraphId: StableId;
|
|
2317
|
+
xPx: number;
|
|
2318
|
+
yPx: number;
|
|
2319
|
+
preservePageStart: boolean;
|
|
2320
|
+
pageDelta: number;
|
|
2321
|
+
}
|
|
2322
|
+
/** Delete the drawing at the supplied run-content target. */
|
|
2323
|
+
interface RemoveDrawingIntent extends IntentBase, DrawingTarget {
|
|
2324
|
+
kind: "removeDrawing";
|
|
2325
|
+
runId: StableId;
|
|
2326
|
+
}
|
|
2327
|
+
/** Replace the equation of the math object in a paragraph (linear syntax).
|
|
2328
|
+
* Math (m:oMath) lives at paragraph level, so this is block-addressed. */
|
|
2329
|
+
interface SetMathLinearIntent extends IntentBase {
|
|
2330
|
+
kind: "setMathLinear";
|
|
2331
|
+
blockId: StableId;
|
|
2332
|
+
mathText: string;
|
|
2333
|
+
}
|
|
2334
|
+
/** Delete the math object in a paragraph. */
|
|
2335
|
+
interface DeleteMathIntent extends IntentBase {
|
|
2336
|
+
kind: "deleteMath";
|
|
2337
|
+
blockId: StableId;
|
|
2338
|
+
}
|
|
2339
|
+
/** Drag-move the equation out of `blockId` to the text position `at`. The
|
|
2340
|
+
* equation is addressed like the other math intents (block + firstMathIn); the
|
|
2341
|
+
* destination is an ordinary wire caret. Dropping mid-text splits the
|
|
2342
|
+
* destination run, so the split-off tail run takes a carried id. */
|
|
2343
|
+
interface MoveMathIntent extends IntentBase {
|
|
2344
|
+
kind: "moveMath";
|
|
2345
|
+
blockId: StableId;
|
|
2346
|
+
at: Position;
|
|
2347
|
+
nodeIds: StableId[];
|
|
2348
|
+
}
|
|
2349
|
+
/** Create the document's header (or footer) part the way Word does on first
|
|
2350
|
+
* entry into the margin band: a new part + relationship + content-type
|
|
2351
|
+
* override, referenced from every sectPr (one is materialized when a minimal
|
|
2352
|
+
* document has none). Applies as a clean no-op when the part already exists,
|
|
2353
|
+
* so it is safe for two participants to open the header at the same moment.
|
|
2354
|
+
* The created paragraph and run take carried ids — every later edit in the
|
|
2355
|
+
* header addresses them. */
|
|
2356
|
+
interface EnsureHeaderFooterIntent extends IntentBase {
|
|
2357
|
+
kind: "ensureHeaderFooter";
|
|
2358
|
+
hfKind: "header" | "footer";
|
|
2359
|
+
nodeIds: StableId[];
|
|
2360
|
+
}
|
|
2361
|
+
/** Delete a comment (and its reply thread) by id. */
|
|
2362
|
+
interface DeleteCommentIntent extends IntentBase {
|
|
2363
|
+
kind: "deleteComment";
|
|
2364
|
+
commentId: string;
|
|
2365
|
+
}
|
|
2366
|
+
/** Wrap a sub-range of a run's text in a named bookmark. */
|
|
2367
|
+
interface InsertBookmarkRangeIntent extends IntentBase {
|
|
2368
|
+
kind: "insertBookmarkRange";
|
|
2369
|
+
runId: StableId;
|
|
2370
|
+
name: string;
|
|
2371
|
+
start: number;
|
|
2372
|
+
end: number;
|
|
2373
|
+
}
|
|
2374
|
+
/** Toggle the checkbox content control carried by a run. */
|
|
2375
|
+
interface ToggleCheckboxIntent extends IntentBase {
|
|
2376
|
+
kind: "toggleCheckbox";
|
|
2377
|
+
runId: StableId;
|
|
2378
|
+
}
|
|
2379
|
+
/** Accept one tracked change, addressed by its position in document order
|
|
2380
|
+
* (collectRevisions order — deterministic across replicas). */
|
|
2381
|
+
interface AcceptRevisionIntent extends IntentBase {
|
|
2382
|
+
kind: "acceptRevision";
|
|
2383
|
+
index: number;
|
|
2384
|
+
}
|
|
2385
|
+
/** Reject one tracked change, addressed by document-order index. */
|
|
2386
|
+
interface RejectRevisionIntent extends IntentBase {
|
|
2387
|
+
kind: "rejectRevision";
|
|
2388
|
+
index: number;
|
|
2389
|
+
}
|
|
2390
|
+
/** Accept every tracked change in the document. */
|
|
2391
|
+
interface AcceptAllRevisionsIntent extends IntentBase {
|
|
2392
|
+
kind: "acceptAllRevisions";
|
|
2393
|
+
}
|
|
2394
|
+
/** Reject every tracked change in the document. */
|
|
2395
|
+
interface RejectAllRevisionsIntent extends IntentBase {
|
|
2396
|
+
kind: "rejectAllRevisions";
|
|
2397
|
+
}
|
|
2398
|
+
/** Insert a rows×cols table after the paragraph containing the anchor run. */
|
|
2399
|
+
interface InsertTableIntent extends IntentBase {
|
|
2400
|
+
kind: "insertTable";
|
|
2401
|
+
runId: StableId;
|
|
2402
|
+
rows: number;
|
|
2403
|
+
cols: number;
|
|
2404
|
+
nodeIds: StableId[];
|
|
2405
|
+
}
|
|
2406
|
+
/** An intent minus its wire bookkeeping — distributive over the union so each
|
|
2407
|
+
* variant keeps its own fields (a plain Omit<Intent,…> would collapse to the
|
|
2408
|
+
* shared keys only). Used by the editor producer and the undo inverse. */
|
|
2409
|
+
type IntentBody = Intent extends infer T ? (T extends Intent ? Omit<T, "clientId" | "clientSeq" | "base"> : never) : never;
|
|
2410
|
+
|
|
2411
|
+
/**
|
|
2412
|
+
* How much of the document an applied intent disturbed — the input to
|
|
2413
|
+
* dirty-scoped reconciliation (perf B9/B10). Reconciling an edit used to cost
|
|
2414
|
+
* O(document) on every path (full model reparse + full id walk), so per-op
|
|
2415
|
+
* cost grew with the document; the scope lets the caller pay for THE EDIT.
|
|
2416
|
+
*
|
|
2417
|
+
* `doc` is the conservative default and means exactly today's behavior: full
|
|
2418
|
+
* refresh() + assignFromRoots(). Only intents whose blast radius is provably
|
|
2419
|
+
* one paragraph (or the two sides of a split) report a narrower scope; every
|
|
2420
|
+
* structural, document-level, or exotic intent keeps the document scope.
|
|
2421
|
+
*/
|
|
2422
|
+
type Scope = {
|
|
2423
|
+
kind: "doc";
|
|
2424
|
+
}
|
|
2425
|
+
/** Only these paragraphs' contents changed. */
|
|
2426
|
+
| {
|
|
2427
|
+
kind: "block";
|
|
2428
|
+
blocks: XmlElement[];
|
|
2429
|
+
}
|
|
2430
|
+
/** `before` was split; `after` is the new sibling that follows it. */
|
|
2431
|
+
| {
|
|
2432
|
+
kind: "split";
|
|
2433
|
+
before: XmlElement;
|
|
2434
|
+
after: XmlElement;
|
|
2435
|
+
};
|
|
2436
|
+
|
|
2437
|
+
/**
|
|
2438
|
+
* Wire protocol between a collab client and the server host. Transport-
|
|
2439
|
+
* agnostic: the hub speaks these messages; a WebSocket (or in-memory test)
|
|
2440
|
+
* adapter serializes them. Kept deliberately small (plan doc 06).
|
|
2441
|
+
*/
|
|
2442
|
+
/** One highlighted stretch of a remote participant's selection: a half-open
|
|
2443
|
+
* `[start, end)` inside ONE run, in the same WIRE offset basis carets and
|
|
2444
|
+
* suggestRevision use (cumulative within the run, inline separators counting
|
|
2445
|
+
* one unit each — see core `EncodedCaret`). The sender emits one entry per
|
|
2446
|
+
* selection segment, and a segment never straddles a w:t, so a range stays
|
|
2447
|
+
* inside a single run by construction. */
|
|
2448
|
+
interface PresenceRange {
|
|
2449
|
+
blockId: number;
|
|
2450
|
+
runId: number;
|
|
2451
|
+
start: number;
|
|
2452
|
+
end: number;
|
|
2453
|
+
}
|
|
2454
|
+
/** An ephemeral cursor/selection position on the presence channel: stable-id
|
|
2455
|
+
* addresses (plan doc 03). Never logged, never persisted. */
|
|
2456
|
+
interface PresencePosition {
|
|
2457
|
+
anchor: {
|
|
2458
|
+
blockId: number;
|
|
2459
|
+
runId: number;
|
|
2460
|
+
offset: number;
|
|
2461
|
+
};
|
|
2462
|
+
focus?: {
|
|
2463
|
+
blockId: number;
|
|
2464
|
+
runId: number;
|
|
2465
|
+
offset: number;
|
|
2466
|
+
};
|
|
2467
|
+
/** Selection highlight (Google-Docs style): the stretches the participant
|
|
2468
|
+
* has selected, drawn in their presence color under the remote caret.
|
|
2469
|
+
* OPTIONAL and additive — a payload from an older client carries only the
|
|
2470
|
+
* anchor and still renders a caret. Absent/empty ⇒ no selection. */
|
|
2471
|
+
ranges?: PresenceRange[];
|
|
2472
|
+
}
|
|
2473
|
+
|
|
2474
|
+
interface AgentEditCapability {
|
|
2475
|
+
category: "text" | "paragraph" | "review" | "table" | "insert" | "drawing" | "math" | "document";
|
|
2476
|
+
description: string;
|
|
2477
|
+
required: string[];
|
|
2478
|
+
optional?: string[];
|
|
2479
|
+
}
|
|
2480
|
+
/**
|
|
2481
|
+
* The agent-facing coverage map for the complete canonical edit surface.
|
|
2482
|
+
* Record<Intent["kind"], ...> makes a new intent fail the agent build until
|
|
2483
|
+
* its tool contract is declared here.
|
|
2484
|
+
*/
|
|
2485
|
+
declare const AGENT_EDIT_CAPABILITIES: Record<Intent["kind"], AgentEditCapability>;
|
|
2486
|
+
type JsonSchema$1 = Record<string, unknown>;
|
|
2487
|
+
declare function agentOperationSchema(kind: Intent["kind"]): JsonSchema$1;
|
|
2488
|
+
declare function validateAgentOperationShape(input: unknown): string | null;
|
|
2489
|
+
declare function agentCapabilities(category?: AgentEditCapability["category"], requestedKind?: Intent["kind"]): Array<AgentEditCapability & {
|
|
2490
|
+
kind: Intent["kind"];
|
|
2491
|
+
inputSchema: Record<string, unknown>;
|
|
2492
|
+
}>;
|
|
2493
|
+
|
|
2494
|
+
type AgentReference = string;
|
|
2495
|
+
interface AgentCursor {
|
|
2496
|
+
value: string;
|
|
2497
|
+
}
|
|
2498
|
+
interface AgentOverview {
|
|
2499
|
+
revision: string;
|
|
2500
|
+
sections: number;
|
|
2501
|
+
mirrorMargins: boolean;
|
|
2502
|
+
sectionLayouts: AgentSectionLayout[];
|
|
2503
|
+
stories: Array<{
|
|
2504
|
+
id: string;
|
|
2505
|
+
kind: "body" | "header" | "footer" | "footnote" | "endnote" | "textbox";
|
|
2506
|
+
blocks: number;
|
|
2507
|
+
}>;
|
|
2508
|
+
blocks: {
|
|
2509
|
+
paragraphs: number;
|
|
2510
|
+
tables: number;
|
|
2511
|
+
};
|
|
2512
|
+
characters: number;
|
|
2513
|
+
comments: number;
|
|
2514
|
+
components: Record<string, number>;
|
|
2515
|
+
objectCounts: Record<string, number>;
|
|
2516
|
+
outline: OutlineEntry[];
|
|
2517
|
+
}
|
|
2518
|
+
interface AgentSectionLayout {
|
|
2519
|
+
index: number;
|
|
2520
|
+
page: {
|
|
2521
|
+
width: number;
|
|
2522
|
+
height: number;
|
|
2523
|
+
};
|
|
2524
|
+
margins: {
|
|
2525
|
+
top: number;
|
|
2526
|
+
right: number;
|
|
2527
|
+
bottom: number;
|
|
2528
|
+
left: number;
|
|
2529
|
+
};
|
|
2530
|
+
headerDistance: number;
|
|
2531
|
+
footerDistance: number;
|
|
2532
|
+
gutter: number;
|
|
2533
|
+
columns: {
|
|
2534
|
+
count: number;
|
|
2535
|
+
space: number;
|
|
2536
|
+
widths?: number[];
|
|
2537
|
+
spaces?: number[];
|
|
2538
|
+
separator?: boolean;
|
|
2539
|
+
};
|
|
2540
|
+
titlePage: boolean;
|
|
2541
|
+
pageNumberStart?: number;
|
|
2542
|
+
pageNumberFormat?: string;
|
|
2543
|
+
breakType?: "nextPage" | "continuous" | "evenPage" | "oddPage" | "nextColumn";
|
|
2544
|
+
verticalAlignment?: "top" | "center" | "both" | "bottom";
|
|
2545
|
+
pageBorders?: AgentPageBorders;
|
|
2546
|
+
lineNumbering?: {
|
|
2547
|
+
countBy: number;
|
|
2548
|
+
start: number;
|
|
2549
|
+
distance: number;
|
|
2550
|
+
restart: "continuous" | "newPage" | "newSection";
|
|
2551
|
+
};
|
|
2552
|
+
}
|
|
2553
|
+
interface AgentBorder {
|
|
2554
|
+
style: "none" | "single" | "double" | "dotted" | "dashed" | "thick" | "wave" | "dotDash" | "dotDotDash" | "thinThickSmallGap" | "triple";
|
|
2555
|
+
width: number;
|
|
2556
|
+
color: string;
|
|
2557
|
+
space: number;
|
|
2558
|
+
rawWidth?: number;
|
|
2559
|
+
}
|
|
2560
|
+
interface AgentPageBorders {
|
|
2561
|
+
top?: AgentBorder;
|
|
2562
|
+
bottom?: AgentBorder;
|
|
2563
|
+
left?: AgentBorder;
|
|
2564
|
+
right?: AgentBorder;
|
|
2565
|
+
offsetFrom: "text" | "page";
|
|
2566
|
+
}
|
|
2567
|
+
interface OutlineEntry {
|
|
2568
|
+
ref: AgentReference;
|
|
2569
|
+
level: number;
|
|
2570
|
+
text: string;
|
|
2571
|
+
styleId?: string;
|
|
2572
|
+
}
|
|
2573
|
+
interface AgentRun {
|
|
2574
|
+
ref: AgentReference;
|
|
2575
|
+
editable: boolean;
|
|
2576
|
+
paragraphStart: number;
|
|
2577
|
+
paragraphEnd: number;
|
|
2578
|
+
wireLength: number;
|
|
2579
|
+
text: string;
|
|
2580
|
+
formatting: Record<string, unknown>;
|
|
2581
|
+
hyperlink?: {
|
|
2582
|
+
href?: string;
|
|
2583
|
+
anchor?: string;
|
|
2584
|
+
};
|
|
2585
|
+
components: AgentComponentSummary[];
|
|
2586
|
+
}
|
|
2587
|
+
interface AgentParagraph {
|
|
2588
|
+
type: "paragraph";
|
|
2589
|
+
ref: AgentReference;
|
|
2590
|
+
editable: boolean;
|
|
2591
|
+
story: string;
|
|
2592
|
+
styleId?: string;
|
|
2593
|
+
outlineLevel?: number;
|
|
2594
|
+
alignment?: string;
|
|
2595
|
+
list?: {
|
|
2596
|
+
numId: number;
|
|
2597
|
+
level: number;
|
|
2598
|
+
} | null;
|
|
2599
|
+
text: string;
|
|
2600
|
+
textRange: {
|
|
2601
|
+
start: number;
|
|
2602
|
+
end: number;
|
|
2603
|
+
total: number;
|
|
2604
|
+
};
|
|
2605
|
+
runs: AgentRun[];
|
|
2606
|
+
bookmarks: string[];
|
|
2607
|
+
}
|
|
2608
|
+
interface AgentTable {
|
|
2609
|
+
type: "table";
|
|
2610
|
+
ref: AgentReference;
|
|
2611
|
+
editable: boolean;
|
|
2612
|
+
story: string;
|
|
2613
|
+
rows: number;
|
|
2614
|
+
columns: number;
|
|
2615
|
+
styleId?: string;
|
|
2616
|
+
floating: boolean;
|
|
2617
|
+
cells: Array<{
|
|
2618
|
+
row: number;
|
|
2619
|
+
column: number;
|
|
2620
|
+
blocks: AgentReference[];
|
|
2621
|
+
}>;
|
|
2622
|
+
}
|
|
2623
|
+
type AgentBlock = AgentParagraph | AgentTable;
|
|
2624
|
+
interface AgentReadResult {
|
|
2625
|
+
revision: string;
|
|
2626
|
+
story: string;
|
|
2627
|
+
blocks: AgentBlock[];
|
|
2628
|
+
next?: AgentCursor;
|
|
2629
|
+
truncated: boolean;
|
|
2630
|
+
}
|
|
2631
|
+
interface AgentContextRun {
|
|
2632
|
+
ref: AgentReference;
|
|
2633
|
+
start: number;
|
|
2634
|
+
end: number;
|
|
2635
|
+
wireLength?: number;
|
|
2636
|
+
}
|
|
2637
|
+
interface AgentContextParagraph {
|
|
2638
|
+
type: "paragraph";
|
|
2639
|
+
ref: AgentReference;
|
|
2640
|
+
text: string;
|
|
2641
|
+
range?: {
|
|
2642
|
+
start: number;
|
|
2643
|
+
end: number;
|
|
2644
|
+
total: number;
|
|
2645
|
+
};
|
|
2646
|
+
runs: AgentContextRun[];
|
|
2647
|
+
styleId?: string;
|
|
2648
|
+
outlineLevel?: number;
|
|
2649
|
+
list?: {
|
|
2650
|
+
numId: number;
|
|
2651
|
+
level: number;
|
|
2652
|
+
};
|
|
2653
|
+
bookmarks?: string[];
|
|
2654
|
+
objects?: AgentComponentSummary[];
|
|
2655
|
+
}
|
|
2656
|
+
interface AgentContextTable {
|
|
2657
|
+
type: "table";
|
|
2658
|
+
ref: AgentReference;
|
|
2659
|
+
rows: number;
|
|
2660
|
+
columns: number;
|
|
2661
|
+
}
|
|
2662
|
+
interface AgentContextStory {
|
|
2663
|
+
story: string;
|
|
2664
|
+
kind: "body" | "header" | "footer" | "footnote" | "endnote" | "textbox";
|
|
2665
|
+
blocks: Array<AgentContextParagraph | AgentContextTable>;
|
|
2666
|
+
next?: AgentCursor;
|
|
2667
|
+
}
|
|
2668
|
+
interface AgentContextResult {
|
|
2669
|
+
revision: string;
|
|
2670
|
+
contents: AgentContextStory[];
|
|
2671
|
+
truncated: boolean;
|
|
2672
|
+
remainingStories?: string[];
|
|
2673
|
+
}
|
|
2674
|
+
interface AgentSearchResult {
|
|
2675
|
+
revision: string;
|
|
2676
|
+
matches: Array<{
|
|
2677
|
+
blockRef: AgentReference;
|
|
2678
|
+
runRef: AgentReference;
|
|
2679
|
+
editable: boolean;
|
|
2680
|
+
start: number;
|
|
2681
|
+
end: number;
|
|
2682
|
+
excerpt: string;
|
|
2683
|
+
}>;
|
|
2684
|
+
truncated: boolean;
|
|
2685
|
+
}
|
|
2686
|
+
interface AgentComponentSummary {
|
|
2687
|
+
ref: AgentReference;
|
|
2688
|
+
editRef?: AgentReference;
|
|
2689
|
+
type: string;
|
|
2690
|
+
label?: string;
|
|
2691
|
+
}
|
|
2692
|
+
interface AgentObjectResult {
|
|
2693
|
+
revision: string;
|
|
2694
|
+
ref: AgentReference;
|
|
2695
|
+
editRef?: AgentReference;
|
|
2696
|
+
type: string;
|
|
2697
|
+
detail: Record<string, unknown>;
|
|
2698
|
+
}
|
|
2699
|
+
interface AgentAsset {
|
|
2700
|
+
ref: AgentReference;
|
|
2701
|
+
bytes: Uint8Array;
|
|
2702
|
+
mediaType: string;
|
|
2703
|
+
}
|
|
2704
|
+
interface SpatialBounds {
|
|
2705
|
+
x: number;
|
|
2706
|
+
y: number;
|
|
2707
|
+
width: number;
|
|
2708
|
+
height: number;
|
|
2709
|
+
}
|
|
2710
|
+
interface AgentSpatialObject {
|
|
2711
|
+
ref: AgentReference;
|
|
2712
|
+
editRef?: AgentReference;
|
|
2713
|
+
type: string;
|
|
2714
|
+
page: number;
|
|
2715
|
+
bounds: SpatialBounds;
|
|
2716
|
+
rotation?: number;
|
|
2717
|
+
layer: "behind-text" | "body" | "in-front-of-text";
|
|
2718
|
+
zOrder?: number;
|
|
2719
|
+
}
|
|
2720
|
+
interface AgentOverlap {
|
|
2721
|
+
objects: [AgentReference, AgentReference];
|
|
2722
|
+
overlapBounds: SpatialBounds;
|
|
2723
|
+
overlapArea: number;
|
|
2724
|
+
topObject?: AgentReference;
|
|
2725
|
+
}
|
|
2726
|
+
interface AgentSpatialResult {
|
|
2727
|
+
revision: string;
|
|
2728
|
+
layout: {
|
|
2729
|
+
quality: "exact" | "approximate";
|
|
2730
|
+
profile: string;
|
|
2731
|
+
};
|
|
2732
|
+
totalPages: number;
|
|
2733
|
+
pages: Array<{
|
|
2734
|
+
index: number;
|
|
2735
|
+
width: number;
|
|
2736
|
+
height: number;
|
|
2737
|
+
}>;
|
|
2738
|
+
objects: AgentSpatialObject[];
|
|
2739
|
+
overlaps: AgentOverlap[];
|
|
2740
|
+
}
|
|
2741
|
+
type AgentInspectRequest = {
|
|
2742
|
+
kind: "overview";
|
|
2743
|
+
} | {
|
|
2744
|
+
kind: "context";
|
|
2745
|
+
stories?: string[];
|
|
2746
|
+
maxBlocks?: number;
|
|
2747
|
+
maxCharacters?: number;
|
|
2748
|
+
include?: Array<"bookmarks" | "objects">;
|
|
2749
|
+
includeEmpty?: boolean;
|
|
2750
|
+
} | {
|
|
2751
|
+
kind: "read";
|
|
2752
|
+
story?: string;
|
|
2753
|
+
cursor?: AgentCursor;
|
|
2754
|
+
maxBlocks?: number;
|
|
2755
|
+
maxCharacters?: number;
|
|
2756
|
+
} | {
|
|
2757
|
+
kind: "search";
|
|
2758
|
+
query: string;
|
|
2759
|
+
maxResults?: number;
|
|
2760
|
+
} | {
|
|
2761
|
+
kind: "object";
|
|
2762
|
+
ref: AgentReference;
|
|
2763
|
+
} | {
|
|
2764
|
+
kind: "spatial";
|
|
2765
|
+
pages?: {
|
|
2766
|
+
start: number;
|
|
2767
|
+
count: number;
|
|
2768
|
+
};
|
|
2769
|
+
includeOverlaps?: boolean;
|
|
2770
|
+
};
|
|
2771
|
+
type AgentInspectResult = AgentOverview | AgentContextResult | AgentReadResult | AgentSearchResult | AgentObjectResult | AgentSpatialResult;
|
|
2772
|
+
type AgentOperation = Record<string, unknown> & {
|
|
2773
|
+
kind: string;
|
|
2774
|
+
};
|
|
2775
|
+
interface AgentEditRequest {
|
|
2776
|
+
revision: string;
|
|
2777
|
+
operations: AgentOperation[];
|
|
2778
|
+
}
|
|
2779
|
+
interface AgentEditResult {
|
|
2780
|
+
revision: string;
|
|
2781
|
+
status: "applied" | "submitted";
|
|
2782
|
+
operations: string[];
|
|
2783
|
+
connection?: "local" | "live" | "offline" | "reconnecting";
|
|
2784
|
+
}
|
|
2785
|
+
interface AgentComposeRun {
|
|
2786
|
+
text: string;
|
|
2787
|
+
bold?: boolean;
|
|
2788
|
+
italic?: boolean;
|
|
2789
|
+
underline?: boolean;
|
|
2790
|
+
color?: string;
|
|
2791
|
+
highlight?: string;
|
|
2792
|
+
fontSizePt?: number;
|
|
2793
|
+
fontFamily?: string;
|
|
2794
|
+
}
|
|
2795
|
+
interface AgentComposeCell {
|
|
2796
|
+
text?: string;
|
|
2797
|
+
runs?: AgentComposeRun[];
|
|
2798
|
+
fill?: string;
|
|
2799
|
+
align?: "left" | "center" | "right";
|
|
2800
|
+
verticalAlign?: "top" | "center" | "bottom";
|
|
2801
|
+
}
|
|
2802
|
+
interface AgentComposeTextStyle {
|
|
2803
|
+
bold?: boolean;
|
|
2804
|
+
italic?: boolean;
|
|
2805
|
+
underline?: boolean;
|
|
2806
|
+
color?: string;
|
|
2807
|
+
fontSizePt?: number;
|
|
2808
|
+
fontFamily?: string;
|
|
2809
|
+
align?: "left" | "center" | "right";
|
|
2810
|
+
}
|
|
2811
|
+
type AgentComposeBlock = {
|
|
2812
|
+
type: "paragraph";
|
|
2813
|
+
text?: string;
|
|
2814
|
+
runs?: AgentComposeRun[];
|
|
2815
|
+
styleId?: "Normal" | "Title" | "Subtitle" | "Heading1" | "Heading2" | "Heading3";
|
|
2816
|
+
align?: "left" | "center" | "right" | "both";
|
|
2817
|
+
spacing?: {
|
|
2818
|
+
beforePt?: number;
|
|
2819
|
+
afterPt?: number;
|
|
2820
|
+
lineMultiple?: number;
|
|
2821
|
+
};
|
|
2822
|
+
list?: "bullet" | "number";
|
|
2823
|
+
} | {
|
|
2824
|
+
type: "heading";
|
|
2825
|
+
level: 1 | 2 | 3;
|
|
2826
|
+
text: string;
|
|
2827
|
+
} | {
|
|
2828
|
+
type: "table";
|
|
2829
|
+
rows: Array<Array<string | AgentComposeCell>>;
|
|
2830
|
+
headerRows?: number;
|
|
2831
|
+
headerFill?: string;
|
|
2832
|
+
headerTextColor?: string;
|
|
2833
|
+
columnWidths?: number[];
|
|
2834
|
+
} | {
|
|
2835
|
+
type: "equation";
|
|
2836
|
+
mathText: string;
|
|
2837
|
+
align?: "left" | "center" | "right";
|
|
2838
|
+
} | {
|
|
2839
|
+
type: "chart";
|
|
2840
|
+
chart: {
|
|
2841
|
+
type: "column" | "bar" | "line" | "pie";
|
|
2842
|
+
title?: string;
|
|
2843
|
+
categories: string[];
|
|
2844
|
+
series: Array<{
|
|
2845
|
+
name: string;
|
|
2846
|
+
values: number[];
|
|
2847
|
+
}>;
|
|
2848
|
+
};
|
|
2849
|
+
widthPx?: number;
|
|
2850
|
+
heightPx?: number;
|
|
2851
|
+
align?: "left" | "center" | "right";
|
|
2852
|
+
} | {
|
|
2853
|
+
type: "smartArt";
|
|
2854
|
+
smartArt: {
|
|
2855
|
+
layout: "process" | "cycle" | "hierarchy" | "list";
|
|
2856
|
+
items: string[];
|
|
2857
|
+
};
|
|
2858
|
+
widthPx?: number;
|
|
2859
|
+
heightPx?: number;
|
|
2860
|
+
align?: "left" | "center" | "right";
|
|
2861
|
+
} | {
|
|
2862
|
+
type: "image";
|
|
2863
|
+
assetRef: string;
|
|
2864
|
+
widthPx: number;
|
|
2865
|
+
heightPx: number;
|
|
2866
|
+
alt?: string;
|
|
2867
|
+
align?: "left" | "center" | "right";
|
|
2868
|
+
wrap?: "inline" | "square" | "topAndBottom" | "none" | "behind";
|
|
2869
|
+
position?: {
|
|
2870
|
+
xPx: number;
|
|
2871
|
+
yPx: number;
|
|
2872
|
+
};
|
|
2873
|
+
} | {
|
|
2874
|
+
type: "shape";
|
|
2875
|
+
preset: "line" | "verticalLine" | "rectangle" | "roundedRectangle" | "ellipse" | "diamond" | "textBox";
|
|
2876
|
+
text?: string;
|
|
2877
|
+
textStyle?: AgentComposeTextStyle;
|
|
2878
|
+
widthPx?: number;
|
|
2879
|
+
heightPx?: number;
|
|
2880
|
+
position?: {
|
|
2881
|
+
xPx: number;
|
|
2882
|
+
yPx: number;
|
|
2883
|
+
};
|
|
2884
|
+
fill?: string | null;
|
|
2885
|
+
line?: {
|
|
2886
|
+
color: string;
|
|
2887
|
+
widthPx: number;
|
|
2888
|
+
dash: "solid" | "dashed" | "dotted";
|
|
2889
|
+
} | null;
|
|
2890
|
+
wrap?: "inline" | "square" | "topAndBottom" | "none" | "behind";
|
|
2891
|
+
order?: "front" | "back";
|
|
2892
|
+
} | {
|
|
2893
|
+
type: "wordArt";
|
|
2894
|
+
text: string;
|
|
2895
|
+
preset: "plain" | "archUp" | "archDown" | "wave" | "chevron";
|
|
2896
|
+
widthPx?: number;
|
|
2897
|
+
heightPx?: number;
|
|
2898
|
+
position?: {
|
|
2899
|
+
xPx: number;
|
|
2900
|
+
yPx: number;
|
|
2901
|
+
};
|
|
2902
|
+
rotation?: number;
|
|
2903
|
+
fill?: string;
|
|
2904
|
+
opacity?: number;
|
|
2905
|
+
wrap?: "inline" | "square" | "topAndBottom" | "none" | "behind";
|
|
2906
|
+
order?: "front" | "back";
|
|
2907
|
+
} | {
|
|
2908
|
+
type: "pageNumber";
|
|
2909
|
+
fieldKind: "page" | "pageOfTotal";
|
|
2910
|
+
align?: "left" | "center" | "right";
|
|
2911
|
+
color?: string;
|
|
2912
|
+
fontSizePt?: number;
|
|
2913
|
+
fontFamily?: string;
|
|
2914
|
+
bold?: boolean;
|
|
2915
|
+
} | {
|
|
2916
|
+
type: "pageBreak";
|
|
2917
|
+
};
|
|
2918
|
+
interface AgentComposeRequest {
|
|
2919
|
+
revision: string;
|
|
2920
|
+
body: AgentComposeBlock[];
|
|
2921
|
+
header?: AgentComposeBlock[];
|
|
2922
|
+
footer?: AgentComposeBlock[];
|
|
2923
|
+
firstHeader?: AgentComposeBlock[];
|
|
2924
|
+
firstFooter?: AgentComposeBlock[];
|
|
2925
|
+
page?: {
|
|
2926
|
+
margins?: {
|
|
2927
|
+
top?: number;
|
|
2928
|
+
right?: number;
|
|
2929
|
+
bottom?: number;
|
|
2930
|
+
left?: number;
|
|
2931
|
+
};
|
|
2932
|
+
size?: {
|
|
2933
|
+
width: number;
|
|
2934
|
+
height: number;
|
|
2935
|
+
};
|
|
2936
|
+
orientation?: "portrait" | "landscape";
|
|
2937
|
+
columns?: number;
|
|
2938
|
+
columnSeparator?: boolean;
|
|
2939
|
+
mirrorMargins?: boolean;
|
|
2940
|
+
};
|
|
2941
|
+
}
|
|
2942
|
+
interface AgentComposeResult {
|
|
2943
|
+
revision: string;
|
|
2944
|
+
status: "applied";
|
|
2945
|
+
blocks: number;
|
|
2946
|
+
components: number;
|
|
2947
|
+
overview: AgentOverview;
|
|
2948
|
+
createdObjects: AgentComponentSummary[];
|
|
2949
|
+
createdObjectsTruncated: boolean;
|
|
2950
|
+
}
|
|
2951
|
+
interface AgentCollaborativeTarget {
|
|
2952
|
+
getDocument(): DocxDocument | null;
|
|
2953
|
+
getRevision(): string | number;
|
|
2954
|
+
allocateIds(count: number): number[];
|
|
2955
|
+
submit(operation: IntentBody): void | Promise<void>;
|
|
2956
|
+
setPresence?(position: PresencePosition | null): void;
|
|
2957
|
+
uploadMedia?(bytes: Uint8Array): Promise<{
|
|
2958
|
+
blobSha: string;
|
|
2959
|
+
bytesLen: number;
|
|
2960
|
+
iv?: string;
|
|
2961
|
+
} | null>;
|
|
2962
|
+
getConnectionState?(): "local" | "live" | "offline" | "reconnecting";
|
|
2963
|
+
}
|
|
2964
|
+
interface AgentProvenance {
|
|
2965
|
+
author: string;
|
|
2966
|
+
now?: () => string;
|
|
2967
|
+
nextId?: () => string;
|
|
2968
|
+
}
|
|
2969
|
+
interface AgentTool {
|
|
2970
|
+
name: string;
|
|
2971
|
+
description: string;
|
|
2972
|
+
inputSchema: Record<string, unknown>;
|
|
2973
|
+
execute(input: unknown): Promise<unknown>;
|
|
2974
|
+
}
|
|
2975
|
+
|
|
2976
|
+
declare class AgentDocument {
|
|
2977
|
+
private localDoc;
|
|
2978
|
+
private localRevision;
|
|
2979
|
+
private readonly target;
|
|
2980
|
+
private readonly provenance;
|
|
2981
|
+
private readonly addedAssets;
|
|
2982
|
+
private assetCounter;
|
|
2983
|
+
private composeAvailable;
|
|
2984
|
+
private readonly listeners;
|
|
2985
|
+
private readonly inspectedTargets;
|
|
2986
|
+
private constructor();
|
|
2987
|
+
static load(bytes: ArrayBuffer | Uint8Array, options?: {
|
|
2988
|
+
provenance?: AgentProvenance;
|
|
2989
|
+
}): AgentDocument;
|
|
2990
|
+
static create(options?: {
|
|
2991
|
+
provenance?: AgentProvenance;
|
|
2992
|
+
}): AgentDocument;
|
|
2993
|
+
static connect(target: AgentCollaborativeTarget, options?: {
|
|
2994
|
+
provenance?: AgentProvenance;
|
|
2995
|
+
}): AgentDocument;
|
|
2996
|
+
get revision(): string;
|
|
2997
|
+
get document(): DocxDocument;
|
|
2998
|
+
subscribe(listener: (document: DocxDocument, revision: string) => void): () => void;
|
|
2999
|
+
addAsset(bytes: Uint8Array, mediaType: string): string;
|
|
3000
|
+
private inspector;
|
|
3001
|
+
asset(ref: string): AgentAsset;
|
|
3002
|
+
inspect(request: AgentInspectRequest): AgentInspectResult;
|
|
3003
|
+
private recordInspection;
|
|
3004
|
+
private revisionMatchesEdit;
|
|
3005
|
+
capabilities(category?: AgentEditCapability["category"], kind?: Intent["kind"]): ReturnType<typeof agentCapabilities>;
|
|
3006
|
+
compose(request: AgentComposeRequest): Promise<AgentComposeResult>;
|
|
3007
|
+
edit(request: AgentEditRequest): Promise<AgentEditResult>;
|
|
3008
|
+
private editLocal;
|
|
3009
|
+
private editCollaborative;
|
|
3010
|
+
save(): Uint8Array;
|
|
3011
|
+
tools(): AgentTool[];
|
|
3012
|
+
}
|
|
3013
|
+
interface CollabSessionLike {
|
|
3014
|
+
doc: DocxDocument | null;
|
|
3015
|
+
version: number;
|
|
3016
|
+
submitOp(operation: IntentBody): void;
|
|
3017
|
+
setPresence?(position: PresencePosition | null): void;
|
|
3018
|
+
allocIds(count: number): number[];
|
|
3019
|
+
uploadMedia?(bytes: Uint8Array): Promise<{
|
|
3020
|
+
blobSha: string;
|
|
3021
|
+
bytesLen: number;
|
|
3022
|
+
iv?: string;
|
|
3023
|
+
} | null>;
|
|
3024
|
+
connection: "live" | "reconnecting" | "lost";
|
|
3025
|
+
}
|
|
3026
|
+
/** Adapt the existing browser CollabSession without adding a React dependency.
|
|
3027
|
+
* The accessor must return the latest hook value after each render. */
|
|
3028
|
+
declare function collaborativeAgentTarget(getSession: () => CollabSessionLike): AgentCollaborativeTarget;
|
|
3029
|
+
|
|
3030
|
+
/**
|
|
3031
|
+
* A canonical document session for one process. It lets a browser editor and
|
|
3032
|
+
* an AgentDocument share one DocxDocument without a server or a DOM dependency.
|
|
3033
|
+
*/
|
|
3034
|
+
declare class LocalDocumentSession implements AgentCollaborativeTarget {
|
|
3035
|
+
readonly doc: DocxDocument;
|
|
3036
|
+
private revision;
|
|
3037
|
+
private renderRevision;
|
|
3038
|
+
private clientSequence;
|
|
3039
|
+
private nextId;
|
|
3040
|
+
private dirtyScope;
|
|
3041
|
+
private readonly listeners;
|
|
3042
|
+
private readonly uploadedMedia;
|
|
3043
|
+
constructor(source: ArrayBuffer | Uint8Array | DocxDocument);
|
|
3044
|
+
get version(): number;
|
|
3045
|
+
get renderSignal(): number;
|
|
3046
|
+
getDocument(): DocxDocument;
|
|
3047
|
+
getRevision(): number;
|
|
3048
|
+
getConnectionState(): "local";
|
|
3049
|
+
allocateIds(count: number): number[];
|
|
3050
|
+
allocIds: (count: number) => number[];
|
|
3051
|
+
subscribe(listener: () => void): () => void;
|
|
3052
|
+
takeRenderScope: () => Scope | null;
|
|
3053
|
+
submit: (operation: IntentBody) => void;
|
|
3054
|
+
submitOp: (operation: IntentBody) => void;
|
|
3055
|
+
/** Record an operation that DocxView already applied to this same object. */
|
|
3056
|
+
submitPreApplied: (operation: IntentBody) => void;
|
|
3057
|
+
uploadMedia(bytes: Uint8Array): Promise<{
|
|
3058
|
+
blobSha: string;
|
|
3059
|
+
bytesLen: number;
|
|
3060
|
+
}>;
|
|
3061
|
+
private fullIntent;
|
|
3062
|
+
private installUploadedImage;
|
|
3063
|
+
}
|
|
3064
|
+
interface LocalDocumentViewBinding {
|
|
3065
|
+
subscribe(listener: () => void): () => void;
|
|
3066
|
+
getSnapshot(): number;
|
|
3067
|
+
doc: DocxDocument;
|
|
3068
|
+
submit(operation: IntentBody): void;
|
|
3069
|
+
submitOp(operation: IntentBody): void;
|
|
3070
|
+
allocIds(count: number): number[];
|
|
3071
|
+
uploadMedia(bytes: Uint8Array): Promise<{
|
|
3072
|
+
blobSha: string;
|
|
3073
|
+
bytesLen: number;
|
|
3074
|
+
}>;
|
|
3075
|
+
takeRenderScope(): {
|
|
3076
|
+
kind: "doc";
|
|
3077
|
+
} | {
|
|
3078
|
+
kind: "block";
|
|
3079
|
+
blocks: XmlElement[];
|
|
3080
|
+
} | {
|
|
3081
|
+
kind: "split";
|
|
3082
|
+
before: XmlElement;
|
|
3083
|
+
after: XmlElement;
|
|
3084
|
+
} | null;
|
|
3085
|
+
}
|
|
3086
|
+
declare function localDocumentViewBinding(session: LocalDocumentSession): LocalDocumentViewBinding;
|
|
3087
|
+
|
|
3088
|
+
type JsonSchema = Record<string, unknown>;
|
|
3089
|
+
declare const AGENT_COMPOSE_SCHEMA: JsonSchema;
|
|
3090
|
+
declare function validateAgentComposeRequest(input: unknown): string | null;
|
|
3091
|
+
|
|
3092
|
+
export { AGENT_COMPOSE_SCHEMA, AGENT_EDIT_CAPABILITIES, type AgentAsset, type AgentBlock, type AgentBorder, type AgentCollaborativeTarget, type AgentComponentSummary, type AgentComposeBlock, type AgentComposeCell, type AgentComposeRequest, type AgentComposeResult, type AgentComposeRun, type AgentComposeTextStyle, type AgentContextParagraph, type AgentContextResult, type AgentContextRun, type AgentContextStory, type AgentContextTable, type AgentCursor, AgentDocument, type AgentEditCapability, type AgentEditRequest, type AgentEditResult, type AgentInspectRequest, type AgentInspectResult, type AgentObjectResult, type AgentOperation, type AgentOverlap, type AgentOverview, type AgentPageBorders, type AgentParagraph, type AgentProvenance, type AgentReadResult, type AgentReference, type AgentRun, type AgentSearchResult, type AgentSectionLayout, type AgentSpatialObject, type AgentSpatialResult, type AgentTable, type AgentTool, LocalDocumentSession, type LocalDocumentViewBinding, type OutlineEntry, type SpatialBounds, agentCapabilities, agentOperationSchema, collaborativeAgentTarget, localDocumentViewBinding, validateAgentComposeRequest, validateAgentOperationShape };
|