@beyondwork/docx-react-component 1.0.102 → 1.0.103

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.
Files changed (33) hide show
  1. package/package.json +1 -1
  2. package/src/core/commands/formatting-commands.ts +8 -7
  3. package/src/core/commands/paragraph-layout-commands.ts +11 -10
  4. package/src/core/commands/section-layout-commands.ts +7 -6
  5. package/src/core/commands/style-commands.ts +3 -2
  6. package/src/io/normalize/normalize-text.ts +6 -5
  7. package/src/io/ooxml/parse-anchor.ts +15 -15
  8. package/src/io/ooxml/parse-drawing.ts +5 -5
  9. package/src/io/ooxml/parse-fields.ts +16 -15
  10. package/src/io/ooxml/parse-font-table.ts +2 -1
  11. package/src/io/ooxml/parse-footnotes.ts +3 -2
  12. package/src/io/ooxml/parse-headers-footers.ts +7 -6
  13. package/src/io/ooxml/parse-main-document.ts +41 -40
  14. package/src/io/ooxml/parse-numbering.ts +3 -2
  15. package/src/io/ooxml/parse-object.ts +6 -6
  16. package/src/io/ooxml/parse-paragraph-formatting.ts +12 -11
  17. package/src/io/ooxml/parse-picture.ts +16 -16
  18. package/src/io/ooxml/parse-run-formatting.ts +11 -10
  19. package/src/io/ooxml/parse-settings.ts +2 -1
  20. package/src/io/ooxml/parse-shapes.ts +18 -17
  21. package/src/io/ooxml/parse-styles.ts +16 -16
  22. package/src/io/ooxml/parse-theme.ts +5 -4
  23. package/src/model/canonical-document.ts +835 -833
  24. package/src/runtime/formatting/document-lookup.ts +3 -2
  25. package/src/runtime/formatting/formatting-context.ts +66 -25
  26. package/src/runtime/formatting/index.ts +18 -0
  27. package/src/runtime/formatting/layout-inputs.ts +256 -0
  28. package/src/runtime/formatting/numbering/geometry.ts +13 -12
  29. package/src/runtime/formatting/style-cascade.ts +2 -1
  30. package/src/runtime/formatting/table-style-resolver.ts +8 -7
  31. package/src/runtime/surface-projection.ts +31 -36
  32. package/src/session/import/normalize.ts +2 -1
  33. package/src/session/import/source-package-evidence.ts +612 -1
@@ -105,7 +105,7 @@ export interface CanonicalDocument {
105
105
  */
106
106
  export interface CanonicalDocumentFragment {
107
107
  /** Block-level children of the fragment, in document order. */
108
- readonly blocks: ReadonlyArray<BlockNode>;
108
+ readonly blocks: BlockNode[];
109
109
  }
110
110
 
111
111
  /**
@@ -138,18 +138,20 @@ export type MutableCanonicalDocumentFragment = Mutable<CanonicalDocumentFragment
138
138
  * Never cast a value received as a parameter. Only cast values you just
139
139
  * created via object literal, spread, `structuredClone`, or `createCanonicalDocument`.
140
140
  *
141
- * **Shallow only.** `Mutable<T>` strips `readonly` at the top level of `T`;
142
- * nested `ReadonlyArray<…>`, `Readonly<…>`, and inner `readonly` modifiers
143
- * declared inside referenced types are preserved. For example,
144
- * `Mutable<CanonicalDocument>` does NOT make `draft.content.children`
145
- * mutable `content` is `DocumentRootNode`, whose `children` field is
146
- * declared as it is in the source type. If you need to mutate nested
147
- * structure, build the nested value first (also as a `Mutable<…>` of the
148
- * nested type) and assign it onto the draft as a complete replacement.
149
- * Deep-readonly propagation across nested catalogs/stores/nodes is a
150
- * deferred D1 follow-up (see `docs/plans/refactor/02-canonical-document-deferred.md`).
141
+ * `Mutable<T>` strips readonly recursively, including `…[]`,
142
+ * `Readonly<…>`, and inner readonly modifiers declared inside referenced
143
+ * types. That is intentional for D1: parser/runtime producers can build a
144
+ * fully local draft with normal assignment and array operations, then return
145
+ * it widened to the readonly canonical type at the function boundary.
151
146
  */
152
- export type Mutable<T> = { -readonly [K in keyof T]: T[K] };
147
+ export type Mutable<T> =
148
+ T extends (...args: infer Args) => infer Return
149
+ ? (...args: Args) => Return
150
+ : T extends (infer Item)[]
151
+ ? Mutable<Item>[]
152
+ : T extends object
153
+ ? { -readonly [K in keyof T]: Mutable<T[K]> }
154
+ : T;
153
155
 
154
156
  /**
155
157
  * Draft-only mutable view of `CanonicalDocument`. Equivalent to
@@ -186,92 +188,92 @@ export type MutableCanonicalFontTable = Mutable<CanonicalFontTable>;
186
188
 
187
189
 
188
190
  export interface DocumentMetadata {
189
- title?: string;
190
- subject?: string;
191
- description?: string;
192
- creator?: string;
193
- language?: string;
194
- keywords?: string[];
195
- category?: string;
196
- lastModifiedBy?: string;
197
- contentStatus?: string;
198
- revision?: string;
199
- version?: string;
200
- createdUtc?: string;
201
- modifiedUtc?: string;
202
- importMode?: string;
203
- appProperties?: DocumentAppProperties;
204
- customProperties: Record<string, string>;
191
+ readonly title?: string;
192
+ readonly subject?: string;
193
+ readonly description?: string;
194
+ readonly creator?: string;
195
+ readonly language?: string;
196
+ readonly keywords?: string[];
197
+ readonly category?: string;
198
+ readonly lastModifiedBy?: string;
199
+ readonly contentStatus?: string;
200
+ readonly revision?: string;
201
+ readonly version?: string;
202
+ readonly createdUtc?: string;
203
+ readonly modifiedUtc?: string;
204
+ readonly importMode?: string;
205
+ readonly appProperties?: DocumentAppProperties;
206
+ readonly customProperties: Record<string, string>;
205
207
  }
206
208
 
207
209
  export interface DocumentAppProperties {
208
- application?: string;
209
- appVersion?: string;
210
- template?: string;
211
- pages?: number;
212
- words?: number;
213
- characters?: number;
214
- charactersWithSpaces?: number;
215
- totalTime?: number;
216
- company?: string;
217
- manager?: string;
218
- docSecurity?: number;
210
+ readonly application?: string;
211
+ readonly appVersion?: string;
212
+ readonly template?: string;
213
+ readonly pages?: number;
214
+ readonly words?: number;
215
+ readonly characters?: number;
216
+ readonly charactersWithSpaces?: number;
217
+ readonly totalTime?: number;
218
+ readonly company?: string;
219
+ readonly manager?: string;
220
+ readonly docSecurity?: number;
219
221
  }
220
222
 
221
223
  export interface StylesCatalog {
222
- paragraphs: Record<string, ParagraphStyleDefinition>;
223
- characters: Record<string, CharacterStyleDefinition>;
224
- tables: Record<string, TableStyleDefinition>;
224
+ readonly paragraphs: Record<string, ParagraphStyleDefinition>;
225
+ readonly characters: Record<string, CharacterStyleDefinition>;
226
+ readonly tables: Record<string, TableStyleDefinition>;
225
227
  /**
226
228
  * `w:type="numbering"` styles — preserve-only. Word emits these for
227
229
  * style-linked list families (List Bullet, List Number). Canonical
228
230
  * consumers do not apply numbering via these styles; they survive
229
231
  * only for round-trip fidelity.
230
232
  */
231
- numberingStyles?: Record<string, NumberingStyleDefinition>;
232
- latentStyles?: Record<string, LatentStyleDefinition>;
233
- fromPackage?: boolean;
234
- docDefaults?: DocumentDefaults;
233
+ readonly numberingStyles?: Record<string, NumberingStyleDefinition>;
234
+ readonly latentStyles?: Record<string, LatentStyleDefinition>;
235
+ readonly fromPackage?: boolean;
236
+ readonly docDefaults?: DocumentDefaults;
235
237
  }
236
238
 
237
239
  /** A `<w:style w:type="numbering">` entry. Preserve-only. */
238
240
  export interface NumberingStyleDefinition {
239
- styleId: string;
240
- displayName: string;
241
- kind: "numbering";
242
- isDefault: boolean;
243
- basedOn?: string;
244
- aliases?: string[];
241
+ readonly styleId: string;
242
+ readonly displayName: string;
243
+ readonly kind: "numbering";
244
+ readonly isDefault: boolean;
245
+ readonly basedOn?: string;
246
+ readonly aliases?: string[];
245
247
  /**
246
248
  * The `<w:numId w:val="..."/>` inside the `<w:pPr><w:numPr>` subtree,
247
249
  * when present. Consumers that later resolve numbering-type styles to
248
250
  * numbering instances (Lane 3a) will use this.
249
251
  */
250
- numberingInstanceId?: string;
252
+ readonly numberingInstanceId?: string;
251
253
  }
252
254
 
253
255
  export interface ParagraphStyleDefinition {
254
- styleId: string;
255
- basedOn?: string;
256
- nextStyle?: string;
257
- outlineLevel?: number;
258
- numbering?: ParagraphStyleNumberingReference;
259
- displayName: string;
256
+ readonly styleId: string;
257
+ readonly basedOn?: string;
258
+ readonly nextStyle?: string;
259
+ readonly outlineLevel?: number;
260
+ readonly numbering?: ParagraphStyleNumberingReference;
261
+ readonly displayName: string;
260
262
  /**
261
263
  * Alternate display names parsed from `<w:aliases w:val="A,B"/>`
262
264
  * (ECMA-376 §17.7.4.2). Comma-separated in source; stored as array.
263
265
  */
264
- aliases?: string[];
266
+ readonly aliases?: string[];
265
267
  /**
266
268
  * `<w:autoRedefine/>` — when true, Word re-records paragraph direct
267
269
  * formatting into the style definition as the user types (ECMA-376
268
270
  * §17.7.4.3). Round-trip preservation only; no render effect.
269
271
  */
270
- autoRedefine?: boolean;
271
- kind: "paragraph";
272
- isDefault: boolean;
273
- paragraphProperties?: CanonicalParagraphFormatting;
274
- runProperties?: CanonicalRunFormatting;
272
+ readonly autoRedefine?: boolean;
273
+ readonly kind: "paragraph";
274
+ readonly isDefault: boolean;
275
+ readonly paragraphProperties?: CanonicalParagraphFormatting;
276
+ readonly runProperties?: CanonicalRunFormatting;
275
277
  /**
276
278
  * Style ID of the linked character style (from `<w:link w:val="..."/>`).
277
279
  * Populated during parse; the second-pass resolver in `parse-styles.ts`
@@ -279,55 +281,55 @@ export interface ParagraphStyleDefinition {
279
281
  * declares the relationship on one side. Mirrors LibreOffice's
280
282
  * `StyleSheetTable.cxx:535` second pass.
281
283
  */
282
- linkedStyleId?: string;
284
+ readonly linkedStyleId?: string;
283
285
  }
284
286
 
285
287
  export interface ParagraphStyleNumberingReference {
286
- numberingInstanceId: string;
287
- level?: number;
288
+ readonly numberingInstanceId: string;
289
+ readonly level?: number;
288
290
  }
289
291
 
290
292
  export interface CharacterStyleDefinition {
291
- styleId: string;
292
- basedOn?: string;
293
- displayName: string;
293
+ readonly styleId: string;
294
+ readonly basedOn?: string;
295
+ readonly displayName: string;
294
296
  /** See `ParagraphStyleDefinition.aliases`. */
295
- aliases?: string[];
296
- kind: "character";
297
- isDefault: boolean;
298
- runProperties?: CanonicalRunFormatting;
297
+ readonly aliases?: string[];
298
+ readonly kind: "character";
299
+ readonly isDefault: boolean;
300
+ readonly runProperties?: CanonicalRunFormatting;
299
301
  /**
300
302
  * Style ID of the linked paragraph style (from `<w:link w:val="..."/>`).
301
303
  * See `ParagraphStyleDefinition.linkedStyleId` for the second-pass
302
304
  * reciprocal-resolution contract.
303
305
  */
304
- linkedStyleId?: string;
306
+ readonly linkedStyleId?: string;
305
307
  }
306
308
 
307
309
  export interface TableStyleDefinition {
308
- styleId: string;
309
- basedOn?: string;
310
- displayName: string;
310
+ readonly styleId: string;
311
+ readonly basedOn?: string;
312
+ readonly displayName: string;
311
313
  /** See `ParagraphStyleDefinition.aliases`. */
312
- aliases?: string[];
313
- kind: "table";
314
- isDefault: boolean;
315
- formatting?: TableStyleFormatting;
316
- conditionalFormatting?: Partial<Record<TableStyleConditionalRegion, TableStyleFormatting>>;
314
+ readonly aliases?: string[];
315
+ readonly kind: "table";
316
+ readonly isDefault: boolean;
317
+ readonly formatting?: TableStyleFormatting;
318
+ readonly conditionalFormatting?: Partial<Record<TableStyleConditionalRegion, TableStyleFormatting>>;
317
319
  }
318
320
 
319
321
  export interface LatentStyleDefinition {
320
- name: string;
321
- locked?: boolean;
322
- semiHidden?: boolean;
323
- unhideWhenUsed?: boolean;
324
- qFormat?: boolean;
325
- uiPriority?: number;
322
+ readonly name: string;
323
+ readonly locked?: boolean;
324
+ readonly semiHidden?: boolean;
325
+ readonly unhideWhenUsed?: boolean;
326
+ readonly qFormat?: boolean;
327
+ readonly uiPriority?: number;
326
328
  }
327
329
 
328
330
  export interface NumberingCatalog {
329
- abstractDefinitions: Record<string, AbstractNumberingDefinition>;
330
- instances: Record<string, NumberingInstance>;
331
+ readonly abstractDefinitions: Record<string, AbstractNumberingDefinition>;
332
+ readonly instances: Record<string, NumberingInstance>;
331
333
  /**
332
334
  * `<w:numPicBullet>` media-catalog entries keyed by `w:numPicBulletId`.
333
335
  * Each entry preserves the raw drawing/pic XML plus a resolved media
@@ -335,7 +337,7 @@ export interface NumberingCatalog {
335
337
  * Consumed by numbering-prefix when `NumberingLevelDefinition.picBulletId`
336
338
  * is set (ECMA-376 §17.9.19). Rendering is Lane 6 territory.
337
339
  */
338
- numPicBullets?: Record<string, NumPicBullet>;
340
+ readonly numPicBullets?: Record<string, NumPicBullet>;
339
341
  }
340
342
 
341
343
  /**
@@ -348,101 +350,101 @@ export interface NumberingCatalog {
348
350
  */
349
351
  export interface NumPicBullet {
350
352
  /** `w:numPicBulletId` attribute value — the lookup key. */
351
- numPicBulletId: string;
353
+ readonly numPicBulletId: string;
352
354
  /** Verbatim XML for the `<w:numPicBullet>` element. */
353
- rawXml: string;
355
+ readonly rawXml: string;
354
356
  /**
355
357
  * Resolved media-catalog media id when the bullet's inner image references
356
358
  * a relationship we could resolve at parse time. Undefined when the
357
359
  * bullet uses an unresolved blipRef or a VML path.
358
360
  */
359
- mediaId?: string;
361
+ readonly mediaId?: string;
360
362
  /**
361
363
  * Bullet cell extent in EMU (English Metric Units) when parsed from the
362
364
  * drawing's `wp:extent` — lets the renderer size the bullet image without
363
365
  * round-tripping through a new measurement pass. Undefined for VML paths.
364
366
  */
365
- widthEmu?: number;
366
- heightEmu?: number;
367
+ readonly widthEmu?: number;
368
+ readonly heightEmu?: number;
367
369
  }
