@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
@@ -26,6 +26,7 @@ import type {
26
26
  SectionPageBorders,
27
27
  DrawingFrameNode,
28
28
  UnknownPropertyChild,
29
+ Mutable,
29
30
  } from "../../model/canonical-document.ts";
30
31
  import type { OpcRelationship } from "./part-manifest.ts";
31
32
  import { SCOPE_MARKER_BOOKMARK_PREFIX } from "./parse-scope-markers.ts";
@@ -2288,7 +2289,7 @@ function readParagraphSpacing(node: XmlElementNode): ParagraphSpacing | undefine
2288
2289
  );
2289
2290
  if (!spacingNode) return undefined;
2290
2291
 
2291
- const spacing: ParagraphSpacing = {};
2292
+ const spacing: Mutable<ParagraphSpacing> = {};
2292
2293
  const before = spacingNode.attributes["w:before"] ?? spacingNode.attributes.before;
2293
2294
  const after = spacingNode.attributes["w:after"] ?? spacingNode.attributes.after;
2294
2295
  const line = spacingNode.attributes["w:line"] ?? spacingNode.attributes.line;
@@ -2332,7 +2333,7 @@ function readParagraphIndentation(node: XmlElementNode): ParagraphIndentation |
2332
2333
  );
2333
2334
  if (!indNode) return undefined;
2334
2335
 
2335
- const indentation: ParagraphIndentation = {};
2336
+ const indentation: Mutable<ParagraphIndentation> = {};
2336
2337
  const left = indNode.attributes["w:left"] ?? indNode.attributes.left;
2337
2338
  const right = indNode.attributes["w:right"] ?? indNode.attributes.right;
2338
2339
  const firstLine = indNode.attributes["w:firstLine"] ?? indNode.attributes.firstLine;
@@ -2450,7 +2451,7 @@ function readParagraphBorders(node: XmlElementNode): ParagraphBorders | undefine
2450
2451
  return undefined;
2451
2452
  }
2452
2453
 
2453
- const borders: ParagraphBorders = {};
2454
+ const borders: Mutable<ParagraphBorders> = {};
2454
2455
  for (const [name, key] of [
2455
2456
  ["top", "top"],
2456
2457
  ["left", "left"],
@@ -2481,7 +2482,7 @@ function readParagraphShading(node: XmlElementNode): ParagraphShading | undefine
2481
2482
  return undefined;
2482
2483
  }
2483
2484
 
2484
- const shading: ParagraphShading = {};
2485
+ const shading: Mutable<ParagraphShading> = {};
2485
2486
  const fill = shadingNode.attributes["w:fill"] ?? shadingNode.attributes.fill;
2486
2487
  const color = shadingNode.attributes["w:color"] ?? shadingNode.attributes.color;
2487
2488
  const val = shadingNode.attributes["w:val"] ?? shadingNode.attributes.val;
@@ -2491,14 +2492,14 @@ function readParagraphShading(node: XmlElementNode): ParagraphShading | undefine
2491
2492
  const themeColor = shadingNode.attributes["w:themeColor"] ?? shadingNode.attributes.themeColor;
2492
2493
  const themeColorTint = shadingNode.attributes["w:themeColorTint"] ?? shadingNode.attributes.themeColorTint;
2493
2494
  const themeColorShade = shadingNode.attributes["w:themeColorShade"] ?? shadingNode.attributes.themeColorShade;
2494
- if (fill) shading.fill = fill;
2495
- if (color) shading.color = color;
2496
- if (val) shading.val = val;
2497
- if (themeFill) shading.themeFill = themeFill;
2498
- if (themeFillTint) shading.themeFillTint = themeFillTint;
2499
- if (themeFillShade) shading.themeFillShade = themeFillShade;
2500
- if (themeColor) shading.themeColor = themeColor;
2501
- if (themeColorTint) shading.themeColorTint = themeColorTint;
2495
+ if (fill) (shading as Mutable<typeof shading>).fill = fill;
2496
+ if (color) (shading as Mutable<typeof shading>).color = color;
2497
+ if (val) (shading as Mutable<typeof shading>).val = val;
2498
+ if (themeFill) (shading as Mutable<typeof shading>).themeFill = themeFill;
2499
+ if (themeFillTint) (shading as Mutable<typeof shading>).themeFillTint = themeFillTint;
2500
+ if (themeFillShade) (shading as Mutable<typeof shading>).themeFillShade = themeFillShade;
2501
+ if (themeColor) (shading as Mutable<typeof shading>).themeColor = themeColor;
2502
+ if (themeColorTint) (shading as Mutable<typeof shading>).themeColorTint = themeColorTint;
2502
2503
  if (themeColorShade) shading.themeColorShade = themeColorShade;
2503
2504
  return Object.keys(shading).length > 0 ? shading : undefined;
2504
2505
  }