368
370
 
369
371
  export interface AbstractNumberingDefinition {
370
- abstractNumberingId: string;
371
- levels: NumberingLevelDefinition[];
372
- nsid?: string;
373
- multiLevelType?: "singleLevel" | "multilevel" | "hybridMultilevel";
372
+ readonly abstractNumberingId: string;
373
+ readonly levels: NumberingLevelDefinition[];
374
+ readonly nsid?: string;
375
+ readonly multiLevelType?: "singleLevel" | "multilevel" | "hybridMultilevel";
374
376
  /** ECMA-376 17.9.26 `<w:tmpl>` — template code identifying the abstractNum's origin template (ST_LongHexNumber). Preserved for round-trip. */
375
- tplc?: string;
376
- styleLink?: string;
377
- numStyleLink?: string;
377
+ readonly tplc?: string;
378
+ readonly styleLink?: string;
379
+ readonly numStyleLink?: string;
378
380
  }
379
381
 
380
382
  export interface NumberingLevelParagraphGeometry {
381
- justification?: "left" | "center" | "right" | "both" | "distribute";
382
- spacing?: ParagraphSpacing;
383
- indentation?: ParagraphIndentation;
384
- tabStops?: TabStop[];
383
+ readonly justification?: "left" | "center" | "right" | "both" | "distribute";
384
+ readonly spacing?: ParagraphSpacing;
385
+ readonly indentation?: ParagraphIndentation;
386
+ readonly tabStops?: TabStop[];
385
387
  }
386
388
 
387
389
  export interface NumberingLevelDefinition {
388
- level: number;
389
- format: string;
390
- text: string;
391
- startAt?: number;
392
- paragraphStyleId?: string;
393
- isLegalNumbering?: boolean;
394
- suffix?: "tab" | "space" | "nothing";
395
- paragraphGeometry?: NumberingLevelParagraphGeometry;
396
- runProperties?: CanonicalRunFormatting;
397
- restartAfterLevel?: number;
390
+ readonly level: number;
391
+ readonly format: string;
392
+ readonly text: string;
393
+ readonly startAt?: number;
394
+ readonly paragraphStyleId?: string;
395
+ readonly isLegalNumbering?: boolean;
396
+ readonly suffix?: "tab" | "space" | "nothing";
397
+ readonly paragraphGeometry?: NumberingLevelParagraphGeometry;
398
+ readonly runProperties?: CanonicalRunFormatting;
399
+ readonly restartAfterLevel?: number;
398
400
  /**
399
401
  * `<w:lvlPicBulletId w:val="N"/>` reference — picks the matching entry
400
402
  * from `NumberingCatalog.numPicBullets`. When set, the marker renders as
401
403
  * an inline image instead of a text glyph. ECMA-376 §17.9.12.
402
404
  */
403
- picBulletId?: string;
405
+ readonly picBulletId?: string;
404
406
  }
405
407
 
406
408
  export interface NumberingLevelOverrideDefinition {
407
- level: number;
408
- format?: string;
409
- text?: string;
410
- startAt?: number;
411
- paragraphStyleId?: string;
412
- isLegalNumbering?: boolean;
413
- suffix?: "tab" | "space" | "nothing";
414
- paragraphGeometry?: NumberingLevelParagraphGeometry;
415
- runProperties?: CanonicalRunFormatting;
416
- restartAfterLevel?: number;
417
- picBulletId?: string;
409
+ readonly level: number;
410
+ readonly format?: string;
411
+ readonly text?: string;
412
+ readonly startAt?: number;
413
+ readonly paragraphStyleId?: string;
414
+ readonly isLegalNumbering?: boolean;
415
+ readonly suffix?: "tab" | "space" | "nothing";
416
+ readonly paragraphGeometry?: NumberingLevelParagraphGeometry;
417
+ readonly runProperties?: CanonicalRunFormatting;
418
+ readonly restartAfterLevel?: number;
419
+ readonly picBulletId?: string;
418
420
  }
419
421
 
420
422
  export interface NumberingInstance {
421
- numberingInstanceId: string;
422
- abstractNumberingId: string;
423
- overrides: NumberingLevelOverride[];
423
+ readonly numberingInstanceId: string;
424
+ readonly abstractNumberingId: string;
425
+ readonly overrides: NumberingLevelOverride[];
424
426
  }
425
427
 
426
428
  export interface NumberingLevelOverride {
427
- level: number;
428
- startAt?: number;
429
- levelDefinition?: NumberingLevelOverrideDefinition;
429
+ readonly level: number;
430
+ readonly startAt?: number;
431
+ readonly levelDefinition?: NumberingLevelOverrideDefinition;
430
432
  }
431
433
 
432
434
  export interface MediaCatalog {
433
- items: Record<string, MediaItem>;
435
+ readonly items: Record<string, MediaItem>;
434
436
  }
435
437
 
436
438
  export interface MediaItem {
437
- mediaId: string;
438
- contentType: string;
439
- filename: string;
440
- relationshipId?: string;
441
- packagePartName: string;
442
- altText?: string;
443
- display?: "inline" | "floating";
444
- widthEmu?: number;
445
- heightEmu?: number;
439
+ readonly mediaId: string;
440
+ readonly contentType: string;
441
+ readonly filename: string;
442
+ readonly relationshipId?: string;
443
+ readonly packagePartName: string;
444
+ readonly altText?: string;
445
+ readonly display?: "inline" | "floating";
446
+ readonly widthEmu?: number;
447
+ readonly heightEmu?: number;
446
448
  }
447
449
 
448
450
  // ---- Sub-part canonical types ----
@@ -450,25 +452,25 @@ export interface MediaItem {
450
452
  export type HeaderFooterVariant = "default" | "first" | "even";
451
453
 
452
454
  export interface HeaderDocument {
453
- variant: HeaderFooterVariant;
454
- partPath: string;
455
- relationshipId: string;
456
- blocks: BlockNode[];
457
- sectionIndex?: number;
455
+ readonly variant: HeaderFooterVariant;
456
+ readonly partPath: string;
457
+ readonly relationshipId: string;
458
+ readonly blocks: BlockNode[];
459
+ readonly sectionIndex?: number;
458
460
  }
459
461
 
460
462
  export interface FooterDocument {
461
- variant: HeaderFooterVariant;
462
- partPath: string;
463
- relationshipId: string;
464
- blocks: BlockNode[];
465
- sectionIndex?: number;
463
+ readonly variant: HeaderFooterVariant;
464
+ readonly partPath: string;
465
+ readonly relationshipId: string;
466
+ readonly blocks: BlockNode[];
467
+ readonly sectionIndex?: number;
466
468
  }
467
469
 
468
470
  export interface FootnoteDefinition {
469
- noteId: string;
470
- kind: "footnote" | "endnote";
471
- blocks: BlockNode[];
471
+ readonly noteId: string;
472
+ readonly kind: "footnote" | "endnote";
473
+ readonly blocks: BlockNode[];
472
474
  }
473
475
 
474
476
  /**
@@ -483,33 +485,33 @@ export interface FootnoteDefinition {
483
485
  */
484
486
  export interface FootnoteSeparators {
485
487
  /** Raw XML of the <w:r> children inside the separator paragraph. */
486
- separatorContent?: string;
488
+ readonly separatorContent?: string;
487
489
  /** Full XML of the first separator paragraph. */
488
- separatorParagraphXml?: string;
490
+ readonly separatorParagraphXml?: string;
489
491
  /** Raw XML of the <w:r> children inside the continuationSeparator paragraph. */
490
- continuationSeparatorContent?: string;
492
+ readonly continuationSeparatorContent?: string;
491
493
  /** Full XML of the first continuation-separator paragraph. */
492
- continuationSeparatorParagraphXml?: string;
494
+ readonly continuationSeparatorParagraphXml?: string;
493
495
  }
494
496
 
495
497
  export interface FootnoteCollection {
496
- footnotes: Record<string, FootnoteDefinition>;
497
- endnotes: Record<string, FootnoteDefinition>;
498
+ readonly footnotes: Record<string, FootnoteDefinition>;
499
+ readonly endnotes: Record<string, FootnoteDefinition>;
498
500
  /** Separator content parsed from footnotes.xml special entries. */
499
- footnoteSeparators?: FootnoteSeparators;
501
+ readonly footnoteSeparators?: FootnoteSeparators;
500
502
  /** Separator content parsed from endnotes.xml special entries. */
501
- endnoteSeparators?: FootnoteSeparators;
503
+ readonly endnoteSeparators?: FootnoteSeparators;
502
504
  }
503
505
 
504
506
  export interface ThemeColorScheme {
505
- name: string;
506
- colors: Record<string, string>;
507
+ readonly name: string;
508
+ readonly colors: Record<string, string>;
507
509
  }
508
510
 
509
511
  export interface ThemeFontScheme {
510
- name: string;
511
- majorFont?: string;
512
- minorFont?: string;
512
+ readonly name: string;
513
+ readonly majorFont?: string;
514
+ readonly minorFont?: string;
513
515
  }
514
516
 
515
517
  /**
@@ -541,9 +543,9 @@ export type ThemeFontSlot =
541
543
  | "minorBidi";
542
544
 
543
545
  export interface ThemeDefinition {
544
- name?: string;
545
- colorScheme?: ThemeColorScheme;
546
- fontScheme?: ThemeFontScheme;
546
+ readonly name?: string;
547
+ readonly colorScheme?: ThemeColorScheme;
548
+ readonly fontScheme?: ThemeFontScheme;
547
549
  }
548
550
 
549
551
  /**
@@ -555,49 +557,49 @@ export interface ThemeDefinition {
555
557
  * future serializer can re-emit byte-stable diffs.
556
558
  */
557
559
  export interface CompatSetting {
558
- name: string;
559
- uri: string;
560
- value: string;
560
+ readonly name: string;
561
+ readonly uri: string;
562
+ readonly value: string;
561
563
  }
562
564
 
563
565
  export interface DocumentSettings {
564
- evenAndOddHeaders?: boolean;
565
- zoomLevel?: "pageWidth" | "onePage" | number;
566
+ readonly evenAndOddHeaders?: boolean;
567
+ readonly zoomLevel?: "pageWidth" | "onePage" | number;
566
568
  /**
567
569
  * Document-wide default tab stop interval from `<w:defaultTabStop w:val>`.
568
570
  * Value is stored in twips and feeds layout measurement whenever a paragraph
569
571
  * does not declare an explicit next tab stop.
570
572
  */
571
- defaultTabStop?: number;
573
+ readonly defaultTabStop?: number;
572
574
  /**
573
575
  * Settings-level default footnote configuration from `<w:footnotePr>`.
574
576
  * Section-level `SectionProperties.footnotePr` overrides this when present.
575
577
  */
576
- footnotePr?: FootnoteProperties;
578
+ readonly footnotePr?: FootnoteProperties;
577
579
  /**
578
580
  * Settings-level default endnote configuration from `<w:endnotePr>`.
579
581
  * Section-level `SectionProperties.endnotePr` overrides this when present.
580
582
  */
581
- endnotePr?: EndnoteProperties;
583
+ readonly endnotePr?: EndnoteProperties;
582
584
  /**
583
585
  * Ordered list of <w:compatSetting> entries inside <w:compat>. Insertion
584
586
  * order is preserved for serializer diff stability.
585
587
  */
586
- compatSettings?: CompatSetting[];
588
+ readonly compatSettings?: CompatSetting[];
587
589
  /**
588
590
  * Boolean flag children of <w:compat> that are NOT <w:compatSetting>
589
591
  * (e.g. <w:spaceForUL/>, <w:doNotExpandShiftReturn/>). Keyed by local
590
592
  * element name. The value reflects ST_OnOff semantics: missing `w:val` is
591
593
  * true; explicit `w:val="0"`/`"false"` is false.
592
594
  */
593
- compatFlags?: Record<string, boolean>;
595
+ readonly compatFlags?: Record<string, boolean>;
594
596
  /**
595
597
  * Settings-level (NOT inside <w:compat>) compat-adjacent boolean flags
596
598
  * such as <w:doNotEmbedSmartTags/>. Kept in a separate field from
597
599
  * compatFlags because the OOXML location differs and the future
598
600
  * serializer must re-emit them at root, not inside <w:compat>.
599
601
  */
600
- rootCompatFlags?: Record<string, boolean>;
602
+ readonly rootCompatFlags?: Record<string, boolean>;
601
603
  /**
602
604
  * <w:themeFontLang> attribute bag, captured verbatim so the future
603
605
  * serializer can re-emit unknown attributes Word may add.
@@ -608,7 +610,7 @@ export interface DocumentSettings {
608
610
  * - { "w:val": "en-US", … }: attributes preserved with their qualified
609
611
  * names so the serializer round-trips namespace prefixes intact.
610
612
  */
611
- themeFontLang?: Record<string, string>;
613
+ readonly themeFontLang?: Record<string, string>;
612
614
  /**
613
615
  * Local names of every direct child of <w:settings> that this parser does
614
616
  * not model individually. Insertion order preserved; duplicates retained.
@@ -618,35 +620,35 @@ export interface DocumentSettings {
618
620
  * use this list as a validator assertion that every preserved child still
619
621
  * appears in the re-emitted output.
620
622
  */
621
- unmodelledSettingsChildren?: string[];
623
+ readonly unmodelledSettingsChildren?: string[];
622
624
  /**
623
625
  * Parsed from `<w:clrSchemeMapping>` in settings.xml. Maps document-level
624
626
  * color style slot names to physical clrScheme slots. Absent when the
625
627
  * element was not present in the document (identity mapping applies).
626
628
  */
627
- clrSchemeMapping?: ClrSchemeMapping;
629
+ readonly clrSchemeMapping?: ClrSchemeMapping;
628
630
  }
629
631
 
630
632
  export interface SubPartsCatalog {
631
- headers: HeaderDocument[];
632
- footers: FooterDocument[];
633
- footnoteCollection?: FootnoteCollection;
634
- theme?: ThemeDefinition;
635
- finalSectionProperties?: SectionProperties;
636
- resolvedTheme?: ResolvedTheme;
637
- settings?: DocumentSettings;
633
+ readonly headers: HeaderDocument[];
634
+ readonly footers: FooterDocument[];
635
+ readonly footnoteCollection?: FootnoteCollection;
636
+ readonly theme?: ThemeDefinition;
637
+ readonly finalSectionProperties?: SectionProperties;
638
+ readonly resolvedTheme?: ResolvedTheme;
639
+ readonly settings?: DocumentSettings;
638
640
  /**
639
641
  * Fully materialized theme for runtime resolution — combines theme1.xml
640
642
  * color/font scheme with the clrSchemeMapping from settings.xml.
641
643
  * Available after CO1 load wiring lands in docx-session.ts.
642
644
  */
643
- canonicalTheme?: CanonicalTheme;
645
+ readonly canonicalTheme?: CanonicalTheme;
644
646
  }
645
647
 
646
648
  export interface ResolvedTheme {
647
- colors: Record<string, string>;
648
- majorFont?: string;
649
- minorFont?: string;
649
+ readonly colors: Record<string, string>;
650
+ readonly majorFont?: string;
651
+ readonly minorFont?: string;
650
652
  }
651
653
 
652
654
  /**
@@ -688,22 +690,22 @@ export type ClrSchemeMapping = Partial<Record<ClrSchemeMappingSlot, ThemeColorSl
688
690
  * documents with no theme part.
689
691
  */
690
692
  export interface CanonicalTheme {
691
- clrScheme: ThemeColorScheme;
692
- fontScheme?: ThemeFontScheme;
693
+ readonly clrScheme: ThemeColorScheme;
694
+ readonly fontScheme?: ThemeFontScheme;
693
695
  /** Resolved clrSchemeMapping: styleSlot → clrScheme slot name. Empty = identity. */
694
- clrMap: ClrSchemeMapping;
696
+ readonly clrMap: ClrSchemeMapping;
695
697
  /** Stable content hash of clrScheme.colors (sorted key:value pairs). */
696
- themeHash: string;
698
+ readonly themeHash: string;
697
699
  /** Stable content hash of clrMap (sorted key:value pairs). */
698
- clrMapHash: string;
700
+ readonly clrMapHash: string;
699
701
  }
700
702
 
701
703
  // ---- Inline footnote reference node ----
702
704
 
703
705
  export interface FootnoteRefNode {
704
- type: "footnote_ref";
705
- noteId: string;
706
- noteKind: "footnote" | "endnote";
706
+ readonly type: "footnote_ref";
707
+ readonly noteId: string;
708
+ readonly noteKind: "footnote" | "endnote";
707
709
  }
708
710
 
709
711
  export type DocumentNode =
@@ -741,8 +743,8 @@ export type DocumentNode =
741
743
  | OleEmbedNode;
742
744
 
743
745
  export interface DocumentRootNode {
744
- type: "doc";
745
- children: BlockNode[];
746
+ readonly type: "doc";
747
+ readonly children: BlockNode[];
746
748
  }
747
749
 
748
750
  export type BlockNode =
@@ -755,74 +757,74 @@ export type BlockNode =
755
757
  | OpaqueBlockNode;
756
758
 
757
759
  export interface ParagraphSpacing {
758
- before?: number;
759
- after?: number;
760
- line?: number;
761
- lineRule?: "auto" | "exact" | "atLeast";
760
+ readonly before?: number;
761
+ readonly after?: number;
762
+ readonly line?: number;
763
+ readonly lineRule?: "auto" | "exact" | "atLeast";
762
764
  }
763
765
 
764
766
  export interface ParagraphIndentation {
765
- left?: number;
766
- right?: number;
767
- firstLine?: number;
768
- hanging?: number;
767
+ readonly left?: number;
768
+ readonly right?: number;
769
+ readonly firstLine?: number;
770
+ readonly hanging?: number;
769
771
  }
770
772
 
771
773
  export interface TabStop {
772
- position: number;
773
- align: "left" | "center" | "right" | "decimal" | "num" | "bar" | "clear";
774
- leader?: "none" | "dot" | "hyphen" | "underscore" | "heavy" | "middleDot";
774
+ readonly position: number;
775
+ readonly align: "left" | "center" | "right" | "decimal" | "num" | "bar" | "clear";
776
+ readonly leader?: "none" | "dot" | "hyphen" | "underscore" | "heavy" | "middleDot";
775
777
  }
776
778
 
777
779
  export interface ParagraphBorders {
778
- top?: BorderSpec;
779
- left?: BorderSpec;
780
- bottom?: BorderSpec;
781
- right?: BorderSpec;
782
- bar?: BorderSpec;
783
- between?: BorderSpec;
780
+ readonly top?: BorderSpec;
781
+ readonly left?: BorderSpec;
782
+ readonly bottom?: BorderSpec;
783
+ readonly right?: BorderSpec;
784
+ readonly bar?: BorderSpec;
785
+ readonly between?: BorderSpec;
784
786
  }
785
787
 
786
788
  export interface ParagraphShading {
787
- fill?: string;
788
- color?: string;
789
- val?: string;
789
+ readonly fill?: string;
790
+ readonly color?: string;
791
+ readonly val?: string;
790
792
  /**
791
793
  * Theme shading references (§17.3.5). When `themeFill` is set and `fill`
792
794
  * is absent or `"auto"`, render-time shading resolves through the theme
793
795
  * color resolver. The raw theme attrs remain on the canonical model so
794
796
  * export can round-trip the original `<w:shd>` byte-for-byte.
795
797
  */
796
- themeFill?: string;
797
- themeFillTint?: string;
798
- themeFillShade?: string;
799
- themeColor?: string;
800
- themeColorTint?: string;
801
- themeColorShade?: string;
798
+ readonly themeFill?: string;
799
+ readonly themeFillTint?: string;
800
+ readonly themeFillShade?: string;
801
+ readonly themeColor?: string;
802
+ readonly themeColorTint?: string;
803
+ readonly themeColorShade?: string;
802
804
  }
803
805
 
804
806
  /** Body of an OOXML `<w:rPr>` (run properties). All fields optional; absence = "not specified at this level". */
805
807
  export interface CanonicalRunFormatting {
806
- bold?: boolean;
807
- italic?: boolean;
808
- underline?: "single" | "double" | "thick" | "dotted" | "dash" | "wave" | "none";
809
- strikethrough?: boolean;
810
- doubleStrikethrough?: boolean;
811
- vanish?: boolean;
812
- allCaps?: boolean;
813
- smallCaps?: boolean;
814
- verticalAlign?: "baseline" | "superscript" | "subscript";
808
+ readonly bold?: boolean;
809
+ readonly italic?: boolean;
810
+ readonly underline?: "single" | "double" | "thick" | "dotted" | "dash" | "wave" | "none";
811
+ readonly strikethrough?: boolean;
812
+ readonly doubleStrikethrough?: boolean;
813
+ readonly vanish?: boolean;
814
+ readonly allCaps?: boolean;
815
+ readonly smallCaps?: boolean;
816
+ readonly verticalAlign?: "baseline" | "superscript" | "subscript";
815
817
  /**
816
818
  * Convenience alias for the primary font family — the first non-empty of
817
819
  * `fontFamilyAscii` → `fontFamilyHAnsi` → `fontFamilyEastAsia` → `fontFamilyCs`.
818
820
  * Script-aware consumers should read the specific `fontFamily{Ascii,HAnsi,EastAsia,Cs}`
819
821
  * fields directly.
820
822
  */
821
- fontFamily?: string;
822
- fontFamilyAscii?: string;
823
- fontFamilyHAnsi?: string;
824
- fontFamilyEastAsia?: string;
825
- fontFamilyCs?: string;
823
+ readonly fontFamily?: string;
824
+ readonly fontFamilyAscii?: string;
825
+ readonly fontFamilyHAnsi?: string;
826
+ readonly fontFamilyEastAsia?: string;
827
+ readonly fontFamilyCs?: string;
826
828
  /**
827
829
  * ECMA-376 §17.3.2.26 theme-slot bindings on `<w:rFonts>`
828
830
  * (`w:asciiTheme`, `w:hAnsiTheme`, `w:eastAsiaTheme`, `w:cstheme`).
@@ -837,18 +839,18 @@ export interface CanonicalRunFormatting {
837
839
  * concrete name wins. Keep the theme slot on the canonical so the
838
840
  * export path can re-emit it byte-identically.
839
841
  */
840
- asciiTheme?: ThemeFontSlot;
841
- hAnsiTheme?: ThemeFontSlot;
842
- eastAsiaTheme?: ThemeFontSlot;
843
- csTheme?: ThemeFontSlot;
844
- fontSizeHalfPoints?: number;
845
- fontSizeCsHalfPoints?: number;
842
+ readonly asciiTheme?: ThemeFontSlot;
843
+ readonly hAnsiTheme?: ThemeFontSlot;
844
+ readonly eastAsiaTheme?: ThemeFontSlot;
845
+ readonly csTheme?: ThemeFontSlot;
846
+ readonly fontSizeHalfPoints?: number;
847
+ readonly fontSizeCsHalfPoints?: number;
846
848
  /**
847
849
  * Color value from `<w:color w:val>`. Either an OOXML hex (e.g., `"2E74B5"`)
848
850
  * or the sentinel `"auto"` (which serializers must round-trip verbatim).
849
851
  */
850
- colorHex?: string;
851
- colorThemeSlot?: string;
852
+ readonly colorHex?: string;
853
+ readonly colorThemeSlot?: string;
852
854
  /**
853
855
  * `w:themeTint` hex byte (0x00–0xFF) read from `<w:color>`. ECMA-376
854
856
  * §17.18.85. Applied at render/cascade time against `colorThemeSlot`:
@@ -857,17 +859,17 @@ export interface CanonicalRunFormatting {
857
859
  * for byte-stable round-trip; resolution math lives in the runtime
858
860
  * theme-color resolver.
859
861
  */
860
- colorThemeTint?: string;
862
+ readonly colorThemeTint?: string;
861
863
  /**
862
864
  * `w:themeShade` hex byte (0x00–0xFF) from `<w:color>`. ECMA-376
863
865
  * §17.18.83. Applied at render/cascade time: luminance mod =
864
866
  * shade/255 * L (darkens toward black; 0xFF means no modulation).
865
867
  */
866
- colorThemeShade?: string;
867
- highlight?: string;
868
- characterSpacingTwips?: number;
869
- characterStyleId?: string;
870
- languageCode?: string;
868
+ readonly colorThemeShade?: string;
869
+ readonly highlight?: string;
870
+ readonly characterSpacingTwips?: number;
871
+ readonly characterStyleId?: string;
872
+ readonly languageCode?: string;
871
873
  /**
872
874
  * Unmodelled direct children of `<w:rPr>` captured verbatim for round-trip.
873
875
  * See `src/io/ooxml/property-grab-bag.ts` and
@@ -876,27 +878,27 @@ export interface CanonicalRunFormatting {
876
878
  * `<w:em>`, `<w:kern>` through parse→serialize round-trip even though the
877
879
  * runtime does not model them.
878
880
  */
879
- unknownPropertyChildren?: UnknownPropertyChild[];
881
+ readonly unknownPropertyChildren?: UnknownPropertyChild[];
880
882
  }
881
883
 
882
884
  /** Body of an OOXML `<w:pPr>` (paragraph properties). All fields optional; absence = "not specified at this level". */
883
885
  export interface CanonicalParagraphFormatting {
884
- spacing?: ParagraphSpacing;
885
- indentation?: ParagraphIndentation;
886
- alignment?: "left" | "center" | "right" | "both" | "distribute" | "start" | "end";
887
- borders?: ParagraphBorders;
888
- shading?: ParagraphShading;
889
- tabStops?: TabStop[];
890
- contextualSpacing?: boolean;
891
- keepNext?: boolean;
892
- keepLines?: boolean;
893
- widowControl?: boolean;
894
- pageBreakBefore?: boolean;
895
- outlineLevel?: number;
896
- bidi?: boolean;
897
- suppressLineNumbers?: boolean;
898
- suppressAutoHyphens?: boolean;
899
- paragraphMarkRunProperties?: CanonicalRunFormatting;
886
+ readonly spacing?: ParagraphSpacing;
887
+ readonly indentation?: ParagraphIndentation;
888
+ readonly alignment?: "left" | "center" | "right" | "both" | "distribute" | "start" | "end";
889
+ readonly borders?: ParagraphBorders;
890
+ readonly shading?: ParagraphShading;
891
+ readonly tabStops?: TabStop[];
892
+ readonly contextualSpacing?: boolean;
893
+ readonly keepNext?: boolean;
894
+ readonly keepLines?: boolean;
895
+ readonly widowControl?: boolean;
896
+ readonly pageBreakBefore?: boolean;
897
+ readonly outlineLevel?: number;
898
+ readonly bidi?: boolean;
899
+ readonly suppressLineNumbers?: boolean;
900
+ readonly suppressAutoHyphens?: boolean;
901
+ readonly paragraphMarkRunProperties?: CanonicalRunFormatting;
900
902
  /**
901
903
  * `<w:framePr>` — paragraph text-frame properties (ECMA-376 §17.3.1.11).
902
904
  * Absent on ordinary paragraphs. When present, the paragraph renders
@@ -910,7 +912,7 @@ export interface CanonicalParagraphFormatting {
910
912
  * `<w:framePr>`, which hid the paragraph from L04 pagination and L11
911
913
  * render. Canonical representation unblocks downstream adoption.
912
914
  */
913
- frameProperties?: FrameProperties;
915
+ readonly frameProperties?: FrameProperties;
914
916
  /**
915
917
  * Unmodelled direct children of `<w:pPr>` captured verbatim for round-trip.
916
918
  * See `src/io/ooxml/property-grab-bag.ts` for the mechanism and Lane 3 O2
@@ -922,7 +924,7 @@ export interface CanonicalParagraphFormatting {
922
924
  * or `<w:kinsoku>` survive a parse→serialize round-trip even though the
923
925
  * runtime doesn't understand them.
924
926
  */
925
- unknownPropertyChildren?: UnknownPropertyChild[];
927
+ readonly unknownPropertyChildren?: UnknownPropertyChild[];
926
928
  }
927
929
 
928
930
  /**
@@ -937,57 +939,57 @@ export interface CanonicalParagraphFormatting {
937
939
  */
938
940
  export interface FrameProperties {
939
941
  /** `w:w` — frame width in twips. Absence = auto-width from content. */
940
- widthTwips?: number;
942
+ readonly widthTwips?: number;
941
943
  /** `w:h` — frame height in twips. Interpretation depends on `hRule`. */
942
- heightTwips?: number;
944
+ readonly heightTwips?: number;
943
945
  /**
944
946
  * `w:hRule` — height rule.
945
947
  * - `"auto"` (default): height follows content.
946
948
  * - `"atLeast"`: content grows the frame; `heightTwips` is the floor.
947
949
  * - `"exact"`: content is clipped to `heightTwips`.
948
950
  */
949
- hRule?: "auto" | "atLeast" | "exact";
951
+ readonly hRule?: "auto" | "atLeast" | "exact";
950
952
  /** `w:x` — horizontal absolute position in twips from `hAnchor`. */
951
- xTwips?: number;
953
+ readonly xTwips?: number;
952
954
  /** `w:y` — vertical absolute position in twips from `vAnchor`. */
953
- yTwips?: number;
955
+ readonly yTwips?: number;
954
956
  /**
955
957
  * `w:xAlign` — horizontal alignment keyword; overrides `xTwips` if
956
958
  * both are set (Word behavior). `"inside"` / `"outside"` are
957
959
  * mirror-aware for even/odd pages.
958
960
  */
959
- xAlign?: "left" | "center" | "right" | "inside" | "outside";
961
+ readonly xAlign?: "left" | "center" | "right" | "inside" | "outside";
960
962
  /**
961
963
  * `w:yAlign` — vertical alignment keyword; overrides `yTwips` if
962
964
  * both are set. `"inline"` places the frame in the text flow.
963
965
  */
964
- yAlign?: "top" | "center" | "bottom" | "inside" | "outside" | "inline";
966
+ readonly yAlign?: "top" | "center" | "bottom" | "inside" | "outside" | "inline";
965
967
  /** `w:hAnchor` — what `x` / `xAlign` is measured from. */
966
- hAnchor?: "text" | "margin" | "page";
968
+ readonly hAnchor?: "text" | "margin" | "page";
967
969
  /** `w:vAnchor` — what `y` / `yAlign` is measured from. */
968
- vAnchor?: "text" | "margin" | "page";
970
+ readonly vAnchor?: "text" | "margin" | "page";
969
971
  /**
970
972
  * `w:wrap` — how surrounding text flows around the frame.
971
973
  * `"around"`: text wraps on both sides; `"notBeside"`: text stops
972
974
  * above/below the frame; `"none"`: no text on the frame line;
973
975
  * `"auto"` / `"tight"` / `"through"`: extended wrap modes.
974
976
  */
975
- wrap?: "around" | "auto" | "none" | "notBeside" | "tight" | "through";
977
+ readonly wrap?: "around" | "auto" | "none" | "notBeside" | "tight" | "through";
976
978
  /** `w:hSpace` — horizontal clear-space around the frame, twips. */
977
- hSpaceTwips?: number;
979
+ readonly hSpaceTwips?: number;
978
980
  /** `w:vSpace` — vertical clear-space around the frame, twips. */
979
- vSpaceTwips?: number;
981
+ readonly vSpaceTwips?: number;
980
982
  /**
981
983
  * `w:dropCap` — drop-cap semantics when the frame holds an initial
982
984
  * letter. `"none"` (default): not a drop-cap frame.
983
985
  * `"drop"`: character spans `lines` lines, text wraps around it.
984
986
  * `"margin"`: character hangs in the margin.
985
987
  */
986
- dropCap?: "none" | "drop" | "margin";
988
+ readonly dropCap?: "none" | "drop" | "margin";
987
989
  /** `w:lines` — number of lines the drop-cap spans. Only meaningful when `dropCap !== "none"`. */
988
- lines?: number;
990
+ readonly lines?: number;
989
991
  /** `w:anchorLock` — prevents the frame's anchor paragraph from moving between pages during reflow. */
990
- anchorLock?: boolean;
992
+ readonly anchorLock?: boolean;
991
993
  /**
992
994
  * Verbatim source XML of the `<w:framePr>` element. Populated by
993
995
  * the parser for lossless round-trip of extension attributes
@@ -996,7 +998,7 @@ export interface FrameProperties {
996
998
  * modeled fields and merge in any extension attributes from
997
999
  * `rawXml` that aren't covered by the modeled set.
998
1000
  */
999
- rawXml?: string;
1001
+ readonly rawXml?: string;
1000
1002
  }
1001
1003
 
1002
1004
  /**
@@ -1008,65 +1010,65 @@ export interface FrameProperties {
1008
1010
  */
1009
1011
  export interface UnknownPropertyChild {
1010
1012
  /** Qualified element name as it appeared in source, e.g. "w15:collapsed". */
1011
- elementName: string;
1013
+ readonly elementName: string;
1012
1014
  /** Verbatim source XML for the child element, including closing/self-closing form. */
1013
- rawXml: string;
1015
+ readonly rawXml: string;
1014
1016
  }
1015
1017
 
1016
1018
  /** Body of an OOXML `<w:docDefaults>` — baseline formatting applied before style chain. */
1017
1019
  export interface DocumentDefaults {
1018
- paragraph?: CanonicalParagraphFormatting;
1019
- run?: CanonicalRunFormatting;
1020
+ readonly paragraph?: CanonicalParagraphFormatting;
1021
+ readonly run?: CanonicalRunFormatting;
1020
1022
  }
1021
1023
 
1022
1024
  /** Materialized `fontTable.xml` — one entry per `<w:font>` element. */
1023
1025
  export interface CanonicalFontTable {
1024
- fonts: Record<string, CanonicalFontEntry>;
1026
+ readonly fonts: Record<string, CanonicalFontEntry>;
1025
1027
  }
1026
1028
 
1027
1029
  /** Metadata for a single `<w:font>` element from fontTable.xml. */
1028
1030
  export interface CanonicalFontEntry {
1029
1031
  /** `w:name` attribute — the key used in rFonts references. */
1030
- name: string;
1032
+ readonly name: string;
1031
1033
  /**
1032
1034
  * `w:family` value. Qualitative category per ECMA-376 §17.8.3.10.
1033
1035
  * "roman" = proportional serif, "swiss" = proportional sans-serif,
1034
1036
  * "modern" = fixed-pitch, "script" = handwriting, "decorative" = display.
1035
1037
  */
1036
- family?: "roman" | "swiss" | "modern" | "script" | "decorative";
1038
+ readonly family?: "roman" | "swiss" | "modern" | "script" | "decorative";
1037
1039
  /** `w:pitch` value — "fixed" maps to monospace metrics. */
1038
- pitch?: "fixed" | "variable" | "default";
1040
+ readonly pitch?: "fixed" | "variable" | "default";
1039
1041
  /**
1040
1042
  * Windows charset code from `w:charset w:val`.
1041
1043
  * 2 = Symbol font (charset override required for correct glyph mapping).
1042
1044
  */
1043
- charset?: number;
1045
+ readonly charset?: number;
1044
1046
  /** `w:altName` — substitution name when the primary font is unavailable. */
1045
- altName?: string;
1047
+ readonly altName?: string;
1046
1048
  }
1047
1049
 
1048
1050
  export interface ParagraphNode {
1049
- type: "paragraph";
1050
- styleId?: string;
1051
+ readonly type: "paragraph";
1052
+ readonly styleId?: string;
1051
1053
  numbering?: {
1052
- numberingInstanceId: string;
1053
- level: number;
1054
+ readonly numberingInstanceId: string;
1055
+ readonly level: number;
1054
1056
  };
1055
- alignment?: "left" | "center" | "right" | "both" | "distribute";
1056
- spacing?: ParagraphSpacing;
1057
- contextualSpacing?: boolean;
1058
- indentation?: ParagraphIndentation;
1059
- tabStops?: TabStop[];
1060
- keepNext?: boolean;
1061
- keepLines?: boolean;
1062
- outlineLevel?: number;
1063
- pageBreakBefore?: boolean;
1064
- widowControl?: boolean;
1065
- borders?: ParagraphBorders;
1066
- shading?: ParagraphShading;
1067
- bidi?: boolean;
1068
- suppressLineNumbers?: boolean;
1069
- cnfStyle?: string;
1057
+ readonly alignment?: "left" | "center" | "right" | "both" | "distribute";
1058
+ readonly spacing?: ParagraphSpacing;
1059
+ readonly contextualSpacing?: boolean;
1060
+ readonly indentation?: ParagraphIndentation;
1061
+ readonly tabStops?: TabStop[];
1062
+ readonly keepNext?: boolean;
1063
+ readonly keepLines?: boolean;
1064
+ readonly outlineLevel?: number;
1065
+ readonly pageBreakBefore?: boolean;
1066
+ readonly widowControl?: boolean;
1067
+ readonly borders?: ParagraphBorders;
1068
+ readonly shading?: ParagraphShading;
1069
+ readonly bidi?: boolean;
1070
+ readonly suppressLineNumbers?: boolean;
1071
+ readonly cnfStyle?: string;
1070
1072
  /**
1071
1073
  * `<w:framePr>` — inline paragraph text-frame properties set
1072
1074
  * directly on the paragraph (not through the style cascade).
@@ -1084,7 +1086,7 @@ export interface ParagraphNode {
1084
1086
  * to `OpaqueBlockNode` because the parser had no canonical target
1085
1087
  * at the node level.
1086
1088
  */
1087
- frameProperties?: FrameProperties;
1089
+ readonly frameProperties?: FrameProperties;
1088
1090
  /**
1089
1091
  * Preserved w14 extension identifiers for this paragraph.
1090
1092
  * Round-trip (§2 A.7) requires these to survive import → export so the
@@ -1093,65 +1095,65 @@ export interface ParagraphNode {
1093
1095
  * 8-hex uppercase strings per ECMA-376 Part 1 Appendix A.
1094
1096
  */
1095
1097
  wordExtensionIds?: {
1096
- paraId?: string;
1097
- textId?: string;
1098
+ readonly paraId?: string;
1099
+ readonly textId?: string;
1098
1100
  };
1099
- children: InlineNode[];
1101
+ readonly children: InlineNode[];
1100
1102
  }
1101
1103
 
1102
1104
  export interface BorderSpec {
1103
- value?: string;
1104
- size?: number;
1105
- space?: number;
1106
- color?: string;
1105
+ readonly value?: string;
1106
+ readonly size?: number;
1107
+ readonly space?: number;
1108
+ readonly color?: string;
1107
1109
  }
1108
1110
 
1109
1111
  export interface TableBorders {
1110
- top?: BorderSpec;
1111
- left?: BorderSpec;
1112
- bottom?: BorderSpec;
1113
- right?: BorderSpec;
1114
- insideH?: BorderSpec;
1115
- insideV?: BorderSpec;
1112
+ readonly top?: BorderSpec;
1113
+ readonly left?: BorderSpec;
1114
+ readonly bottom?: BorderSpec;
1115
+ readonly right?: BorderSpec;
1116
+ readonly insideH?: BorderSpec;
1117
+ readonly insideV?: BorderSpec;
1116
1118
  }
1117
1119
 
1118
1120
  export interface TableCellBorders {
1119
- top?: BorderSpec;
1120
- left?: BorderSpec;
1121
- bottom?: BorderSpec;
1122
- right?: BorderSpec;
1123
- insideH?: BorderSpec;
1124
- insideV?: BorderSpec;
1121
+ readonly top?: BorderSpec;
1122
+ readonly left?: BorderSpec;
1123
+ readonly bottom?: BorderSpec;
1124
+ readonly right?: BorderSpec;
1125
+ readonly insideH?: BorderSpec;
1126
+ readonly insideV?: BorderSpec;
1125
1127
  }
1126
1128
 
1127
1129
  export interface TableWidth {
1128
- value: number;
1129
- type: "dxa" | "auto" | "pct" | "nil";
1130
+ readonly value: number;
1131
+ readonly type: "dxa" | "auto" | "pct" | "nil";
1130
1132
  }
1131
1133
 
1132
1134
  export interface TableIndent {
1133
- value: number;
1134
- type: "dxa" | "auto" | "pct" | "nil";
1135
+ readonly value: number;
1136
+ readonly type: "dxa" | "auto" | "pct" | "nil";
1135
1137
  }
1136
1138
 
1137
1139
  export interface TableFloatingProperties {
1138
- horizontalAnchor?: "margin" | "page" | "text";
1139
- verticalAnchor?: "margin" | "page" | "text";
1140
- horizontalAlign?: "left" | "center" | "right" | "inside" | "outside";
1141
- horizontalOffset?: number;
1142
- verticalAlign?: "top" | "center" | "bottom" | "inside" | "outside";
1143
- verticalOffset?: number;
1144
- leftFromText?: number;
1145
- rightFromText?: number;
1146
- topFromText?: number;
1147
- bottomFromText?: number;
1148
- overlap?: boolean;
1140
+ readonly horizontalAnchor?: "margin" | "page" | "text";
1141
+ readonly verticalAnchor?: "margin" | "page" | "text";
1142
+ readonly horizontalAlign?: "left" | "center" | "right" | "inside" | "outside";
1143
+ readonly horizontalOffset?: number;
1144
+ readonly verticalAlign?: "top" | "center" | "bottom" | "inside" | "outside";
1145
+ readonly verticalOffset?: number;
1146
+ readonly leftFromText?: number;
1147
+ readonly rightFromText?: number;
1148
+ readonly topFromText?: number;
1149
+ readonly bottomFromText?: number;
1150
+ readonly overlap?: boolean;
1149
1151
  }
1150
1152
 
1151
1153
  export interface CellShading {
1152
- fill?: string;
1153
- color?: string;
1154
- val?: string;
1154
+ readonly fill?: string;
1155
+ readonly color?: string;
1156
+ readonly val?: string;
1155
1157
  /**
1156
1158
  * SOW gap G3 — theme-shading references (§17.3.5). When `themeFill` is set
1157
1159
  * and `fill` is absent or "auto", the runtime resolves the shading via
@@ -1159,29 +1161,29 @@ export interface CellShading {
1159
1161
  * themeFillShade)`. Fields are kept verbatim so export can round-trip the
1160
1162
  * original `w:shd` element without re-encoding the resolved hex.
1161
1163
  */
1162
- themeFill?: string;
1163
- themeFillTint?: string;
1164
- themeFillShade?: string;
1165
- themeColor?: string;
1166
- themeColorTint?: string;
1167
- themeColorShade?: string;
1164
+ readonly themeFill?: string;
1165
+ readonly themeFillTint?: string;
1166
+ readonly themeFillShade?: string;
1167
+ readonly themeColor?: string;
1168
+ readonly themeColorTint?: string;
1169
+ readonly themeColorShade?: string;
1168
1170
  }
1169
1171
 
1170
1172
  export interface TableCellMargins {
1171
- top?: number;
1172
- left?: number;
1173
- bottom?: number;
1174
- right?: number;
1173
+ readonly top?: number;
1174
+ readonly left?: number;
1175
+ readonly bottom?: number;
1176
+ readonly right?: number;
1175
1177
  }
1176
1178
 
1177
1179
  export interface TableLook {
1178
- val?: string;
1179
- firstRow?: boolean;
1180
- lastRow?: boolean;
1181
- firstColumn?: boolean;
1182
- lastColumn?: boolean;
1183
- noHBand?: boolean;
1184
- noVBand?: boolean;
1180
+ readonly val?: string;
1181
+ readonly firstRow?: boolean;
1182
+ readonly lastRow?: boolean;
1183
+ readonly firstColumn?: boolean;
1184
+ readonly lastColumn?: boolean;
1185
+ readonly noHBand?: boolean;
1186
+ readonly noVBand?: boolean;
1185
1187
  }
1186
1188
 
1187
1189
  export type TableStyleConditionalRegion =
@@ -1196,140 +1198,140 @@ export type TableStyleConditionalRegion =
1196
1198
 
1197
1199
  export interface TableStyleFormatting {
1198
1200
  table?: {
1199
- width?: TableWidth;
1200
- alignment?: "left" | "center" | "right";
1201
- borders?: TableBorders;
1202
- cellMargins?: TableCellMargins;
1203
- tblLook?: TableLook;
1201
+ readonly width?: TableWidth;
1202
+ readonly alignment?: "left" | "center" | "right";
1203
+ readonly borders?: TableBorders;
1204
+ readonly cellMargins?: TableCellMargins;
1205
+ readonly tblLook?: TableLook;
1204
1206
  };
1205
1207
  row?: {
1206
- height?: number;
1207
- heightRule?: "auto" | "atLeast" | "exact";
1208
- isHeader?: boolean;
1208
+ readonly height?: number;
1209
+ readonly heightRule?: "auto" | "atLeast" | "exact";
1210
+ readonly isHeader?: boolean;
1209
1211
  };
1210
1212
  cell?: {
1211
- width?: TableWidth;
1212
- borders?: TableCellBorders;
1213
- shading?: CellShading;
1214
- verticalAlign?: "top" | "center" | "bottom";
1213
+ readonly width?: TableWidth;
1214
+ readonly borders?: TableCellBorders;
1215
+ readonly shading?: CellShading;
1216
+ readonly verticalAlign?: "top" | "center" | "bottom";
1215
1217
  };
1216
1218
  /**
1217
1219
  * `<w:pPr>` directly inside the table style body — applies to every
1218
1220
  * cell paragraph by default. Conditional-region pPr (inside
1219
1221
  * `<w:tblStylePr>`) is not captured here; see Lane 3a follow-up.
1220
1222
  */
1221
- paragraphProperties?: CanonicalParagraphFormatting;
1223
+ readonly paragraphProperties?: CanonicalParagraphFormatting;
1222
1224
  /**
1223
1225
  * `<w:rPr>` directly inside the table style body — applies to every
1224
1226
  * run in every cell paragraph by default.
1225
1227
  */
1226
- runProperties?: CanonicalRunFormatting;
1228
+ readonly runProperties?: CanonicalRunFormatting;
1227
1229
  }
1228
1230
 
1229
1231
  export interface TableNode {
1230
- type: "table";
1231
- styleId?: string;
1232
+ readonly type: "table";
1233
+ readonly styleId?: string;
1232
1234
  /** @deprecated Use `unknownPropertyChildren`. Kept for snapshot back-compat. */
1233
- propertiesXml?: string;
1234
- unknownPropertyChildren?: UnknownPropertyChild[];
1235
- gridColumns: number[];
1236
- rows: TableRowNode[];
1237
- width?: TableWidth;
1238
- alignment?: "left" | "center" | "right";
1239
- borders?: TableBorders;
1240
- cellMargins?: TableCellMargins;
1241
- tblLook?: TableLook;
1242
- indent?: TableIndent;
1243
- layoutMode?: "fixed" | "autofit";
1244
- cellSpacing?: TableWidth;
1245
- caption?: string;
1246
- description?: string;
1247
- bidiVisual?: boolean;
1248
- floating?: TableFloatingProperties;
1235
+ readonly propertiesXml?: string;
1236
+ readonly unknownPropertyChildren?: UnknownPropertyChild[];
1237
+ readonly gridColumns: number[];
1238
+ readonly rows: TableRowNode[];
1239
+ readonly width?: TableWidth;
1240
+ readonly alignment?: "left" | "center" | "right";
1241
+ readonly borders?: TableBorders;
1242
+ readonly cellMargins?: TableCellMargins;
1243
+ readonly tblLook?: TableLook;
1244
+ readonly indent?: TableIndent;
1245
+ readonly layoutMode?: "fixed" | "autofit";
1246
+ readonly cellSpacing?: TableWidth;
1247
+ readonly caption?: string;
1248
+ readonly description?: string;
1249
+ readonly bidiVisual?: boolean;
1250
+ readonly floating?: TableFloatingProperties;
1249
1251
  }
1250
1252
 
1251
1253
  export interface TableRowNode {
1252
- type: "table_row";
1254
+ readonly type: "table_row";
1253
1255
  /** @deprecated Use `unknownPropertyChildren`. Kept for snapshot back-compat. */
1254
- propertiesXml?: string;
1255
- unknownPropertyChildren?: UnknownPropertyChild[];
1256
- cells: TableCellNode[];
1257
- gridBefore?: number;
1258
- widthBefore?: TableWidth;
1259
- gridAfter?: number;
1260
- widthAfter?: TableWidth;
1261
- height?: number;
1262
- heightRule?: "auto" | "atLeast" | "exact";
1263
- isHeader?: boolean;
1264
- cantSplit?: boolean;
1265
- horizontalAlignment?: "left" | "center" | "right";
1266
- cnfStyle?: string;
1256
+ readonly propertiesXml?: string;
1257
+ readonly unknownPropertyChildren?: UnknownPropertyChild[];
1258
+ readonly cells: TableCellNode[];
1259
+ readonly gridBefore?: number;
1260
+ readonly widthBefore?: TableWidth;
1261
+ readonly gridAfter?: number;
1262
+ readonly widthAfter?: TableWidth;
1263
+ readonly height?: number;
1264
+ readonly heightRule?: "auto" | "atLeast" | "exact";
1265
+ readonly isHeader?: boolean;
1266
+ readonly cantSplit?: boolean;
1267
+ readonly horizontalAlignment?: "left" | "center" | "right";
1268
+ readonly cnfStyle?: string;
1267
1269
  }
1268
1270
 
1269
1271
  export interface TableCellNode {
1270
- type: "table_cell";
1272
+ readonly type: "table_cell";
1271
1273
  /** @deprecated Use `unknownPropertyChildren`. Kept for snapshot back-compat. */
1272
- propertiesXml?: string;
1273
- unknownPropertyChildren?: UnknownPropertyChild[];
1274
- gridSpan?: number;
1275
- verticalMerge?: "restart" | "continue";
1276
- children: BlockNode[];
1277
- width?: TableWidth;
1278
- borders?: TableCellBorders;
1279
- shading?: CellShading;
1280
- verticalAlign?: "top" | "center" | "bottom";
1281
- textDirection?: "lrTb" | "tbRl" | "btLr";
1282
- noWrap?: boolean;
1283
- fitText?: boolean;
1284
- margins?: TableCellMargins;
1285
- cnfStyle?: string;
1274
+ readonly propertiesXml?: string;
1275
+ readonly unknownPropertyChildren?: UnknownPropertyChild[];
1276
+ readonly gridSpan?: number;
1277
+ readonly verticalMerge?: "restart" | "continue";
1278
+ readonly children: BlockNode[];
1279
+ readonly width?: TableWidth;
1280
+ readonly borders?: TableCellBorders;
1281
+ readonly shading?: CellShading;
1282
+ readonly verticalAlign?: "top" | "center" | "bottom";
1283
+ readonly textDirection?: "lrTb" | "tbRl" | "btLr";
1284
+ readonly noWrap?: boolean;
1285
+ readonly fitText?: boolean;
1286
+ readonly margins?: TableCellMargins;
1287
+ readonly cnfStyle?: string;
1286
1288
  }
1287
1289
 
1288
1290
  export interface SdtCheckboxState {
1289
- checked: boolean;
1290
- checkedChar?: string;
1291
- uncheckedChar?: string;
1291
+ readonly checked: boolean;
1292
+ readonly checkedChar?: string;
1293
+ readonly uncheckedChar?: string;
1292
1294
  }
1293
1295
 
1294
1296
  export interface SdtDatePickerState {
1295
- fullDate?: string;
1296
- dateFormat?: string;
1297
- lid?: string;
1297
+ readonly fullDate?: string;
1298
+ readonly dateFormat?: string;
1299
+ readonly lid?: string;
1298
1300
  }
1299
1301
 
1300
1302
  export interface SdtDropdownListItem {
1301
- displayText?: string;
1302
- value: string;
1303
+ readonly displayText?: string;
1304
+ readonly value: string;
1303
1305
  }
1304
1306
 
1305
1307
  export interface SdtNode {
1306
- type: "sdt";
1308
+ readonly type: "sdt";
1307
1309
  properties: {
1308
- sdtType?: string;
1309
- alias?: string;
1310
- tag?: string;
1311
- lock?: string;
1312
- propertiesXml?: string;
1313
- checkbox?: SdtCheckboxState;
1314
- datePicker?: SdtDatePickerState;
1315
- dropdownList?: SdtDropdownListItem[];
1316
- comboBox?: SdtDropdownListItem[];
1317
- showingPlcHdr?: boolean;
1310
+ readonly sdtType?: string;
1311
+ readonly alias?: string;
1312
+ readonly tag?: string;
1313
+ readonly lock?: string;
1314
+ readonly propertiesXml?: string;
1315
+ readonly checkbox?: SdtCheckboxState;
1316
+ readonly datePicker?: SdtDatePickerState;
1317
+ readonly dropdownList?: SdtDropdownListItem[];
1318
+ readonly comboBox?: SdtDropdownListItem[];
1319
+ readonly showingPlcHdr?: boolean;
1318
1320
  };
1319
- children: BlockNode[];
1321
+ readonly children: BlockNode[];
1320
1322
  }
1321
1323
 
1322
1324
  export interface CustomXmlNode {
1323
- type: "custom_xml";
1324
- uri?: string;
1325
- element?: string;
1326
- rawXml?: string;
1327
- children: BlockNode[];
1325
+ readonly type: "custom_xml";
1326
+ readonly uri?: string;
1327
+ readonly element?: string;
1328
+ readonly rawXml?: string;
1329
+ readonly children: BlockNode[];
1328
1330
  }
1329
1331
 
1330
1332
  export interface AltChunkNode {
1331
- type: "alt_chunk";
1332
- relationshipId: string;
1333
+ readonly type: "alt_chunk";
1334
+ readonly relationshipId: string;
1333
1335
  }
1334
1336
 
1335
1337
  /**
@@ -1377,53 +1379,53 @@ export type FieldRefreshStatus =
1377
1379
  | "preserve-only";
1378
1380
 
1379
1381
  export interface FieldNode {
1380
- type: "field";
1381
- fieldType: "simple" | "complex";
1382
- instruction: string;
1383
- children: InlineNode[];
1382
+ readonly type: "field";
1383
+ readonly fieldType: "simple" | "complex";
1384
+ readonly instruction: string;
1385
+ readonly children: InlineNode[];
1384
1386
  /** Classified field family. Undefined for legacy snapshots. */
1385
- fieldFamily?: FieldFamily;
1387
+ readonly fieldFamily?: FieldFamily;
1386
1388
  /** Target bookmark name for REF/PAGEREF/NOTEREF fields. */
1387
- fieldTarget?: string;
1389
+ readonly fieldTarget?: string;
1388
1390
  /** Runtime refresh status. Undefined for legacy or preserve-only fields. */
1389
- refreshStatus?: FieldRefreshStatus;
1391
+ readonly refreshStatus?: FieldRefreshStatus;
1390
1392
  /** Parsed field switches. Present only when the instruction contains recognized switches. */
1391
1393
  switches?: {
1392
- hyperlink?: boolean;
1393
- relativePosition?: boolean;
1394
- numericRef?: boolean;
1395
- recursive?: boolean;
1396
- suppressNonDelimiter?: boolean;
1397
- includeNumbering?: boolean;
1398
- includeLevel?: boolean;
1394
+ readonly hyperlink?: boolean;
1395
+ readonly relativePosition?: boolean;
1396
+ readonly numericRef?: boolean;
1397
+ readonly recursive?: boolean;
1398
+ readonly suppressNonDelimiter?: boolean;
1399
+ readonly includeNumbering?: boolean;
1400
+ readonly includeLevel?: boolean;
1399
1401
  };
1400
1402
  /** Legacy form-field metadata from w:ffData (textInput, checkBox, ddList). Round-trip only; no UI for MVP. */
1401
- legacyFormField?: LegacyFormFieldNode;
1403
+ readonly legacyFormField?: LegacyFormFieldNode;
1402
1404
  }