@@ -2511,7 +2512,7 @@ function readParagraphCnfStyle(node: XmlElementNode): string | undefined {
2511
2512
  }
2512
2513
 
2513
2514
  function readBorder(node: XmlElementNode): ParagraphBorders[keyof ParagraphBorders] {
2514
- const border: NonNullable<ParagraphBorders[keyof ParagraphBorders]> = {};
2515
+ const border: Mutable<NonNullable<ParagraphBorders[keyof ParagraphBorders]>> = {};
2515
2516
  const value = node.attributes["w:val"] ?? node.attributes.val;
2516
2517
  const size = node.attributes["w:sz"] ?? node.attributes.sz;
2517
2518
  const space = node.attributes["w:space"] ?? node.attributes.space;
@@ -3632,7 +3633,7 @@ function readSectionPropertiesXmlFromPPr(
3632
3633
  export function parseSectionPropertiesFromElement(
3633
3634
  node: XmlElementNode,
3634
3635
  ): SectionProperties {
3635
- const props: SectionProperties = {};
3636
+ const props: Mutable<SectionProperties> = {};
3636
3637
 
3637
3638
  for (const child of node.children) {
3638
3639
  if (child.type !== "element") continue;
@@ -3643,7 +3644,7 @@ export function parseSectionPropertiesFromElement(
3643
3644
  const w = safeParseInt(child.attributes["w:w"]);
3644
3645
  const h = safeParseInt(child.attributes["w:h"]);
3645
3646
  if (w !== undefined && h !== undefined) {
3646
- const pageSize: PageSize = { width: w, height: h };
3647
+ const pageSize: Mutable<PageSize> = { width: w, height: h };
3647
3648
  const orient = child.attributes["w:orient"];
3648
3649
  if (orient === "landscape" || orient === "portrait") {
3649
3650
  pageSize.orientation = orient;
@@ -3658,26 +3659,26 @@ export function parseSectionPropertiesFromElement(
3658
3659
  const bottom = safeParseInt(child.attributes["w:bottom"]);
3659
3660
  const left = safeParseInt(child.attributes["w:left"]);
3660
3661
  if (top !== undefined && right !== undefined && bottom !== undefined && left !== undefined) {
3661
- const margins: PageMargins = { top, right, bottom, left };
3662
+ const margins: Mutable<PageMargins> = { top, right, bottom, left };
3662
3663
  const header = safeParseInt(child.attributes["w:header"]);
3663
3664
  const footer = safeParseInt(child.attributes["w:footer"]);
3664
3665
  const gutter = safeParseInt(child.attributes["w:gutter"]);
3665
- if (header !== undefined) margins.header = header;
3666
- if (footer !== undefined) margins.footer = footer;
3667
- if (gutter !== undefined) margins.gutter = gutter;
3666
+ if (header !== undefined) (margins as Mutable<typeof margins>).header = header;
3667
+ if (footer !== undefined) (margins as Mutable<typeof margins>).footer = footer;
3668
+ if (gutter !== undefined) (margins as Mutable<typeof margins>).gutter = gutter;
3668
3669
  props.pageMargins = margins;
3669
3670
  }
3670
3671
  break;
3671
3672
  }
3672
3673
  case "cols": {
3673
- const columns: ColumnProperties = {};
3674
+ const columns: Mutable<ColumnProperties> = {};
3674
3675
  const num = safeParseInt(child.attributes["w:num"]);
3675
3676
  const space = safeParseInt(child.attributes["w:space"]);
3676
3677
  const equalWidth = child.attributes["w:equalWidth"];
3677
3678
  const sep = child.attributes["w:sep"];
3678
- if (num !== undefined) columns.count = num;
3679
- if (space !== undefined) columns.space = space;
3680
- if (equalWidth !== undefined) columns.equalWidth = equalWidth !== "0" && equalWidth !== "false";
3679
+ if (num !== undefined) (columns as Mutable<typeof columns>).count = num;
3680
+ if (space !== undefined) (columns as Mutable<typeof columns>).space = space;
3681
+ if (equalWidth !== undefined) (columns as Mutable<typeof columns>).equalWidth = equalWidth !== "0" && equalWidth !== "false";
3681
3682
  if (sep === "1" || sep === "true") columns.separator = true;
3682
3683
  const colDefs: Array<{ width: number; space?: number }> = [];
3683
3684
  for (const colChild of child.children) {
@@ -3689,31 +3690,31 @@ export function parseSectionPropertiesFromElement(
3689
3690
  }
3690
3691
  }
3691
3692
  }
3692
- if (colDefs.length > 0) columns.columns = colDefs;
3693
+ if (colDefs.length > 0) (columns as Mutable<typeof columns>).columns = colDefs;
3693
3694
  if (Object.keys(columns).length > 0) props.columns = columns;
3694
3695
  break;
3695
3696
  }
3696
3697
  case "pgNumType": {
3697
- const numbering: PageNumbering = {};
3698
+ const numbering: Mutable<PageNumbering> = {};
3698
3699
  const fmt = child.attributes["w:fmt"];
3699
3700
  const start = safeParseInt(child.attributes["w:start"]);
3700
3701
  const chapStyle = child.attributes["w:chapStyle"];
3701
3702
  const chapSep = child.attributes["w:chapSep"];
3702
- if (fmt) numbering.format = fmt;
3703
- if (start !== undefined) numbering.start = start;
3704
- if (chapStyle) numbering.chapStyle = chapStyle;
3705
- if (chapSep) numbering.chapSep = chapSep;
3703
+ if (fmt) (numbering as Mutable<typeof numbering>).format = fmt;
3704
+ if (start !== undefined) (numbering as Mutable<typeof numbering>).start = start;
3705
+ if (chapStyle) (numbering as Mutable<typeof numbering>).chapStyle = chapStyle;
3706
+ if (chapSep) (numbering as Mutable<typeof numbering>).chapSep = chapSep;
3706
3707
  if (Object.keys(numbering).length > 0) props.pageNumbering = numbering;
3707
3708
  break;
3708
3709
  }
3709
3710
  case "lnNumType": {
3710
- const lineNumbering: SectionLineNumbering = {};
3711
+ const lineNumbering: Mutable<SectionLineNumbering> = {};
3711
3712
  const countBy = safeParseInt(child.attributes["w:countBy"]);
3712
3713
  const start = safeParseInt(child.attributes["w:start"]);
3713
3714
  const distance = safeParseInt(child.attributes["w:distance"]);
3714
3715
  const restart = child.attributes["w:restart"];
3715
- if (countBy !== undefined) lineNumbering.countBy = countBy;
3716
- if (start !== undefined) lineNumbering.start = start;
3716
+ if (countBy !== undefined) (lineNumbering as Mutable<typeof lineNumbering>).countBy = countBy;
3717
+ if (start !== undefined) (lineNumbering as Mutable<typeof lineNumbering>).start = start;
3717
3718
  if (distance !== undefined) lineNumbering.distance = distance;
3718
3719
  if (
3719
3720
  restart === "newPage" ||
@@ -3728,7 +3729,7 @@ export function parseSectionPropertiesFromElement(
3728
3729
  break;
3729
3730
  }
3730
3731
  case "pgBorders": {
3731
- const pageBorders: SectionPageBorders = {};
3732
+ const pageBorders: Mutable<SectionPageBorders> = {};
3732
3733
  const offsetFrom = child.attributes["w:offsetFrom"];
3733
3734
  const display = child.attributes["w:display"];
3734
3735
  const zOrder = child.attributes["w:zOrder"];
@@ -3765,7 +3766,7 @@ export function parseSectionPropertiesFromElement(
3765
3766
  break;
3766
3767
  }
3767
3768
  case "docGrid": {
3768
- const documentGrid: SectionDocumentGrid = {};
3769
+ const documentGrid: Mutable<SectionDocumentGrid> = {};
3769
3770
  const type = child.attributes["w:type"];
3770
3771
  const linePitch = safeParseInt(child.attributes["w:linePitch"]);
3771
3772
  const charSpace = safeParseInt(child.attributes["w:charSpace"]);
@@ -3777,7 +3778,7 @@ export function parseSectionPropertiesFromElement(
3777
3778
  ) {
3778
3779
  documentGrid.type = type;
3779
3780
  }
3780
- if (linePitch !== undefined) documentGrid.linePitch = linePitch;
3781
+ if (linePitch !== undefined) (documentGrid as Mutable<typeof documentGrid>).linePitch = linePitch;
3781
3782
  if (charSpace !== undefined) documentGrid.charSpace = charSpace;
3782
3783
  if (Object.keys(documentGrid).length > 0) {
3783
3784
  props.documentGrid = documentGrid;
@@ -3856,7 +3857,7 @@ function safeParseInt(value: string | undefined): number | undefined {
3856
3857
  function readFootnoteLikeProperties(
3857
3858
  node: XmlElementNode,
3858
3859
  ): FootnoteProperties | undefined {
3859
- const result: FootnoteProperties = {};
3860
+ const result: Mutable<FootnoteProperties> = {};
3860
3861
 
3861
3862
  for (const child of node.children) {
3862
3863
  if (child.type !== "element") continue;
@@ -3902,15 +3903,15 @@ function readFootnoteLikeProperties(
3902
3903
  }
3903
3904
 
3904
3905
  function parseBorderSpec(node: XmlElementNode): BorderSpec | undefined {
3905
- const border: BorderSpec = {};
3906
+ const border: Mutable<BorderSpec> = {};
3906
3907
  const value = node.attributes["w:val"];
3907
3908
  const size = safeParseInt(node.attributes["w:sz"]);
3908
3909
  const space = safeParseInt(node.attributes["w:space"]);
3909
3910
  const color = node.attributes["w:color"];
3910
3911
 
3911
- if (value) border.value = value;
3912
- if (size !== undefined) border.size = size;
3913
- if (space !== undefined) border.space = space;
3912
+ if (value) (border as Mutable<typeof border>).value = value;
3913
+ if (size !== undefined) (border as Mutable<typeof border>).size = size;
3914
+ if (space !== undefined) (border as Mutable<typeof border>).space = space;
3914
3915
  if (color) border.color = color;
3915
3916
 
3916
3917
  return Object.keys(border).length > 0 ? border : undefined;
@@ -8,6 +8,7 @@ import type {
8
8
  ParagraphSpacing,
9
9
  ParagraphIndentation,
10
10
  TabStop,
11
+ Mutable,
11
12
  } from "../../model/canonical-document.ts";
12
13
  import { readRunProperties } from "./parse-run-formatting.ts";
13
14
  import type { OpcRelationship } from "./part-manifest.ts";
@@ -519,7 +520,7 @@ function readParagraphIndentation(node: XmlElementNode): ParagraphIndentation |
519
520
  return undefined;
520
521
  }
521
522
 
522
- const indentation: ParagraphIndentation = {};
523
+ const indentation: Mutable<ParagraphIndentation> = {};
523
524
  const left = readStringAttr(indNode, "w:start") ?? readStringAttr(indNode, "w:left");
524
525
  const right = readStringAttr(indNode, "w:end") ?? readStringAttr(indNode, "w:right");
525
526
  const firstLine = readStringAttr(indNode, "w:firstLine");
@@ -560,7 +561,7 @@ function readParagraphSpacing(node: XmlElementNode): ParagraphSpacing | undefine
560
561
  return undefined;
561
562
  }
562
563
 
563
- const spacing: ParagraphSpacing = {};
564
+ const spacing: Mutable<ParagraphSpacing> = {};
564
565
  const before = readStringAttr(spacingNode, "w:before");
565
566
  const after = readStringAttr(spacingNode, "w:after");
566
567
  const line = readStringAttr(spacingNode, "w:line");
@@ -18,7 +18,7 @@
18
18
  * responsibility post-v2.0; this module emits only data.
19
19
  */
20
20
 
21
- import type { OleEmbedNode } from "../../model/canonical-document.ts";
21
+ import type { OleEmbedNode, Mutable } from "../../model/canonical-document.ts";
22
22
  import type { OpcRelationship } from "./part-manifest.ts";
23
23
  import type { XmlElementNode } from "./xml-element.ts";
24
24
  import { resolveOleRelationship } from "./parse-ole-relationship.ts";
@@ -93,13 +93,13 @@ export function parseObject(
93
93
 
94
94
  const metadata: OleEmbedNode["metadata"] = {};
95
95
  if (resolved.originalFilename) {
96
- metadata.originalFilename = resolved.originalFilename;
96
+ (metadata as Mutable<typeof metadata>).originalFilename = resolved.originalFilename;
97
97
  }
98
98
  if (classId) {
99
- metadata.classId = classId;
99
+ (metadata as Mutable<typeof metadata>).classId = classId;
100
100
  }
101
101
  if (shapeId) {
102
- metadata.shapeId = shapeId;
102
+ (metadata as Mutable<typeof metadata>).shapeId = shapeId;
103
103
  }
104
104
 
105
105
  const id =
@@ -107,7 +107,7 @@ export function parseObject(
107
107
  ? `ole-embed-${resolved.relationshipId}-${occurrenceIndex}`
108
108
  : `ole-embed-${resolved.relationshipId}`;
109
109
 
110
- const result: OleEmbedNode = {
110
+ const result: Mutable<OleEmbedNode> = {
111
111
  type: "ole_embed",
112
112
  id,
113
113
  embedType: "oleObject",
@@ -116,7 +116,7 @@ export function parseObject(
116
116
  rawXml,
117
117
  };
118
118
  if (progId) {
119
- result.progId = progId;
119
+ (result as Mutable<typeof result>).progId = progId;
120
120
  }
121
121
  return result;
122
122
  }
@@ -14,6 +14,7 @@ import type {
14
14
  ParagraphShading,
15
15
  ParagraphSpacing,
16
16
  TabStop,
17
+ Mutable,
17
18
  } from "../../model/canonical-document.ts";
18
19
  import { readRunProperties } from "./parse-run-formatting.ts";
19
20
  import { findChildOptional, localName, readIntAttr, readIntVal, readOnOff } from "./xml-attr-helpers.ts";
@@ -87,31 +88,31 @@ const PPR_GRAB_BAG_DESCRIPTOR: PropertyGrabBagDescriptor = {
87
88
  };
88
89
 
89
90
  function readSpacing(node: XmlElementNode): ParagraphSpacing | undefined {
90
- const out: ParagraphSpacing = {};
91
+ const out: Mutable<ParagraphSpacing> = {};
91
92
  const before = readIntAttr(node, "w:before");
92
93
  const after = readIntAttr(node, "w:after");
93
94
  const line = readIntAttr(node, "w:line");
94
95
  const rule = node.attributes["w:lineRule"] ?? node.attributes.lineRule;
95
- if (before !== undefined) out.before = before;
96
- if (after !== undefined) out.after = after;
96
+ if (before !== undefined) (out as Mutable<typeof out>).before = before;
97
+ if (after !== undefined) (out as Mutable<typeof out>).after = after;
97
98
  if (line !== undefined) out.line = line;
98
99
  if (rule) {
99
100
  const n = rule.toLowerCase();
100
- if (n === "auto" || n === "exact") out.lineRule = n;
101
+ if (n === "auto" || n === "exact") (out as Mutable<typeof out>).lineRule = n;
101
102
  else if (n === "atleast") out.lineRule = "atLeast";
102
103
  }
103
104
  return Object.keys(out).length > 0 ? out : undefined;
104
105
  }
105
106
 
106
107
  function readIndent(node: XmlElementNode): ParagraphIndentation | undefined {
107
- const out: ParagraphIndentation = {};
108
+ const out: Mutable<ParagraphIndentation> = {};
108
109
  const left = readIntAttr(node, "w:left") ?? readIntAttr(node, "w:start");
109
110
  const right = readIntAttr(node, "w:right") ?? readIntAttr(node, "w:end");
110
111
  const firstLine = readIntAttr(node, "w:firstLine");
111
112
  const hanging = readIntAttr(node, "w:hanging");
112
- if (left !== undefined) out.left = left;
113
- if (right !== undefined) out.right = right;
114
- if (firstLine !== undefined) out.firstLine = firstLine;
113
+ if (left !== undefined) (out as Mutable<typeof out>).left = left;
114
+ if (right !== undefined) (out as Mutable<typeof out>).right = right;
115
+ if (firstLine !== undefined) (out as Mutable<typeof out>).firstLine = firstLine;
115
116
  if (hanging !== undefined) out.hanging = hanging;
116
117
  return Object.keys(out).length > 0 ? out : undefined;
117
118
  }
@@ -138,7 +139,7 @@ function readTabStops(node: XmlElementNode): TabStop[] | undefined {
138
139
  }
139
140
 
140
141
  function readBorders(node: XmlElementNode): ParagraphBorders | undefined {
141
- const out: ParagraphBorders = {};
142
+ const out: Mutable<ParagraphBorders> = {};
142
143
  const sides = ["top", "bottom", "left", "right", "between", "bar"] as const;
143
144
  for (const side of sides) {
144
145
  const child = findChildOptional(node, side);
@@ -205,7 +206,7 @@ function readShading(node: XmlElementNode): ParagraphShading | undefined {
205
206
  * text frames, drop-caps); extension attrs are rare in that corpus.
206
207
  */
207
208
  export function readFrameProperties(node: XmlElementNode): FrameProperties | undefined {
208
- const out: FrameProperties = {};
209
+ const out: Mutable<FrameProperties> = {};
209
210
  const width = readIntAttr(node, "w:w");
210
211
  if (width !== undefined) out.widthTwips = width;
211
212
  const height = readIntAttr(node, "w:h");
@@ -268,7 +269,7 @@ export function readParagraphProperties(
268
269
  ): CanonicalParagraphFormatting | undefined {
269
270
  if (!node) return undefined;
270
271
 
271
- const out: CanonicalParagraphFormatting = {};
272
+ const out: Mutable<CanonicalParagraphFormatting> = {};
272
273
 
273
274
  const spacingNode = findChildOptional(node, "spacing");
274
275
  if (spacingNode) {
@@ -1,4 +1,4 @@
1
- import type { PictureContent } from "../../model/canonical-document.ts";
1
+ import type { PictureContent, Mutable } from "../../model/canonical-document.ts";
2
2
  import {
3
3
  type XmlElementNode,
4
4
  findFirstChild,
@@ -100,21 +100,21 @@ export function parsePicture(graphicDataEl: XmlElementNode): PictureContent | nu
100
100
  const glowEl = effectLst ? findFirstChild(effectLst, "glow") : undefined;
101
101
  const glow = glowEl ? parseGlow(glowEl) : undefined;
102
102
 
103
- const result: PictureContent = { type: "picture", blipRef };
104
- if (isLinked) result.isLinked = true;
103
+ const result: Mutable<PictureContent> = { type: "picture", blipRef };
104
+ if (isLinked) (result as Mutable<typeof result>).isLinked = true;
105
105
  if (lum && (lum.bright !== undefined || lum.contrast !== undefined)) {
106
- result.lum = lum;
106
+ (result as Mutable<typeof result>).lum = lum;
107
107
  }
108
- if (srcRect) result.srcRect = srcRect;
109
- if (stretch !== undefined) result.stretch = stretch;
108
+ if (srcRect) (result as Mutable<typeof result>).srcRect = srcRect;
109
+ if (stretch !== undefined) (result as Mutable<typeof result>).stretch = stretch;
110
110
  if (tile !== undefined) result.tile = tile;
111
- if (rotation !== undefined) result.rotation = rotation;
112
- if (flipH !== undefined) result.flipH = flipH;
113
- if (flipV !== undefined) result.flipV = flipV;
114
- if (presetGeom) result.presetGeom = presetGeom;
115
- if (softEdgeRadius !== undefined) result.softEdgeRadius = softEdgeRadius;
116
- if (outerShadow) result.outerShadow = outerShadow;
117
- if (glow) result.glow = glow;
111
+ if (rotation !== undefined) (result as Mutable<typeof result>).rotation = rotation;
112
+ if (flipH !== undefined) (result as Mutable<typeof result>).flipH = flipH;
113
+ if (flipV !== undefined) (result as Mutable<typeof result>).flipV = flipV;
114
+ if (presetGeom) (result as Mutable<typeof result>).presetGeom = presetGeom;
115
+ if (softEdgeRadius !== undefined) (result as Mutable<typeof result>).softEdgeRadius = softEdgeRadius;
116
+ if (outerShadow) (result as Mutable<typeof result>).outerShadow = outerShadow;
117
+ if (glow) (result as Mutable<typeof result>).glow = glow;
118
118
  return result;
119
119
  }
120
120
 
@@ -172,13 +172,13 @@ function readTileAttrs(
172
172
  const v = tileEl.attributes[key];
173
173
  if (v !== undefined) {
174
174
  const n = parseInt(v, 10);
175
- if (Number.isFinite(n)) result[key] = n;
175
+ if (Number.isFinite(n)) (result as Mutable<typeof result>)[key] = n;
176
176
  }
177
177
  }
178
178
  const flip = tileEl.attributes.flip;
179
- if (flip === "x" || flip === "y" || flip === "xy") result.flip = flip;
179
+ if (flip === "x" || flip === "y" || flip === "xy") (result as Mutable<typeof result>).flip = flip;
180
180
  const algn = tileEl.attributes.algn;
181
- if (algn) result.algn = algn;
181
+ if (algn) (result as Mutable<typeof result>).algn = algn;
182
182
  return Object.keys(result).length > 0 ? result : {};
183
183
  }
184
184
 
@@ -1,6 +1,7 @@
1
1
  import type {
2
2
  CanonicalRunFormatting,
3
3
  ThemeFontSlot,
4
+ Mutable,
4
5
  } from "../../model/canonical-document.ts";
5
6
  import { findChildOptional, readIntVal, readOnOff, readStringAttr } from "./xml-attr-helpers.ts";
6
7
  import type { XmlElementNode } from "./xml-element.ts";
@@ -58,7 +59,7 @@ export function readRunProperties(
58
59
  ): CanonicalRunFormatting | undefined {
59
60
  if (!node) return undefined;
60
61
 
61
- const rPr: CanonicalRunFormatting = {};
62
+ const rPr: Mutable<CanonicalRunFormatting> = {};
62
63
 
63
64
  const bold = readOnOff(findChildOptional(node, "b"));
64
65
  if (bold !== undefined) rPr.bold = bold;
@@ -121,9 +122,9 @@ export function readRunProperties(
121
122
  const hAnsi = rFonts.attributes["w:hAnsi"] ?? rFonts.attributes.hAnsi;
122
123
  const eastAsia = rFonts.attributes["w:eastAsia"] ?? rFonts.attributes.eastAsia;
123
124
  const cs = rFonts.attributes["w:cs"] ?? rFonts.attributes.cs;
124
- if (ascii) rPr.fontFamilyAscii = ascii;
125
- if (hAnsi) rPr.fontFamilyHAnsi = hAnsi;
126
- if (eastAsia) rPr.fontFamilyEastAsia = eastAsia;
125
+ if (ascii) (rPr as Mutable<typeof rPr>).fontFamilyAscii = ascii;
126
+ if (hAnsi) (rPr as Mutable<typeof rPr>).fontFamilyHAnsi = hAnsi;
127
+ if (eastAsia) (rPr as Mutable<typeof rPr>).fontFamilyEastAsia = eastAsia;
127
128
  if (cs) rPr.fontFamilyCs = cs;
128
129
  const primary = ascii ?? hAnsi ?? eastAsia ?? cs;
129
130
  if (primary) rPr.fontFamily = primary;
@@ -150,9 +151,9 @@ export function readRunProperties(
150
151
  rFonts.attributes["w:csTheme"] ??
151
152
  rFonts.attributes.csTheme,
152
153
  );
153
- if (asciiTheme) rPr.asciiTheme = asciiTheme;
154
- if (hAnsiTheme) rPr.hAnsiTheme = hAnsiTheme;
155
- if (eastAsiaTheme) rPr.eastAsiaTheme = eastAsiaTheme;
154
+ if (asciiTheme) (rPr as Mutable<typeof rPr>).asciiTheme = asciiTheme;
155
+ if (hAnsiTheme) (rPr as Mutable<typeof rPr>).hAnsiTheme = hAnsiTheme;
156
+ if (eastAsiaTheme) (rPr as Mutable<typeof rPr>).eastAsiaTheme = eastAsiaTheme;
156
157
  if (csTheme) rPr.csTheme = csTheme;
157
158
  }
158
159
 
@@ -171,9 +172,9 @@ export function readRunProperties(
171
172
  color.attributes["w:themeTint"] ?? color.attributes["themeTint"];
172
173
  const shade =
173
174
  color.attributes["w:themeShade"] ?? color.attributes["themeShade"];
174
- if (val) rPr.colorHex = val;
175
- if (theme) rPr.colorThemeSlot = theme;
176
- if (tint) rPr.colorThemeTint = tint;
175
+ if (val) (rPr as Mutable<typeof rPr>).colorHex = val;
176
+ if (theme) (rPr as Mutable<typeof rPr>).colorThemeSlot = theme;
177
+ if (tint) (rPr as Mutable<typeof rPr>).colorThemeTint = tint;
177
178
  if (shade) rPr.colorThemeShade = shade;
178
179
  }
179
180
 
@@ -5,6 +5,7 @@ import type {
5
5
  DocumentSettings,
6
6
  FootnoteProperties,
7
7
  ThemeColorSlot,
8
+ Mutable,
8
9
  } from "../../model/canonical-document.ts";
9
10
  import { parseXml } from "./xml-parser.ts";
10
11
  import { localName } from "./xml-attr-helpers.ts";
@@ -160,7 +161,7 @@ function readFootnoteLikeProperties(
160
161
  ): FootnoteProperties | undefined {
161
162
  if (!element) return undefined;
162
163
 
163
- const result: FootnoteProperties = {};
164
+ const result: Mutable<FootnoteProperties> = {};
164
165
  for (const child of element.children) {
165
166
  if (child.type !== "element") continue;
166
167
  const name = localName(child.name);
@@ -14,6 +14,7 @@ import type {
14
14
  BlockNode,
15
15
  ShapeContent,
16
16
  TextBoxBodyProperties,
17
+ Mutable,
17
18
  } from "../../model/canonical-document.ts";
18
19
  import { parseFill } from "./parse-fill.ts";
19
20
  import {
@@ -46,7 +47,7 @@ export interface ParsedWpsShape {
46
47
  * shape-textbox paragraphs). Same shape + semantics as
47
48
  * `ShapeContent.txbxBlocks` on the drawing-frame path.
48
49
  */
49
- txbxBlocks?: ReadonlyArray<BlockNode>;
50
+ txbxBlocks?: BlockNode[];
50
51
  /** DrawML geometry preset, e.g. "rect", "roundRect". */
51
52
  geometry?: string;
52
53
  /** Original drawing XML for lossless round-trip export. */
@@ -129,7 +130,7 @@ export function parseShapeXml(
129
130
  // content (CCEP "Copyright CCEP STRICTLY CONFIDENTIAL" footer band)
130
131
  // is reachable only via the `.text` summary string — L03 cascade +
131
132
  // L11 render can't walk runs/marks.
132
- let txbxBlocks: ReadonlyArray<BlockNode> | undefined;
133
+ let txbxBlocks: BlockNode[] | undefined;
133
134
  if (txbxContentXml && blockParser) {
134
135
  try {
135
136
  // The `blockParser` callback is supplied by parse-main-document.ts
@@ -142,7 +143,7 @@ export function parseShapeXml(
142
143
  // canonical; a structural `as unknown as BlockNode[]` preserves
143
144
  // type safety at every consumer site (L03 cascade, L11 render,
144
145
  // validator walk).
145
- txbxBlocks = blockParser(txbxContentXml) as unknown as ReadonlyArray<BlockNode>;
146
+ txbxBlocks = blockParser(txbxContentXml) as unknown as BlockNode[];
146
147
  } catch {
147
148
  txbxBlocks = undefined;
148
149
  }
@@ -271,7 +272,7 @@ export function parseShapeContent(
271
272
  const txbxContentXml = txbxContent ? extractRawXml(txbxContent) : undefined;
272
273
  const text = txbxContent ? extractAllText(txbxContent).trim() || undefined : undefined;
273
274
 
274
- let txbxBlocks: ReadonlyArray<BlockNode> | undefined;
275
+ let txbxBlocks: BlockNode[] | undefined;
275
276
  if (txbxContentXml && blockParser) {
276
277
  try {
277
278
  // See `TxbxBlockParser` doc above: runtime output is canonical
@@ -279,7 +280,7 @@ export function parseShapeContent(
279
280
  // footer fixture 2026-04-24). Cast at the assembly seam so
280
281
  // downstream consumers (L03, L11, validator) get canonical types
281
282
  // without local `as unknown` ceremony.
282
- txbxBlocks = blockParser(txbxContentXml) as unknown as ReadonlyArray<BlockNode>;
283
+ txbxBlocks = blockParser(txbxContentXml) as unknown as BlockNode[];
283
284
  } catch {
284
285
  // Preserve-only fallback: keep txbxContentXml for serialization; leave
285
286
  // txbxBlocks undefined so consumers know recursion did not succeed.
@@ -294,15 +295,15 @@ export function parseShapeContent(
294
295
  // roundRect text boxes + callout/ellipse shapes as non-text.
295
296
  const isTextBox = Boolean(txbxContent);
296
297
 
297
- const result: ShapeContent = { type: "shape", rawXml: drawingRawXml };
298
- if (geometry) result.geometry = geometry;
298
+ const result: Mutable<ShapeContent> = { type: "shape", rawXml: drawingRawXml };
299
+ if (geometry) (result as Mutable<typeof result>).geometry = geometry;
299
300
  if (text) result.text = text;
300
- if (fill) result.fill = fill;
301
- if (line) result.line = line;
302
- if (isTextBox) result.isTextBox = true;
303
- if (textBoxBody) result.textBoxBody = textBoxBody;
304
- if (txbxContentXml) result.txbxContentXml = txbxContentXml;
305
- if (txbxBlocks && txbxBlocks.length > 0) result.txbxBlocks = txbxBlocks;
301
+ if (fill) (result as Mutable<typeof result>).fill = fill;
302
+ if (line) (result as Mutable<typeof result>).line = line;
303
+ if (isTextBox) (result as Mutable<typeof result>).isTextBox = true;
304
+ if (textBoxBody) (result as Mutable<typeof result>).textBoxBody = textBoxBody;
305
+ if (txbxContentXml) (result as Mutable<typeof result>).txbxContentXml = txbxContentXml;
306
+ if (txbxBlocks && txbxBlocks.length > 0) (result as Mutable<typeof result>).txbxBlocks = txbxBlocks;
306
307
  return result;
307
308
  }
308
309
 
@@ -310,7 +311,7 @@ function readTextBoxBody(wsp: XmlElementNode): TextBoxBodyProperties | undefined
310
311
  const bodyPr = findFirstChild(wsp, "bodyPr");
311
312
  if (!bodyPr) return undefined;
312
313
 
313
- const result: TextBoxBodyProperties = {};
314
+ const result: Mutable<TextBoxBodyProperties> = {};
314
315
  const anchor = bodyPr.attributes.anchor;
315
316
  if (anchor === "t" || anchor === "ctr" || anchor === "b") {
316
317
  result.anchor = anchor;
@@ -319,9 +320,9 @@ function readTextBoxBody(wsp: XmlElementNode): TextBoxBodyProperties | undefined
319
320
  const top = readIntAttr(bodyPr, "tIns");
320
321
  const right = readIntAttr(bodyPr, "rIns");
321
322
  const bottom = readIntAttr(bodyPr, "bIns");
322
- if (left !== undefined) result.insetLeftEmu = left;
323
- if (top !== undefined) result.insetTopEmu = top;
324
- if (right !== undefined) result.insetRightEmu = right;
323
+ if (left !== undefined) (result as Mutable<typeof result>).insetLeftEmu = left;
324
+ if (top !== undefined) (result as Mutable<typeof result>).insetTopEmu = top;
325
+ if (right !== undefined) (result as Mutable<typeof result>).insetRightEmu = right;
325
326
  if (bottom !== undefined) result.insetBottomEmu = bottom;
326
327
 
327
328
  return Object.keys(result).length > 0 ? result : undefined;