1403
1405
 
1404
1406
  export type LegacyFormFieldKind = "textInput" | "checkBox" | "ddList";
1405
1407
 
1406
1408
  export interface LegacyFormFieldNode {
1407
- kind: LegacyFormFieldKind;
1408
- name?: string;
1409
- enabled?: boolean;
1410
- calcOnExit?: boolean;
1409
+ readonly kind: LegacyFormFieldKind;
1410
+ readonly name?: string;
1411
+ readonly enabled?: boolean;
1412
+ readonly calcOnExit?: boolean;
1411
1413
  textInput?: {
1412
- default?: string;
1413
- maxLength?: number;
1414
- format?: string;
1414
+ readonly default?: string;
1415
+ readonly maxLength?: number;
1416
+ readonly format?: string;
1415
1417
  };
1416
1418
  checkBox?: {
1417
- size?: number;
1418
- default?: boolean;
1419
- checked?: boolean;
1419
+ readonly size?: number;
1420
+ readonly default?: boolean;
1421
+ readonly checked?: boolean;
1420
1422
  };
1421
1423
  ddList?: {
1422
- default?: number;
1423
- listEntry?: string[];
1424
+ readonly default?: number;
1425
+ readonly listEntry?: string[];
1424
1426
  };
1425
1427
  /** Verbatim <w:ffData>…</w:ffData> XML for lossless round-trip. */
1426
- rawXml: string;
1428
+ readonly rawXml: string;
1427
1429
  /**
1428
1430
  * Phase V.a: set to `true` when typed fields have been mutated via
1429
1431
  * `setLegacyFormFieldValue` since parse. On serialize, the `rawXml` is
@@ -1431,7 +1433,7 @@ export interface LegacyFormFieldNode {
1431
1433
  * Un-mutated nodes emit the preserved `rawXml` verbatim for lossless
1432
1434
  * round-trip.
1433
1435
  */
1434
- mutated?: boolean;
1436
+ readonly mutated?: boolean;
1435
1437
  }
1436
1438
 
1437
1439
  // ─── Field registry ─────────────────────────────────────────────────────────
@@ -1446,34 +1448,34 @@ export interface LegacyFormFieldNode {
1446
1448
  */
1447
1449
  export interface FieldRegistry {
1448
1450
  /** Supported field instances that participate in refresh. */
1449
- supported: FieldRegistryEntry[];
1451
+ readonly supported: FieldRegistryEntry[];
1450
1452
  /** Preserve-only field instances cataloged for round-trip safety. */
1451
- preserveOnly: FieldRegistryEntry[];
1453
+ readonly preserveOnly: FieldRegistryEntry[];
1452
1454
  /** First-class TOC regions, including cached field-result rows and generated heading rows. */
1453
- tocRegions?: TocRegion[];
1455
+ readonly tocRegions?: TocRegion[];
1454
1456
  /** Generated TOC structure extracted from heading-driven TOC fields. */
1455
- tocStructure?: TocStructure;
1457
+ readonly tocStructure?: TocStructure;
1456
1458
  }
1457
1459
 
1458
1460
  export interface FieldRegistryEntry {
1459
1461
  /** Stable document-order index of this field (0-based). */
1460
- fieldIndex: number;
1462
+ readonly fieldIndex: number;
1461
1463
  /** Classified field family. */
1462
- fieldFamily: FieldFamily;
1464
+ readonly fieldFamily: FieldFamily;
1463
1465
  /** Whether the field is in the supported refresh slice. */
1464
- supported: boolean;
1466
+ readonly supported: boolean;
1465
1467
  /** Field instruction text. */
1466
- instruction: string;
1468
+ readonly instruction: string;
1467
1469
  /** Target bookmark name for REF/PAGEREF/NOTEREF fields. */
1468
- fieldTarget?: string;
1470
+ readonly fieldTarget?: string;
1469
1471
  /** Current display text extracted from field content. */
1470
- displayText: string;
1472
+ readonly displayText: string;
1471
1473
  /** Paragraph index in document order where this field appears. */
1472
- paragraphIndex: number;
1474
+ readonly paragraphIndex: number;
1473
1475
  /** Runtime refresh status. */
1474
- refreshStatus: FieldRefreshStatus;
1476
+ readonly refreshStatus: FieldRefreshStatus;
1475
1477
  /** Parsed field switches carried from FieldNode.switches. Present only for REF/PAGEREF/NOTEREF/TOC entries with recognized switches. */
1476
- switches?: FieldNode["switches"];
1478
+ readonly switches?: FieldNode["switches"];
1477
1479
  }
1478
1480
 
1479
1481
  /**
@@ -1482,138 +1484,138 @@ export interface FieldRegistryEntry {
1482
1484
  */
1483
1485
  export interface TocStructure {
1484
1486
  /** The raw TOC field instruction (e.g. "TOC \\o \"1-3\" \\h"). */
1485
- instruction: string;
1487
+ readonly instruction: string;
1486
1488
  /** Heading level range the TOC covers. */
1487
- levelRange: { from: number; to: number };
1489
+ readonly levelRange: { from: number; to: number };
1488
1490
  /** Ordered TOC entries derived from heading paragraphs. */
1489
- entries: TocEntry[];
1491
+ readonly entries: TocEntry[];
1490
1492
  /** Whether the TOC content is current with the heading structure. */
1491
- status: "current" | "stale";
1493
+ readonly status: "current" | "stale";
1492
1494
  }
1493
1495
 
1494
1496
  export interface TocInstructionModel {
1495
1497
  /** The raw TOC field instruction (e.g. "TOC \\o \"1-3\" \\h"). */
1496
- raw: string;
1498
+ readonly raw: string;
1497
1499
  /** Heading level range selected by \\o, or defaulted to 1-9. */
1498
- outlineRange: { from: number; to: number };
1500
+ readonly outlineRange: { from: number; to: number };
1499
1501
  /** \\h — result entries should hyperlink to their anchors. */
1500
- hyperlink?: boolean;
1502
+ readonly hyperlink?: boolean;
1501
1503
  /** \\z — hide tab leader and page numbers in web layout. */
1502
- hidePageNumbersInWeb?: boolean;
1504
+ readonly hidePageNumbersInWeb?: boolean;
1503
1505
  /** \\u — include paragraphs with outline levels. */
1504
- useOutlineLevels?: boolean;
1506
+ readonly useOutlineLevels?: boolean;
1505
1507
  /** \\t "Style,Level,..." — style-driven TOC mapping. */
1506
- styleMap?: TocStyleMapEntry[];
1508
+ readonly styleMap?: TocStyleMapEntry[];
1507
1509
  /** \\b bookmark — bound source content to a bookmark. */
1508
- bookmarkName?: string;
1510
+ readonly bookmarkName?: string;
1509
1511
  /** \\c identifier — table-of-figures / sequence identifier. */
1510
- sequenceIdentifier?: string;
1512
+ readonly sequenceIdentifier?: string;
1511
1513
  /** \\f identifier — TC-entry identifier. */
1512
- tcIdentifier?: string;
1514
+ readonly tcIdentifier?: string;
1513
1515
  /** \\p separator — custom entry/page separator. */
1514
- entryPageSeparator?: string;
1516
+ readonly entryPageSeparator?: string;
1515
1517
  /** \\d separator — custom sequence separator. */
1516
- sequenceSeparator?: string;
1518
+ readonly sequenceSeparator?: string;
1517
1519
  /** \\n optional range — omit page numbers. */
1518
- omitPageNumbers?: true | { from: number; to: number };
1520
+ readonly omitPageNumbers?: true | { from: number; to: number };
1519
1521
  /** Switches parsed but not yet semantically implemented. */
1520
- unsupportedSwitches?: string[];
1522
+ readonly unsupportedSwitches?: string[];
1521
1523
  }
1522
1524
 
1523
1525
  export interface TocStyleMapEntry {
1524
- styleName: string;
1525
- level: number;
1526
+ readonly styleName: string;
1527
+ readonly level: number;
1526
1528
  }
1527
1529
 
1528
1530
  export interface TocCachedEntry {
1529
1531
  /** Text extracted from the cached field-result row before the page-number tab. */
1530
- text: string;
1532
+ readonly text: string;
1531
1533
  /** TOC level inferred from TOC1/TOC2/etc. paragraph style. */
1532
- level: number;
1534
+ readonly level: number;
1533
1535
  /** Paragraph index of the cached result row in document order. */
1534
- paragraphIndex: number;
1536
+ readonly paragraphIndex: number;
1535
1537
  /** Style ID of the cached result paragraph, if available. */
1536
- styleId?: string;
1538
+ readonly styleId?: string;
1537
1539
  /** Bookmark/hyperlink anchor used by the cached result row, if present. */
1538
- bookmarkName?: string;
1540
+ readonly bookmarkName?: string;
1539
1541
  /** Page label extracted from the cached field result. */
1540
- pageText?: string;
1542
+ readonly pageText?: string;
1541
1543
  /** Full visible row text, including tabs/page labels. */
1542
- displayText: string;
1544
+ readonly displayText: string;
1543
1545
  }
1544
1546
 
1545
1547
  export interface TocRegion {
1546
1548
  /** Stable document-order id for this imported TOC region. */
1547
- tocId: string;
1549
+ readonly tocId: string;
1548
1550
  /** Source TOC field index in FieldRegistry.supported. */
1549
- sourceFieldIndex: number;
1551
+ readonly sourceFieldIndex: number;
1550
1552
  /** Parsed instruction metadata and switches. */
1551
- instruction: TocInstructionModel;
1553
+ readonly instruction: TocInstructionModel;
1552
1554
  /** Inclusive paragraph range containing the cached/generated result rows. */
1553
- resultRange: { fromParagraphIndex: number; toParagraphIndex: number };
1555
+ readonly resultRange: { fromParagraphIndex: number; toParagraphIndex: number };
1554
1556
  /** Parent container kind where the region was found. */
1555
- parentKind: "body" | "sdt" | "custom_xml" | "table_cell";
1557
+ readonly parentKind: "body" | "sdt" | "custom_xml" | "table_cell";
1556
1558
  /** Structural path to the parent block sequence, for diagnostics. */
1557
- sourcePath: string;
1559
+ readonly sourcePath: string;
1558
1560
  /** Cached rows imported from the DOCX field result. */
1559
- cachedEntries: TocCachedEntry[];
1561
+ readonly cachedEntries: TocCachedEntry[];
1560
1562
  /** Heading-derived rows generated from the canonical document. */
1561
- generatedEntries: TocEntry[];
1563
+ readonly generatedEntries: TocEntry[];
1562
1564
  /** Whether cached entries match the generated heading model. */
1563
- status: "current" | "stale";
1565
+ readonly status: "current" | "stale";
1564
1566
  }
1565
1567
 
1566
1568
  export interface TocEntry {
1567
1569
  /** Heading text. */
1568
- text: string;
1570
+ readonly text: string;
1569
1571
  /** Heading outline level (1-9). */
1570
- level: number;
1572
+ readonly level: number;
1571
1573
  /** Paragraph index of the heading in document order. */
1572
- paragraphIndex: number;
1574
+ readonly paragraphIndex: number;
1573
1575
  /** Style ID of the heading paragraph, if available. */
1574
- styleId?: string;
1576
+ readonly styleId?: string;
1575
1577
  /** Bookmark name anchoring this heading, if present. */
1576
- bookmarkName?: string;
1578
+ readonly bookmarkName?: string;
1577
1579
  }
1578
1580
 
1579
1581
  export interface BookmarkStartNode {
1580
- type: "bookmark_start";
1581
- bookmarkId: string;
1582
- name: string;
1582
+ readonly type: "bookmark_start";
1583
+ readonly bookmarkId: string;
1584
+ readonly name: string;
1583
1585
  }
1584
1586
 
1585
1587
  export interface BookmarkEndNode {
1586
- type: "bookmark_end";
1587
- bookmarkId: string;
1588
+ readonly type: "bookmark_end";
1589
+ readonly bookmarkId: string;
1588
1590
  }
1589
1591
 
1590
1592
  export interface SectionBreakNode {
1591
- type: "section_break";
1592
- sectionPropertiesXml?: string;
1593
+ readonly type: "section_break";
1594
+ readonly sectionPropertiesXml?: string;
1593
1595
  /**
1594
1596
  * @deprecated Legacy field from older snapshots. New exports should use
1595
1597
  * sectionPropertiesXml and only contain raw <w:sectPr> content.
1596
1598
  */
1597
- propertiesXml?: string;
1598
- sectionProperties?: SectionProperties;
1599
+ readonly propertiesXml?: string;
1600
+ readonly sectionProperties?: SectionProperties;
1599
1601
  }
1600
1602
 
1601
1603
  export interface SectionProperties {
1602
- pageSize?: PageSize;
1603
- pageMargins?: PageMargins;
1604
- columns?: ColumnProperties;
1605
- pageNumbering?: PageNumbering;
1606
- lineNumbering?: SectionLineNumbering;
1607
- pageBorders?: SectionPageBorders;
1608
- documentGrid?: SectionDocumentGrid;
1609
- headerReferences?: HeaderFooterReference[];
1610
- footerReferences?: HeaderFooterReference[];
1611
- sectionType?: "continuous" | "nextPage" | "evenPage" | "oddPage" | "nextColumn";
1612
- titlePage?: boolean;
1604
+ readonly pageSize?: PageSize;
1605
+ readonly pageMargins?: PageMargins;
1606
+ readonly columns?: ColumnProperties;
1607
+ readonly pageNumbering?: PageNumbering;
1608
+ readonly lineNumbering?: SectionLineNumbering;
1609
+ readonly pageBorders?: SectionPageBorders;
1610
+ readonly documentGrid?: SectionDocumentGrid;
1611
+ readonly headerReferences?: HeaderFooterReference[];
1612
+ readonly footerReferences?: HeaderFooterReference[];
1613
+ readonly sectionType?: "continuous" | "nextPage" | "evenPage" | "oddPage" | "nextColumn";
1614
+ readonly titlePage?: boolean;
1613
1615
  /** Per-section footnote configuration (ECMA-376 §17.11.12). Overrides file-level defaults. */
1614
- footnotePr?: FootnoteProperties;
1616
+ readonly footnotePr?: FootnoteProperties;
1615
1617
  /** Per-section endnote configuration (ECMA-376 §17.11.4). Overrides file-level defaults. */
1616
- endnotePr?: EndnoteProperties;
1618
+ readonly endnotePr?: EndnoteProperties;
1617
1619
  /**
1618
1620
  * Unmodelled direct children of `<w:sectPr>` captured verbatim for
1619
1621
  * round-trip. Mirrors `CanonicalParagraphFormatting.unknownPropertyChildren`
@@ -1622,7 +1624,7 @@ export interface SectionProperties {
1622
1624
  * `<w15:footnoteColumns>` and Word-internal section knobs through a
1623
1625
  * parse→serialize round-trip when the runtime mutates section properties.
1624
1626
  */
1625
- unknownPropertyChildren?: UnknownPropertyChild[];
1627
+ readonly unknownPropertyChildren?: UnknownPropertyChild[];
1626
1628
  }
1627
1629
 
1628
1630
  /**
@@ -1641,13 +1643,13 @@ export interface SectionProperties {
1641
1643
  * counterpart; `EndnoteProperties` aliases this shape.
1642
1644
  */
1643
1645
  export interface FootnoteProperties {
1644
- pos?: "pageBottom" | "beneathText" | "sectEnd" | "docEnd";
1646
+ readonly pos?: "pageBottom" | "beneathText" | "sectEnd" | "docEnd";
1645
1647
  numFmt?: "decimal" | "upperRoman" | "lowerRoman" | "upperLetter" | "lowerLetter"
1646
1648
  | "ordinal" | "cardinalText" | "ordinalText" | "hex" | "chicago" | "bullet"
1647
1649
  | "ideographDigital" | "japaneseCounting" | "arabicAbjad" | "arabicAlpha"
1648
1650
  | "none";
1649
- numStart?: number;
1650
- numRestart?: "continuous" | "eachSect" | "eachPage";
1651
+ readonly numStart?: number;
1652
+ readonly numRestart?: "continuous" | "eachSect" | "eachPage";
1651
1653
  }
1652
1654
 
1653
1655
  /**
@@ -1658,62 +1660,62 @@ export interface FootnoteProperties {
1658
1660
  export type EndnoteProperties = FootnoteProperties;
1659
1661
 
1660
1662
  export interface PageSize {
1661
- width: number;
1662
- height: number;
1663
- orientation?: "portrait" | "landscape";
1663
+ readonly width: number;
1664
+ readonly height: number;
1665
+ readonly orientation?: "portrait" | "landscape";
1664
1666
  }
1665
1667
 
1666
1668
  export interface PageMargins {
1667
- top: number;
1668
- right: number;
1669
- bottom: number;
1670
- left: number;
1671
- header?: number;
1672
- footer?: number;
1673
- gutter?: number;
1669
+ readonly top: number;
1670
+ readonly right: number;
1671
+ readonly bottom: number;
1672
+ readonly left: number;
1673
+ readonly header?: number;
1674
+ readonly footer?: number;
1675
+ readonly gutter?: number;
1674
1676
  }
1675
1677
 
1676
1678
  export interface ColumnProperties {
1677
- count?: number;
1678
- space?: number;
1679
- equalWidth?: boolean;
1680
- columns?: Array<{ width: number; space?: number }>;
1681
- separator?: boolean;
1679
+ readonly count?: number;
1680
+ readonly space?: number;
1681
+ readonly equalWidth?: boolean;
1682
+ readonly columns?: Array<{ width: number; space?: number }>;
1683
+ readonly separator?: boolean;
1682
1684
  }
1683
1685
 
1684
1686
  export interface PageNumbering {
1685
- format?: string;
1686
- start?: number;
1687
- chapStyle?: string;
1688
- chapSep?: string;
1687
+ readonly format?: string;
1688
+ readonly start?: number;
1689
+ readonly chapStyle?: string;
1690
+ readonly chapSep?: string;
1689
1691
  }
1690
1692
 
1691
1693
  export interface SectionLineNumbering {
1692
- countBy?: number;
1693
- start?: number;
1694
- distance?: number;
1695
- restart?: "newPage" | "newSection" | "continuous";
1694
+ readonly countBy?: number;
1695
+ readonly start?: number;
1696
+ readonly distance?: number;
1697
+ readonly restart?: "newPage" | "newSection" | "continuous";
1696
1698
  }
1697
1699
 
1698
1700
  export interface SectionPageBorders {
1699
- top?: BorderSpec;
1700
- left?: BorderSpec;
1701
- bottom?: BorderSpec;
1702
- right?: BorderSpec;
1703
- offsetFrom?: "page" | "text";
1704
- display?: "allPages" | "firstPage" | "notFirstPage";
1705
- zOrder?: "front" | "back";
1701
+ readonly top?: BorderSpec;
1702
+ readonly left?: BorderSpec;
1703
+ readonly bottom?: BorderSpec;
1704
+ readonly right?: BorderSpec;
1705
+ readonly offsetFrom?: "page" | "text";
1706
+ readonly display?: "allPages" | "firstPage" | "notFirstPage";
1707
+ readonly zOrder?: "front" | "back";
1706
1708
  }
1707
1709
 
1708
1710
  export interface SectionDocumentGrid {
1709
- type?: "default" | "lines" | "linesAndChars" | "snapToChars";
1710
- linePitch?: number;
1711
- charSpace?: number;
1711
+ readonly type?: "default" | "lines" | "linesAndChars" | "snapToChars";
1712
+ readonly linePitch?: number;
1713
+ readonly charSpace?: number;
1712
1714
  }
1713
1715
 
1714
1716
  export interface HeaderFooterReference {
1715
- variant: HeaderFooterVariant;
1716
- relationshipId: string;
1717
+ readonly variant: HeaderFooterVariant;
1718
+ readonly relationshipId: string;
1717
1719
  }
1718
1720
 
1719
1721
  export type InlineNode =
@@ -1741,9 +1743,9 @@ export type InlineNode =
1741
1743
  | OleEmbedNode;
1742
1744
 
1743
1745
  export interface TextNode {
1744
- type: "text";
1745
- text: string;
1746
- marks?: TextMark[];
1746
+ readonly type: "text";
1747
+ readonly text: string;
1748
+ readonly marks?: TextMark[];
1747
1749
  }
1748
1750
 
1749
1751
  export type TextMark =
@@ -1770,11 +1772,11 @@ export type TextMark =
1770
1772
  | { type: "allCaps" };
1771
1773
 
1772
1774
  export interface HardBreakNode {
1773
- type: "hard_break";
1775
+ readonly type: "hard_break";
1774
1776
  }
1775
1777
 
1776
1778
  export interface ColumnBreakNode {
1777
- type: "column_break";
1779
+ readonly type: "column_break";
1778
1780
  }
1779
1781
 
1780
1782
  /**
@@ -1792,54 +1794,54 @@ export interface ColumnBreakNode {
1792
1794
  * section properties; `PageBreakNode` is inline inside a run.
1793
1795
  */
1794
1796
  export interface PageBreakNode {
1795
- type: "page_break";
1797
+ readonly type: "page_break";
1796
1798
  }
1797
1799
 
1798
1800
  export interface TabNode {
1799
- type: "tab";
1801
+ readonly type: "tab";
1800
1802
  }
1801
1803
 
1802
1804
  export interface SymbolNode {
1803
- type: "symbol";
1804
- char: string;
1805
- font?: string;
1806
- marks?: TextMark[];
1805
+ readonly type: "symbol";
1806
+ readonly char: string;
1807
+ readonly font?: string;
1808
+ readonly marks?: TextMark[];
1807
1809
  }
1808
1810
 
1809
1811
  export interface HyperlinkNode {
1810
- type: "hyperlink";
1811
- href: string;
1812
- children: Array<TextNode | HardBreakNode | ColumnBreakNode | PageBreakNode | TabNode | SymbolNode>;
1812
+ readonly type: "hyperlink";
1813
+ readonly href: string;
1814
+ readonly children: Array<TextNode | HardBreakNode | ColumnBreakNode | PageBreakNode | TabNode | SymbolNode>;
1813
1815
  }
1814
1816
 
1815
1817
  export interface ImageNode {
1816
- type: "image";
1817
- mediaId: string;
1818
- altText?: string;
1819
- placementXml?: string;
1820
- display?: "inline" | "floating";
1821
- floating?: FloatingImageProperties;
1818
+ readonly type: "image";
1819
+ readonly mediaId: string;
1820
+ readonly altText?: string;
1821
+ readonly placementXml?: string;
1822
+ readonly display?: "inline" | "floating";
1823
+ readonly floating?: FloatingImageProperties;
1822
1824
  }
1823
1825
 
1824
1826
  export interface FloatingImageProperties {
1825
- horizontalPosition?: FloatingAxisPosition;
1826
- verticalPosition?: FloatingAxisPosition;
1827
- wrap?: "none" | "square" | "tight" | "through" | "topAndBottom";
1828
- behindDoc?: boolean;
1829
- layoutInCell?: boolean;
1830
- allowOverlap?: boolean;
1827
+ readonly horizontalPosition?: FloatingAxisPosition;
1828
+ readonly verticalPosition?: FloatingAxisPosition;
1829
+ readonly wrap?: "none" | "square" | "tight" | "through" | "topAndBottom";
1830
+ readonly behindDoc?: boolean;
1831
+ readonly layoutInCell?: boolean;
1832
+ readonly allowOverlap?: boolean;
1831
1833
  }
1832
1834
 
1833
1835
  export interface FloatingAxisPosition {
1834
- relativeFrom?: string;
1835
- align?: string;
1836
- offset?: number;
1836
+ readonly relativeFrom?: string;
1837
+ readonly align?: string;
1838
+ readonly offset?: number;
1837
1839
  }
1838
1840
 
1839
1841
  export interface OpaqueInlineNode {
1840
- type: "opaque_inline";
1841
- fragmentId: string;
1842
- warningId: string;
1842
+ readonly type: "opaque_inline";
1843
+ readonly fragmentId: string;
1844
+ readonly warningId: string;
1843
1845
  }
1844
1846
 
1845
1847
  // ---- Complex rendering inline nodes (read-only previews) ----
@@ -1850,8 +1852,8 @@ export interface OpaqueInlineNode {
1850
1852
  * mc:AlternateContent it is referenced by previewMediaId.
1851
1853
  */
1852
1854
  export interface ChartPreviewNode {
1853
- type: "chart_preview";
1854
- previewMediaId?: string;
1855
+ readonly type: "chart_preview";
1856
+ readonly previewMediaId?: string;
1855
1857
  /**
1856
1858
  * Typed chart data model parsed from the `c:chartSpace` part, when
1857
1859
  * available. Populated at import time by the Stage 1 chart parser
@@ -1869,7 +1871,7 @@ export interface ChartPreviewNode {
1869
1871
  * `parsedData` in place.
1870
1872
  */
1871
1873
  readonly parsedData?: ChartModel;
1872
- rawXml: string;
1874
+ readonly rawXml: string;
1873
1875
  }
1874
1876
 
1875
1877
  /**
@@ -1877,9 +1879,9 @@ export interface ChartPreviewNode {
1877
1879
  * stored in rawXml for lossless round-trip export.
1878
1880
  */
1879
1881
  export interface SmartArtPreviewNode {
1880
- type: "smartart_preview";
1881
- previewMediaId?: string;
1882
- rawXml: string;
1882
+ readonly type: "smartart_preview";
1883
+ readonly previewMediaId?: string;
1884
+ readonly rawXml: string;
1883
1885
  }
1884
1886
 
1885
1887
  /**
@@ -1894,14 +1896,14 @@ export interface SmartArtPreviewNode {
1894
1896
  * runtime contract was confirmed canonical).
1895
1897
  */
1896
1898
  export interface ShapeNode {
1897
- type: "shape";
1898
- text?: string;
1899
- geometry?: string;
1900
- isTextBox?: boolean;
1899
+ readonly type: "shape";
1900
+ readonly text?: string;
1901
+ readonly geometry?: string;
1902
+ readonly isTextBox?: boolean;
1901
1903
  /** Text box body layout from `wps:bodyPr` / `a:bodyPr`. */
1902
- textBoxBody?: TextBoxBodyProperties;
1904
+ readonly textBoxBody?: TextBoxBodyProperties;
1903
1905
  /** Raw `<w:txbxContent>` XML, preserved for serialization + round-trip. */
1904
- txbxContentXml?: string;
1906
+ readonly txbxContentXml?: string;
1905
1907
  /**
1906
1908
  * Parsed canonical block-level structure from `<w:txbxContent>`,
1907
1909
  * populated when the parse path supplies a `blockParser` callback
@@ -1909,8 +1911,8 @@ export interface ShapeNode {
1909
1911
  * body via `src/io/ooxml/parse-main-document.ts`). Shape + semantics
1910
1912
  * identical to `ShapeContent.txbxBlocks` on the drawing-frame path.
1911
1913
  */
1912
- txbxBlocks?: ReadonlyArray<BlockNode>;
1913
- rawXml: string;
1914
+ readonly txbxBlocks?: BlockNode[];
1915
+ readonly rawXml: string;
1914
1916
  }
1915
1917
 
1916
1918
  /**
@@ -1918,10 +1920,10 @@ export interface ShapeNode {
1918
1920
  * Text is extracted for display. The original drawing XML is preserved in rawXml.
1919
1921
  */
1920
1922
  export interface WordArtNode {
1921
- type: "wordart";
1922
- text: string;
1923
- geometry?: string;
1924
- rawXml: string;
1923
+ readonly type: "wordart";
1924
+ readonly text: string;
1925
+ readonly geometry?: string;
1926
+ readonly rawXml: string;
1925
1927
  }
1926
1928
 
1927
1929
  /**
@@ -1930,10 +1932,10 @@ export interface WordArtNode {
1930
1932
  * in rawXml for lossless round-trip export.
1931
1933
  */
1932
1934
  export interface VmlShapeNode {
1933
- type: "vml_shape";
1934
- text?: string;
1935
- shapeType?: string;
1936
- rawXml: string;
1935
+ readonly type: "vml_shape";
1936
+ readonly text?: string;
1937
+ readonly shapeType?: string;
1938
+ readonly rawXml: string;
1937
1939
  }
1938
1940
 
1939
1941
  /**
@@ -1956,111 +1958,111 @@ export interface VmlShapeNode {
1956
1958
  * through when `<o:OLEObject>` is absent.
1957
1959
  */
1958
1960
  export interface OleEmbedNode {
1959
- type: "ole_embed";
1960
- id: string;
1961
- progId?: string;
1962
- embedType: "oleObject";
1963
- relationshipId: string;
1961
+ readonly type: "ole_embed";
1962
+ readonly id: string;
1963
+ readonly progId?: string;
1964
+ readonly embedType: "oleObject";
1965
+ readonly relationshipId: string;
1964
1966
  metadata: {
1965
- originalFilename?: string;
1966
- classId?: string;
1967
- shapeId?: string;
1967
+ readonly originalFilename?: string;
1968
+ readonly classId?: string;
1969
+ readonly shapeId?: string;
1968
1970
  };
1969
- rawXml: string;
1971
+ readonly rawXml: string;
1970
1972
  }
1971
1973
 
1972
1974
  export interface AnchorGeometry {
1973
- display: "inline" | "floating";
1974
- extent: { widthEmu: number; heightEmu: number };
1975
- wrapMode: "none" | "square" | "tight" | "through" | "topAndBottom";
1975
+ readonly display: "inline" | "floating";
1976
+ readonly extent: { widthEmu: number; heightEmu: number };
1977
+ readonly wrapMode: "none" | "square" | "tight" | "through" | "topAndBottom";
1976
1978
  /**
1977
1979
  * Polygon coords (in OOXML's 21600ths-of-image units) when wrapMode is
1978
1980
  * "tight" or "through" and `wp:wrapPolygon` is present. First point from
1979
1981
  * `wp:start`; subsequent points from sequential `wp:lineTo`. Consumed by
1980
1982
  * Lane 6 P7 float-wrap for proper polygon text flow.
1981
1983
  */
1982
- wrapPolygon?: Array<{ x: number; y: number }>;
1983
- positionH?: { relativeFrom: string; align?: string; offset?: number };
1984
- positionV?: { relativeFrom: string; align?: string; offset?: number };
1985
- distMargins?: { top?: number; bottom?: number; left?: number; right?: number };
1986
- relativeHeight?: number;
1987
- behindDoc?: boolean;
1988
- layoutInCell?: boolean;
1989
- allowOverlap?: boolean;
1990
- simplePos?: boolean;
1984
+ readonly wrapPolygon?: Array<{ x: number; y: number }>;
1985
+ readonly positionH?: { relativeFrom: string; align?: string; offset?: number };
1986
+ readonly positionV?: { relativeFrom: string; align?: string; offset?: number };
1987
+ readonly distMargins?: { top?: number; bottom?: number; left?: number; right?: number };
1988
+ readonly relativeHeight?: number;
1989
+ readonly behindDoc?: boolean;
1990
+ readonly layoutInCell?: boolean;
1991
+ readonly allowOverlap?: boolean;
1992
+ readonly simplePos?: boolean;
1991
1993
  docPr?: {
1992
- id: string;
1993
- name?: string;
1994
- descr?: string;
1994
+ readonly id: string;
1995
+ readonly name?: string;
1996
+ readonly descr?: string;
1995
1997
  /** `wp:docPr hidden="1"` — Word UI hides the frame from the user. */
1996
- hidden?: boolean;
1998
+ readonly hidden?: boolean;
1997
1999
  };
1998
2000
  /**
1999
2001
  * `wp:cNvGraphicFramePr/a:graphicFrameLocks` — object-manipulation locks
2000
2002
  * consumed by Lane 6 object chrome (disable resize handles / move, etc.).
2001
2003
  */
2002
2004
  frameLocks?: {
2003
- noChangeAspect?: boolean;
2004
- noResize?: boolean;
2005
- noMove?: boolean;
2006
- noRot?: boolean;
2007
- noSelect?: boolean;
2008
- noGrp?: boolean;
2005
+ readonly noChangeAspect?: boolean;
2006
+ readonly noResize?: boolean;
2007
+ readonly noMove?: boolean;
2008
+ readonly noRot?: boolean;
2009
+ readonly noSelect?: boolean;
2010
+ readonly noGrp?: boolean;
2009
2011
  };
2010
2012
  }
2011
2013
 
2012
2014
  export interface PictureContent {
2013
- type: "picture";
2014
- blipRef: string;
2015
+ readonly type: "picture";
2016
+ readonly blipRef: string;
2015
2017
  /**
2016
2018
  * Phase 4.4 G4 — true when the image references an external URL via
2017
2019
  * `a:blip r:link` (bytes not in the .docx package) rather than embedded
2018
2020
  * via `r:embed`. External-linked images can't resolve to mediaId;
2019
2021
  * `state: "missing"` in surface projection.
2020
2022
  */
2021
- isLinked?: boolean;
2023
+ readonly isLinked?: boolean;
2022
2024
  /** Resolved media catalog ID (e.g. "media:word/media/image1.png"), populated by parse-drawing. */
2023
- mediaId?: string;
2025
+ readonly mediaId?: string;
2024
2026
  /** Absolute package path for media catalog lookup. */
2025
- packagePartName?: string;
2027
+ readonly packagePartName?: string;
2026
2028
  /** MIME resolved from the OPC media part, when known. */
2027
- contentType?: string;
2029
+ readonly contentType?: string;
2028
2030
  /** DrawingML a:lum brightness/contrast adjustments on the blip. Values are OOXML fixed percentages. */
2029
- lum?: { bright?: number; contrast?: number };
2030
- srcRect?: { top: number; bottom: number; left: number; right: number };
2031
- stretch?: boolean;
2031
+ readonly lum?: { bright?: number; contrast?: number };
2032
+ readonly srcRect?: { top: number; bottom: number; left: number; right: number };
2033
+ readonly stretch?: boolean;
2032
2034
  /**
2033
2035
  * Phase 4.5 G7 — `pic:blipFill/a:tile` (tiled image repeat). Mutually
2034
2036
  * exclusive with `stretch`. tx/ty = offset (EMUs), sx/sy = scale ×1000,
2035
2037
  * flip = "x"|"y"|"xy", algn = alignment token.
2036
2038
  */
2037
2039
  tile?: {
2038
- tx?: number;
2039
- ty?: number;
2040
- sx?: number;
2041
- sy?: number;
2042
- flip?: "x" | "y" | "xy";
2043
- algn?: string;
2040
+ readonly tx?: number;
2041
+ readonly ty?: number;
2042
+ readonly sx?: number;
2043
+ readonly sy?: number;
2044
+ readonly flip?: "x" | "y" | "xy";
2045
+ readonly algn?: string;
2044
2046
  };
2045
- rotation?: number;
2046
- flipH?: boolean;
2047
- flipV?: boolean;
2048
- presetGeom?: string;
2047
+ readonly rotation?: number;
2048
+ readonly flipH?: boolean;
2049
+ readonly flipV?: boolean;
2050
+ readonly presetGeom?: string;
2049
2051
  /** N11.b — DrawingML a:softEdge feather radius in EMU. */
2050
- softEdgeRadius?: number;
2052
+ readonly softEdgeRadius?: number;
2051
2053
  /** N11.b — DrawingML a:outerShdw attributes. `dir` is in 60000ths of a degree; `blurRad`/`dist` in EMU. */
2052
- outerShadow?: { blurRad: number; dist: number; dir: number; color: string; colorType: "srgbClr" | "schemeClr" };
2054
+ readonly outerShadow?: { blurRad: number; dist: number; dir: number; color: string; colorType: "srgbClr" | "schemeClr" };
2053
2055
  /** N11.b — DrawingML a:glow radius in EMU + color. */
2054
- glow?: { radius: number; color: string; colorType: "srgbClr" | "schemeClr" };
2056
+ readonly glow?: { radius: number; color: string; colorType: "srgbClr" | "schemeClr" };
2055
2057
  /** Original w:drawing XML slice, preserved for lossless round-trip serialization. */
2056
- rawXml?: string;
2058
+ readonly rawXml?: string;
2057
2059
  }
2058
2060
 
2059
2061
  export interface ShapeContent {
2060
- type: "shape";
2062
+ readonly type: "shape";
2061
2063
  /** Plain-text fallback extracted from `w:txbxContent` when present. */
2062
- text?: string;
2063
- geometry?: string;
2064
+ readonly text?: string;
2065
+ readonly geometry?: string;
2064
2066
  /**
2065
2067
  * Shape fill — solid, gradient, pattern, or none. srgbClr values on solid +
2066
2068
  * gradient stops + pattern fg/bg are normalized to uppercase hex. schemeClr
@@ -2073,26 +2075,26 @@ export interface ShapeContent {
2073
2075
  | { kind: "solid"; color: string; colorType: "srgbClr" | "schemeClr" }
2074
2076
  | { kind: "none" }
2075
2077
  | {
2076
- kind: "gradient";
2077
- stops: Array<{ pos: number; color: string; colorType: "srgbClr" | "schemeClr" }>;
2078
+ readonly kind: "gradient";
2079
+ readonly stops: Array<{ pos: number; color: string; colorType: "srgbClr" | "schemeClr" }>;
2078
2080
  direction:
2079
2081
  | { kind: "linear"; angle: number; scaled?: boolean }
2080
2082
  | { kind: "path"; path: "circle" | "rect" | "shape" };
2081
- rotWithShape?: boolean;
2083
+ readonly rotWithShape?: boolean;
2082
2084
  }
2083
2085
  | {
2084
- kind: "pattern";
2085
- preset: string;
2086
- fg?: { color: string; colorType: "srgbClr" | "schemeClr" };
2087
- bg?: { color: string; colorType: "srgbClr" | "schemeClr" };
2086
+ readonly kind: "pattern";
2087
+ readonly preset: string;
2088
+ readonly fg?: { color: string; colorType: "srgbClr" | "schemeClr" };
2089
+ readonly bg?: { color: string; colorType: "srgbClr" | "schemeClr" };
2088
2090
  };
2089
- line?: { color?: string; widthEmu?: number; noLine?: boolean };
2091
+ readonly line?: { color?: string; widthEmu?: number; noLine?: boolean };
2090
2092
  /** True when the shape's geometry + txbxContent presence make it a text box. */
2091
- isTextBox?: boolean;
2093
+ readonly isTextBox?: boolean;
2092
2094
  /** Text box body layout from `wps:bodyPr` / `a:bodyPr`. */
2093
- textBoxBody?: TextBoxBodyProperties;
2095
+ readonly textBoxBody?: TextBoxBodyProperties;
2094
2096
  /** Raw w:txbxContent XML, preserved for serialization + lossless round-trip. */
2095
- txbxContentXml?: string;
2097
+ readonly txbxContentXml?: string;
2096
2098
  /**
2097
2099
  * Parsed block-level structure from `w:txbxContent`, populated when a
2098
2100
  * `blockParser` callback is supplied during parse (CO4 F3.3).
@@ -2106,22 +2108,22 @@ export interface ShapeContent {
2106
2108
  * contract — unblocks L03 cascade + L11 render walking `txbxBlocks`
2107
2109
  * without `as unknown as BlockNode[]` casts at the consumer site.
2108
2110
  */
2109
- txbxBlocks?: ReadonlyArray<BlockNode>;
2110
- rawXml: string;
2111
+ readonly txbxBlocks?: BlockNode[];
2112
+ readonly rawXml: string;
2111
2113
  }
2112
2114
 
2113
2115
  export interface TextBoxBodyProperties {
2114
2116
  /** OOXML bodyPr anchor: top, center, or bottom. */
2115
- anchor?: "t" | "ctr" | "b";
2116
- insetLeftEmu?: number;
2117
- insetTopEmu?: number;
2118
- insetRightEmu?: number;
2119
- insetBottomEmu?: number;
2117
+ readonly anchor?: "t" | "ctr" | "b";
2118
+ readonly insetLeftEmu?: number;
2119
+ readonly insetTopEmu?: number;
2120
+ readonly insetRightEmu?: number;
2121
+ readonly insetBottomEmu?: number;
2120
2122
  }
2121
2123
 
2122
2124
  export interface DrawingFrameNode {
2123
- type: "drawing_frame";
2124
- anchor: AnchorGeometry;
2125
+ readonly type: "drawing_frame";
2126
+ readonly anchor: AnchorGeometry;
2125
2127
  content:
2126
2128
  | PictureContent
2127
2129
  | ShapeContent
@@ -2131,20 +2133,20 @@ export interface DrawingFrameNode {
2131
2133
  }
2132
2134
 
2133
2135
  export interface OpaqueBlockNode {
2134
- type: "opaque_block";
2135
- fragmentId: string;
2136
- warningId: string;
2137
- rawXml?: string;
2136
+ readonly type: "opaque_block";
2137
+ readonly fragmentId: string;
2138
+ readonly warningId: string;
2139
+ readonly rawXml?: string;
2138
2140
  }
2139
2141
 
2140
2142
  export interface DocRange {
2141
- from: number;
2142
- to: number;
2143
+ readonly from: number;
2144
+ readonly to: number;
2143
2145
  }
2144
2146
 
2145
2147
  export interface BoundaryAssoc {
2146
- start: -1 | 1;
2147
- end: -1 | 1;
2148
+ readonly start: -1 | 1;
2149
+ readonly end: -1 | 1;
2148
2150
  }
2149
2151
 
2150
2152
  export type CanonicalAnchor =
@@ -2166,70 +2168,70 @@ export type CanonicalAnchor =
2166
2168
  };
2167
2169
 
2168
2170
  export interface ReviewStore {
2169
- comments: Record<string, CommentThread>;
2170
- revisions: Record<string, RevisionRecord>;
2171
+ readonly comments: Record<string, CommentThread>;
2172
+ readonly revisions: Record<string, RevisionRecord>;
2171
2173
  }
2172
2174
 
2173
2175
  export interface CommentThread {
2174
- commentId: string;
2175
- status: "open" | "resolved" | "detached";
2176
- anchor: CanonicalAnchor;
2177
- createdAt: ISO8601DateTime;
2178
- createdBy?: string;
2179
- authorId?: string;
2180
- body?: string;
2181
- entries?: CommentEntry[];
2182
- resolution?: CommentResolution;
2183
- resolvedAt?: ISO8601DateTime;
2184
- warningIds: string[];
2185
- isResolved?: boolean;
2186
- metadata?: CommentThreadMetadata;
2176
+ readonly commentId: string;
2177
+ readonly status: "open" | "resolved" | "detached";
2178
+ readonly anchor: CanonicalAnchor;
2179
+ readonly createdAt: ISO8601DateTime;
2180
+ readonly createdBy?: string;
2181
+ readonly authorId?: string;
2182
+ readonly body?: string;
2183
+ readonly entries?: CommentEntry[];
2184
+ readonly resolution?: CommentResolution;
2185
+ readonly resolvedAt?: ISO8601DateTime;
2186
+ readonly warningIds: string[];
2187
+ readonly isResolved?: boolean;
2188
+ readonly metadata?: CommentThreadMetadata;
2187
2189
  }
2188
2190
 
2189
2191
  export interface CommentEntry {
2190
- entryId: string;
2191
- authorId: string;
2192
- createdAt: ISO8601DateTime;
2193
- body: string;
2194
- metadata?: CommentEntryMetadata;
2192
+ readonly entryId: string;
2193
+ readonly authorId: string;
2194
+ readonly createdAt: ISO8601DateTime;
2195
+ readonly body: string;
2196
+ readonly metadata?: CommentEntryMetadata;
2195
2197
  }
2196
2198
 
2197
2199
  export interface CommentEntryMetadata {
2198
- ooxmlCommentId?: string;
2199
- paraId?: string;
2200
- parentParaId?: string;
2201
- durableId?: string;
2202
- initials?: string;
2200
+ readonly ooxmlCommentId?: string;
2201
+ readonly paraId?: string;
2202
+ readonly parentParaId?: string;
2203
+ readonly durableId?: string;
2204
+ readonly initials?: string;
2203
2205
  }
2204
2206
 
2205
2207
  export interface CommentResolution {
2206
- resolvedAt: ISO8601DateTime;
2207
- resolvedBy: string;
2208
+ readonly resolvedAt: ISO8601DateTime;
2209
+ readonly resolvedBy: string;
2208
2210
  }
2209
2211
 
2210
2212
  export interface CommentThreadMetadata {
2211
- source?: "runtime" | "import";
2212
- rootOoxmlCommentId?: string;
2213
- rootParaId?: string;
2213
+ readonly source?: "runtime" | "import";
2214
+ readonly rootOoxmlCommentId?: string;
2215
+ readonly rootParaId?: string;
2214
2216
  /**
2215
2217
  * Runtime-authored discussion thread for a tracked change. The comment
2216
2218
  * anchor points at the revision range; this metadata keeps the review
2217
2219
  * relation stable after remaps and lets suggestion cards surface replies.
2218
2220
  */
2219
- linkedRevisionId?: string;
2220
- detachedReason?: "incomplete-markers" | "multi-paragraph" | "opaque-region" | "revision-overlap";
2221
- actionabilityNote?: string;
2221
+ readonly linkedRevisionId?: string;
2222
+ readonly detachedReason?: "incomplete-markers" | "multi-paragraph" | "opaque-region" | "revision-overlap";
2223
+ readonly actionabilityNote?: string;
2222
2224
  }
2223
2225
 
2224
2226
  export interface RevisionPropertyChangeData {
2225
- xmlTag: "pPrChange" | "sectPrChange" | "tblPrChange" | "rPrChange";
2226
- beforeXml: string;
2227
+ readonly xmlTag: "pPrChange" | "sectPrChange" | "tblPrChange" | "rPrChange";
2228
+ readonly beforeXml: string;
2227
2229
  }
2228
2230
 
2229
2231
  export interface RevisionMoveData {
2230
- moveId: string;
2231
- direction: "from" | "to";
2232
- linkedRevisionId?: string;
2232
+ readonly moveId: string;
2233
+ readonly direction: "from" | "to";
2234
+ readonly linkedRevisionId?: string;
2233
2235
  }
2234
2236
 
2235
2237
  export type RevisionStoryTargetRecord =
@@ -2250,21 +2252,21 @@ export type RevisionStoryTargetRecord =
2250
2252
  | { kind: "endnote"; noteId: string };
2251
2253
 
2252
2254
  export interface RevisionRecord {
2253
- changeId: string;
2254
- kind: "insertion" | "deletion" | "formatting" | "move" | "property-change";
2255
- anchor: CanonicalAnchor;
2256
- authorId?: string;
2257
- createdAt: ISO8601DateTime;
2258
- warningIds?: string[];
2259
- metadata?: RevisionMetadataRecord;
2260
- status: "open" | "accepted" | "rejected" | "detached";
2255
+ readonly changeId: string;
2256
+ readonly kind: "insertion" | "deletion" | "formatting" | "move" | "property-change";
2257
+ readonly anchor: CanonicalAnchor;
2258
+ readonly authorId?: string;
2259
+ readonly createdAt: ISO8601DateTime;
2260
+ readonly warningIds?: string[];
2261
+ readonly metadata?: RevisionMetadataRecord;
2262
+ readonly status: "open" | "accepted" | "rejected" | "detached";
2261
2263
  }
2262
2264
 
2263
2265
  export interface RevisionMetadataRecord {
2264
- source?: "runtime" | "import";
2265
- storyTarget?: RevisionStoryTargetRecord;
2266
- preserveOnlyReason?: string;
2267
- suggestionId?: string;
2266
+ readonly source?: "runtime" | "import";
2267
+ readonly storyTarget?: RevisionStoryTargetRecord;
2268
+ readonly preserveOnlyReason?: string;
2269
+ readonly suggestionId?: string;
2268
2270
  semanticKind?:
2269
2271
  | "insertion"
2270
2272
  | "deletion"
@@ -2273,49 +2275,49 @@ export interface RevisionMetadataRecord {
2273
2275
  | "paragraph-property-change"
2274
2276
  | "structural-change"
2275
2277
  | "object-change";
2276
- linkedRevisionIds?: string[];
2277
- predecessorSuggestionId?: string;
2278
+ readonly linkedRevisionIds?: string[];
2279
+ readonly predecessorSuggestionId?: string;
2278
2280
  importedRevisionForm?:
2279
2281
  | "run-insertion"
2280
2282
  | "run-deletion"
2281
2283
  | "paragraph-insertion"
2282
2284
  | "paragraph-deletion";
2283
- originalRevisionType?: string;
2284
- ooxmlRevisionId?: string;
2285
- propertyChangeData?: RevisionPropertyChangeData;
2286
- moveData?: RevisionMoveData;
2285
+ readonly originalRevisionType?: string;
2286
+ readonly ooxmlRevisionId?: string;
2287
+ readonly propertyChangeData?: RevisionPropertyChangeData;
2288
+ readonly moveData?: RevisionMoveData;
2287
2289
  }
2288
2290
 
2289
2291
  export interface PreservationStore {
2290
- opaqueFragments: Record<string, OpaqueFragmentRecord>;
2291
- packageParts: Record<string, PreservedPackagePart>;
2292
+ readonly opaqueFragments: Record<string, OpaqueFragmentRecord>;
2293
+ readonly packageParts: Record<string, PreservedPackagePart>;
2292
2294
  }
2293
2295
 
2294
2296
  export interface OpaqueFragmentRecord {
2295
- fragmentId: string;
2296
- payloadKind: "xml-subtree" | "package-part";
2297
- payloadReference: string;
2298
- featureClass: "preserve-only";
2299
- lastKnownRange: DocRange;
2300
- warningId: string;
2301
- packagePartName?: string;
2302
- relationshipId?: string;
2297
+ readonly fragmentId: string;
2298
+ readonly payloadKind: "xml-subtree" | "package-part";
2299
+ readonly payloadReference: string;
2300
+ readonly featureClass: "preserve-only";
2301
+ readonly lastKnownRange: DocRange;
2302
+ readonly warningId: string;
2303
+ readonly packagePartName?: string;
2304
+ readonly relationshipId?: string;
2303
2305
  }
2304
2306
 
2305
2307
  export interface PreservedPackagePart {
2306
- packagePartName: string;
2307
- contentType: string;
2308
- relationshipIds: string[];
2308
+ readonly packagePartName: string;
2309
+ readonly contentType: string;
2310
+ readonly relationshipIds: string[];
2309
2311
  }
2310
2312
 
2311
2313
  export interface DiagnosticStore {
2312
- warnings: DiagnosticWarningEntry[];
2313
- errors: DiagnosticErrorEntry[];
2314
+ readonly warnings: DiagnosticWarningEntry[];
2315
+ readonly errors: DiagnosticErrorEntry[];
2314
2316
  }
2315
2317
 
2316
2318
  export interface DiagnosticWarningEntry {
2317
- diagnosticId: string;
2318
- warningId: string;
2319
+ readonly diagnosticId: string;
2320
+ readonly warningId: string;
2319
2321
  source:
2320
2322
  | "import"
2321
2323
  | "runtime"
@@ -2323,11 +2325,11 @@ export interface DiagnosticWarningEntry {
2323
2325
  | "preservation"
2324
2326
  | "validation"
2325
2327
  | "export";
2326
- message: string;
2328
+ readonly message: string;
2327
2329
  }
2328
2330
 
2329
2331
  export interface DiagnosticErrorEntry {
2330
- diagnosticId: string;
2332
+ readonly diagnosticId: string;
2331
2333
  code:
2332
2334
  | "load_failed"
2333
2335
  | "import_failed"
@@ -2336,10 +2338,10 @@ export interface DiagnosticErrorEntry {
2336
2338
  | "validation_failed"
2337
2339
  | "datastore_failed"
2338
2340
  | "internal_invariant";
2339
- message: string;
2340
- isFatal: boolean;
2341
- source: "import" | "runtime" | "validation" | "datastore" | "host" | "export";
2342
- details?: unknown;
2341
+ readonly message: string;
2342
+ readonly isFatal: boolean;
2343
+ readonly source: "import" | "runtime" | "validation" | "datastore" | "host" | "export";
2344
+ readonly details?: unknown;
2343
2345
  }
2344
2346
 
2345
2347
  export function createCanonicalDocument(