ooxml.js 1.3.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -28,14 +28,14 @@ const XmlPiSchema = zod.z.object({
28
28
  target: zod.z.string(),
29
29
  content: zod.z.string()
30
30
  });
31
- function isRecord$1(value) {
31
+ function isRecord$2(value) {
32
32
  return typeof value === "object" && value !== null && !Array.isArray(value);
33
33
  }
34
34
  function isAttribute(value) {
35
- return isRecord$1(value) && typeof value.name === "string" && typeof value.value === "string";
35
+ return isRecord$2(value) && typeof value.name === "string" && typeof value.value === "string";
36
36
  }
37
37
  function isXmlNode(value) {
38
- if (!isRecord$1(value)) return false;
38
+ if (!isRecord$2(value)) return false;
39
39
  const t = value.type;
40
40
  if (t === "text" || t === "cdata" || t === "comment") return typeof value.value === "string";
41
41
  if (t === "declaration") return Array.isArray(value.attributes) && value.attributes.every(isAttribute);
@@ -130,7 +130,7 @@ const PARSER = new fast_xml_parser.XMLParser({
130
130
  function parseXml(xml) {
131
131
  return parseNodes(PARSER.parse(xml));
132
132
  }
133
- function isRecord(value) {
133
+ function isRecord$1(value) {
134
134
  return typeof value === "object" && value !== null && !Array.isArray(value);
135
135
  }
136
136
  function isUnknownArray$1(value) {
@@ -145,7 +145,7 @@ function parseNodes(raw) {
145
145
  return raw.map(parseNode);
146
146
  }
147
147
  function parseNode(raw) {
148
- if (!isRecord(raw)) throw new Error("fast-xml-parser node was not an object");
148
+ if (!isRecord$1(raw)) throw new Error("fast-xml-parser node was not an object");
149
149
  let tagKey;
150
150
  for (const key of Object.keys(raw)) if (key !== ":@") {
151
151
  if (tagKey !== void 0) throw new Error("XML node had multiple tag keys");
@@ -183,7 +183,7 @@ function parseNode(raw) {
183
183
  }
184
184
  function parseAttributes(raw) {
185
185
  if (raw === void 0) return [];
186
- if (!isRecord(raw)) throw new Error("XML attributes were not an object");
186
+ if (!isRecord$1(raw)) throw new Error("XML attributes were not an object");
187
187
  const attrs = [];
188
188
  for (const key of Object.keys(raw)) {
189
189
  if (!key.startsWith("@_")) throw new Error(`unexpected attribute key without @_ prefix: ${key}`);
@@ -197,7 +197,7 @@ function parseAttributes(raw) {
197
197
  function scalarText(raw) {
198
198
  if (!isUnknownArray$1(raw) || raw.length === 0) throw new Error("expected a scalar-text wrapper array");
199
199
  const first = raw[0];
200
- if (!isRecord(first)) throw new Error("scalar-text wrapper was not an object");
200
+ if (!isRecord$1(first)) throw new Error("scalar-text wrapper was not an object");
201
201
  return asString(first["#text"]);
202
202
  }
203
203
  //#endregion
@@ -534,27 +534,659 @@ function encodeCompactPackage(cpkg) {
534
534
  return zod.z.encode(compactPackageCodec, cpkg);
535
535
  }
536
536
  //#endregion
537
- //#region src/typed/docx.ts
538
- const RunSchema = zod.z.object({
537
+ //#region src/typed/shared/geometry.ts
538
+ const BoxSchema = zod.z.object({
539
+ xPt: zod.z.number(),
540
+ yPt: zod.z.number(),
541
+ widthPt: zod.z.number().nonnegative(),
542
+ heightPt: zod.z.number().nonnegative()
543
+ });
544
+ const PageSizeSchema = zod.z.object({
545
+ widthPt: zod.z.number().positive(),
546
+ heightPt: zod.z.number().positive()
547
+ });
548
+ const MarginsSchema = zod.z.object({
549
+ topPt: zod.z.number().nonnegative(),
550
+ rightPt: zod.z.number().nonnegative(),
551
+ bottomPt: zod.z.number().nonnegative(),
552
+ leftPt: zod.z.number().nonnegative()
553
+ });
554
+ const PAGE_SIZE_LETTER = {
555
+ widthPt: 612,
556
+ heightPt: 792
557
+ };
558
+ const PAGE_SIZE_A4 = {
559
+ widthPt: 595.28,
560
+ heightPt: 841.89
561
+ };
562
+ const SLIDE_SIZE_WIDESCREEN = {
563
+ widthPt: 960,
564
+ heightPt: 540
565
+ };
566
+ const SLIDE_SIZE_STANDARD = {
567
+ widthPt: 720,
568
+ heightPt: 540
569
+ };
570
+ //#endregion
571
+ //#region src/typed/shared/color.ts
572
+ const ColorSchema = zod.z.object({
573
+ r: zod.z.number().min(0).max(1),
574
+ g: zod.z.number().min(0).max(1),
575
+ b: zod.z.number().min(0).max(1)
576
+ });
577
+ const COLOR_BLACK = {
578
+ r: 0,
579
+ g: 0,
580
+ b: 0
581
+ };
582
+ const HEX_COLOR_PATTERN = /^#?([0-9a-fA-F]{6})$/;
583
+ const HEX_BYTE_MAX = 255;
584
+ function rgbHexToColor(hex) {
585
+ const match = HEX_COLOR_PATTERN.exec(hex);
586
+ if (match === null) throw new Error(`not a 6-digit hex colour: ${hex}`);
587
+ const digits = match[1];
588
+ if (digits === void 0) throw new Error(`not a 6-digit hex colour: ${hex}`);
589
+ const r = Number.parseInt(digits.slice(0, 2), 16);
590
+ const g = Number.parseInt(digits.slice(2, 4), 16);
591
+ const b = Number.parseInt(digits.slice(4, 6), 16);
592
+ return {
593
+ r: r / HEX_BYTE_MAX,
594
+ g: g / HEX_BYTE_MAX,
595
+ b: b / HEX_BYTE_MAX
596
+ };
597
+ }
598
+ function toHexByte(component) {
599
+ return Math.round(component * HEX_BYTE_MAX).toString(16).padStart(2, "0");
600
+ }
601
+ function colorToRgbHex(color) {
602
+ return `${toHexByte(color.r)}${toHexByte(color.g)}${toHexByte(color.b)}`;
603
+ }
604
+ const OOXML_PERCENT_SCALE = 1e5;
605
+ function clamp01(x) {
606
+ return Math.max(0, Math.min(1, x));
607
+ }
608
+ function srgbToLinear(c) {
609
+ return c <= .04045 ? c / 12.92 : ((c + .055) / 1.055) ** 2.4;
610
+ }
611
+ function linearToSrgb(c) {
612
+ return c <= .0031308 ? c * 12.92 : 1.055 * c ** (1 / 2.4) - .055;
613
+ }
614
+ function applyShadeOrTint(color, kind, value) {
615
+ const pct = value / OOXML_PERCENT_SCALE;
616
+ const transform = kind === "shade" ? (linear) => linear * pct : (linear) => 1 - (1 - linear) * pct;
617
+ return {
618
+ r: clamp01(linearToSrgb(transform(srgbToLinear(color.r)))),
619
+ g: clamp01(linearToSrgb(transform(srgbToLinear(color.g)))),
620
+ b: clamp01(linearToSrgb(transform(srgbToLinear(color.b))))
621
+ };
622
+ }
623
+ function rgbToHsl(color) {
624
+ const { r, g, b } = color;
625
+ const max = Math.max(r, g, b);
626
+ const min = Math.min(r, g, b);
627
+ const l = (max + min) / 2;
628
+ if (max === min) return {
629
+ h: 0,
630
+ s: 0,
631
+ l
632
+ };
633
+ const d = max - min;
634
+ const s = l > .5 ? d / (2 - max - min) : d / (max + min);
635
+ let h;
636
+ if (max === r) h = (g - b) / d + (g < b ? 6 : 0);
637
+ else if (max === g) h = (b - r) / d + 2;
638
+ else h = (r - g) / d + 4;
639
+ return {
640
+ h: h * 60,
641
+ s,
642
+ l
643
+ };
644
+ }
645
+ function hueToRgbComponent(p, q, hue) {
646
+ let t = hue;
647
+ if (t < 0) t += 1;
648
+ if (t > 1) t -= 1;
649
+ if (t < 1 / 6) return p + (q - p) * 6 * t;
650
+ if (t < 1 / 2) return q;
651
+ if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
652
+ return p;
653
+ }
654
+ function hslToRgb(hsl) {
655
+ const { h, s, l } = hsl;
656
+ if (s === 0) return {
657
+ r: l,
658
+ g: l,
659
+ b: l
660
+ };
661
+ const q = l < .5 ? l * (1 + s) : l + s - l * s;
662
+ const p = 2 * l - q;
663
+ const hk = h / 360;
664
+ return {
665
+ r: clamp01(hueToRgbComponent(p, q, hk + 1 / 3)),
666
+ g: clamp01(hueToRgbComponent(p, q, hk)),
667
+ b: clamp01(hueToRgbComponent(p, q, hk - 1 / 3))
668
+ };
669
+ }
670
+ function applyLumModOrOff(color, kind, value) {
671
+ const hsl = rgbToHsl(color);
672
+ const pct = value / OOXML_PERCENT_SCALE;
673
+ const l = clamp01(kind === "lumMod" ? hsl.l * pct : hsl.l + pct);
674
+ return hslToRgb({
675
+ ...hsl,
676
+ l
677
+ });
678
+ }
679
+ function applyColorTransforms(base, transforms) {
680
+ let color = base;
681
+ for (const t of transforms) if (t.kind === "shade" || t.kind === "tint") color = applyShadeOrTint(color, t.kind, t.value);
682
+ for (const t of transforms) if (t.kind === "lumMod" || t.kind === "lumOff") color = applyLumModOrOff(color, t.kind, t.value);
683
+ return color;
684
+ }
685
+ //#endregion
686
+ //#region src/typed/shared/style.ts
687
+ const AlignmentSchema = zod.z.enum([
688
+ "left",
689
+ "center",
690
+ "right",
691
+ "justify"
692
+ ]);
693
+ //#endregion
694
+ //#region src/typed/shared/metadata.ts
695
+ const DocumentMetadataSchema = zod.z.object({
696
+ title: zod.z.string().optional(),
697
+ author: zod.z.string().optional(),
698
+ subject: zod.z.string().optional(),
699
+ keywords: zod.z.array(zod.z.string()).optional(),
700
+ creator: zod.z.string().optional(),
701
+ createdIso: zod.z.string().optional(),
702
+ modifiedIso: zod.z.string().optional()
703
+ });
704
+ const CORE_PROPERTIES_PATH = "docProps/core.xml";
705
+ const APP_PROPERTIES_PATH = "docProps/app.xml";
706
+ function firstElementText(root, tag) {
707
+ if (root === void 0) return;
708
+ const element = childrenWithTag(root, tag)[0];
709
+ if (element === void 0) return;
710
+ const text = textContent(element);
711
+ return text.length > 0 ? text : void 0;
712
+ }
713
+ function readKeywords(core) {
714
+ const raw = firstElementText(core, "cp:keywords");
715
+ if (raw === void 0) return;
716
+ const parts = raw.split(",").map((part) => part.trim()).filter((part) => part.length > 0);
717
+ return parts.length > 0 ? parts : void 0;
718
+ }
719
+ function readCoreProperties(pkg) {
720
+ const core = rootElement(pkg.parts[CORE_PROPERTIES_PATH]);
721
+ const app = rootElement(pkg.parts[APP_PROPERTIES_PATH]);
722
+ return {
723
+ title: firstElementText(core, "dc:title"),
724
+ author: firstElementText(core, "dc:creator"),
725
+ subject: firstElementText(core, "dc:subject"),
726
+ keywords: readKeywords(core),
727
+ creator: firstElementText(app, "Application"),
728
+ createdIso: firstElementText(core, "dcterms:created"),
729
+ modifiedIso: firstElementText(core, "dcterms:modified")
730
+ };
731
+ }
732
+ //#endregion
733
+ //#region src/typed/shared/content.ts
734
+ const ContentRunSchema = zod.z.object({
539
735
  text: zod.z.string(),
540
736
  bold: zod.z.boolean().optional(),
541
- italic: zod.z.boolean().optional()
737
+ italic: zod.z.boolean().optional(),
738
+ underline: zod.z.boolean().optional(),
739
+ strike: zod.z.boolean().optional(),
740
+ fontFamily: zod.z.string().optional(),
741
+ sizePt: zod.z.number().positive().optional(),
742
+ color: ColorSchema.optional(),
743
+ hyperlink: zod.z.string().optional()
542
744
  });
543
- const ListMembershipSchema = zod.z.object({
745
+ const ContentListMembershipSchema = zod.z.object({
544
746
  numId: zod.z.string(),
545
- level: zod.z.number()
747
+ level: zod.z.number().int().nonnegative()
546
748
  });
547
- const ParagraphSchema = zod.z.object({
548
- runs: zod.z.array(RunSchema),
549
- list: ListMembershipSchema.optional()
749
+ const ContentParagraphSchema = zod.z.object({
750
+ kind: zod.z.literal("paragraph"),
751
+ runs: zod.z.array(ContentRunSchema),
752
+ styleId: zod.z.string().optional(),
753
+ alignment: AlignmentSchema.optional(),
754
+ list: ContentListMembershipSchema.optional(),
755
+ spacingBeforePt: zod.z.number().optional(),
756
+ spacingAfterPt: zod.z.number().optional(),
757
+ lineSpacing: zod.z.number().positive().optional(),
758
+ indentLeftPt: zod.z.number().optional(),
759
+ indentFirstLinePt: zod.z.number().optional()
550
760
  });
551
- const TableCellSchema = zod.z.object({ paragraphs: zod.z.array(ParagraphSchema) });
552
- const TableRowSchema = zod.z.object({ cells: zod.z.array(TableCellSchema) });
553
- const TableSchema = zod.z.object({ rows: zod.z.array(TableRowSchema) });
554
- const HyperlinkSchema = zod.z.object({
555
- text: zod.z.string(),
556
- target: zod.z.string()
761
+ const ContentImageBlockSchema = zod.z.object({
762
+ kind: zod.z.literal("image"),
763
+ format: zod.z.enum(["png", "jpeg"]),
764
+ base64: zod.z.string(),
765
+ widthPt: zod.z.number().positive(),
766
+ heightPt: zod.z.number().positive(),
767
+ altText: zod.z.string().optional()
768
+ });
769
+ const ContentPageBreakSchema = zod.z.object({ kind: zod.z.literal("pageBreak") });
770
+ function isRecord(value) {
771
+ return typeof value === "object" && value !== null && !Array.isArray(value);
772
+ }
773
+ function isContentRun(value) {
774
+ return isRecord(value) && typeof value.text === "string";
775
+ }
776
+ function isContentTableCell(value) {
777
+ return isRecord(value) && Array.isArray(value.blocks) && value.blocks.every(isContentBlock);
778
+ }
779
+ function isContentTableRow(value) {
780
+ return isRecord(value) && Array.isArray(value.cells) && value.cells.every(isContentTableCell) && (value.heightPt === void 0 || typeof value.heightPt === "number");
781
+ }
782
+ function isContentBlock(value) {
783
+ if (!isRecord(value)) return false;
784
+ const kind = value.kind;
785
+ if (kind === "paragraph") return Array.isArray(value.runs) && value.runs.every(isContentRun);
786
+ if (kind === "image") return (value.format === "png" || value.format === "jpeg") && typeof value.base64 === "string" && typeof value.widthPt === "number" && typeof value.heightPt === "number";
787
+ if (kind === "pageBreak") return true;
788
+ if (kind === "table") return Array.isArray(value.rows) && value.rows.every(isContentTableRow) && Array.isArray(value.columnWidthsPt) && value.columnWidthsPt.every((w) => typeof w === "number");
789
+ return false;
790
+ }
791
+ const ContentBlockSchema = zod.z.custom(isContentBlock);
792
+ const ContentTableCellSchema = zod.z.object({
793
+ blocks: zod.z.array(ContentBlockSchema),
794
+ colSpan: zod.z.number().int().positive().optional(),
795
+ rowSpan: zod.z.number().int().positive().optional(),
796
+ background: ColorSchema.optional()
797
+ });
798
+ const ContentTableRowSchema = zod.z.object({
799
+ cells: zod.z.array(ContentTableCellSchema),
800
+ heightPt: zod.z.number().positive().optional()
801
+ });
802
+ const ContentTableSchema = zod.z.object({
803
+ kind: zod.z.literal("table"),
804
+ rows: zod.z.array(ContentTableRowSchema),
805
+ columnWidthsPt: zod.z.array(zod.z.number().positive())
557
806
  });
807
+ const ContentSectionSchema = zod.z.object({
808
+ pageSize: PageSizeSchema,
809
+ margins: MarginsSchema,
810
+ blocks: zod.z.array(ContentBlockSchema)
811
+ });
812
+ const ContentShapeSchema = zod.z.object({
813
+ name: zod.z.string().optional(),
814
+ frame: BoxSchema,
815
+ rotationDeg: zod.z.number().optional(),
816
+ insetLeftPt: zod.z.number().nonnegative(),
817
+ insetTopPt: zod.z.number().nonnegative(),
818
+ insetRightPt: zod.z.number().nonnegative(),
819
+ insetBottomPt: zod.z.number().nonnegative(),
820
+ fontScale: zod.z.number().positive().optional(),
821
+ lineSpacingReduction: zod.z.number().nonnegative().optional(),
822
+ blocks: zod.z.array(ContentBlockSchema)
823
+ });
824
+ const ContentSlideSchema = zod.z.object({
825
+ size: PageSizeSchema,
826
+ shapes: zod.z.array(ContentShapeSchema),
827
+ notes: zod.z.string()
828
+ });
829
+ //#endregion
830
+ //#region src/image/sniff.ts
831
+ const PNG_SIGNATURE = [
832
+ 137,
833
+ 80,
834
+ 78,
835
+ 71,
836
+ 13,
837
+ 10,
838
+ 26,
839
+ 10
840
+ ];
841
+ const JPEG_SIGNATURE = [
842
+ 255,
843
+ 216,
844
+ 255
845
+ ];
846
+ function startsWith(bytes, signature) {
847
+ if (bytes.length < signature.length) return false;
848
+ for (let i = 0; i < signature.length; i++) if (bytes[i] !== signature[i]) return false;
849
+ return true;
850
+ }
851
+ function sniffImageFormat(bytes) {
852
+ if (startsWith(bytes, PNG_SIGNATURE)) return "png";
853
+ if (startsWith(bytes, JPEG_SIGNATURE)) return "jpeg";
854
+ }
855
+ const EMU_PER_POINT = 914400 / 72;
856
+ function emuToPt(emu) {
857
+ return emu / EMU_PER_POINT;
858
+ }
859
+ function twipsToPt(twips) {
860
+ return twips / 20;
861
+ }
862
+ function halfPointsToPt(halfPoints) {
863
+ return halfPoints / 2;
864
+ }
865
+ function drawingMlFontSizeToPt(hundredths) {
866
+ return hundredths / 100;
867
+ }
868
+ function lineUnitsToMultiplier(lineUnits) {
869
+ return lineUnits / 240;
870
+ }
871
+ //#endregion
872
+ //#region src/typed/shared/drawingml.ts
873
+ const ROTATION_UNITS_PER_DEGREE = 6e4;
874
+ function readXfrm(xfrm) {
875
+ if (xfrm === void 0) return;
876
+ const off = childrenWithTag(xfrm, "a:off")[0];
877
+ const ext = childrenWithTag(xfrm, "a:ext")[0];
878
+ if (off === void 0 || ext === void 0) return;
879
+ const x = attr(off, "x");
880
+ const y = attr(off, "y");
881
+ const cx = attr(ext, "cx");
882
+ const cy = attr(ext, "cy");
883
+ if (x === void 0 || y === void 0 || cx === void 0 || cy === void 0) return;
884
+ const rot = attr(xfrm, "rot");
885
+ return {
886
+ xPt: emuToPt(Number(x)),
887
+ yPt: emuToPt(Number(y)),
888
+ widthPt: emuToPt(Number(cx)),
889
+ heightPt: emuToPt(Number(cy)),
890
+ rotationDeg: rot === void 0 ? 0 : Number(rot) / ROTATION_UNITS_PER_DEGREE,
891
+ flipH: attr(xfrm, "flipH") === "1",
892
+ flipV: attr(xfrm, "flipV") === "1"
893
+ };
894
+ }
895
+ const CLR_SCHEME_SLOTS = [
896
+ "dk1",
897
+ "lt1",
898
+ "dk2",
899
+ "lt2",
900
+ "accent1",
901
+ "accent2",
902
+ "accent3",
903
+ "accent4",
904
+ "accent5",
905
+ "accent6",
906
+ "hlink",
907
+ "folHlink"
908
+ ];
909
+ function readThemeSlotColor(colorEl) {
910
+ if (colorEl.tag === "a:srgbClr") {
911
+ const val = attr(colorEl, "val");
912
+ return val === void 0 ? void 0 : rgbHexToColor(val);
913
+ }
914
+ if (colorEl.tag === "a:sysClr") {
915
+ const lastClr = attr(colorEl, "lastClr");
916
+ if (lastClr !== void 0) return rgbHexToColor(lastClr);
917
+ return attr(colorEl, "val") === "window" ? {
918
+ r: 1,
919
+ g: 1,
920
+ b: 1
921
+ } : {
922
+ r: 0,
923
+ g: 0,
924
+ b: 0
925
+ };
926
+ }
927
+ }
928
+ function readClrScheme(clrSchemeEl) {
929
+ const map = /* @__PURE__ */ new Map();
930
+ for (const slot of CLR_SCHEME_SLOTS) {
931
+ const wrapper = childrenWithTag(clrSchemeEl, `a:${slot}`)[0];
932
+ if (wrapper === void 0) continue;
933
+ const colorEl = wrapper.children.find((c) => c.type === "element");
934
+ if (colorEl === void 0) continue;
935
+ const color = readThemeSlotColor(colorEl);
936
+ if (color !== void 0) map.set(slot, color);
937
+ }
938
+ return map;
939
+ }
940
+ function readSchemeFont(fontSchemeEl, tag) {
941
+ if (fontSchemeEl === void 0) return;
942
+ const fontEl = childrenWithTag(fontSchemeEl, tag)[0];
943
+ const latin = fontEl === void 0 ? void 0 : childrenWithTag(fontEl, "a:latin")[0];
944
+ return latin === void 0 ? void 0 : attr(latin, "typeface");
945
+ }
946
+ const DEFAULT_THEME_FONT = "Calibri";
947
+ const EMPTY_THEME = {
948
+ colorScheme: /* @__PURE__ */ new Map(),
949
+ majorFont: DEFAULT_THEME_FONT,
950
+ minorFont: DEFAULT_THEME_FONT
951
+ };
952
+ function readTheme(themeRoot) {
953
+ const clrSchemeEl = elementsWithTag([themeRoot], "a:clrScheme")[0];
954
+ const colorScheme = clrSchemeEl === void 0 ? /* @__PURE__ */ new Map() : readClrScheme(clrSchemeEl);
955
+ const fontSchemeEl = elementsWithTag([themeRoot], "a:fontScheme")[0];
956
+ return {
957
+ colorScheme,
958
+ majorFont: readSchemeFont(fontSchemeEl, "a:majorFont") ?? DEFAULT_THEME_FONT,
959
+ minorFont: readSchemeFont(fontSchemeEl, "a:minorFont") ?? DEFAULT_THEME_FONT
960
+ };
961
+ }
962
+ function resolveThemeFontReference(typeface, theme) {
963
+ if (typeface === "+mj-lt") return theme.majorFont;
964
+ if (typeface === "+mn-lt") return theme.minorFont;
965
+ return typeface;
966
+ }
967
+ function readColorMap(clrMapEl) {
968
+ const map = /* @__PURE__ */ new Map();
969
+ if (clrMapEl === void 0) return map;
970
+ for (const a of clrMapEl.attributes) map.set(a.name, a.value);
971
+ return map;
972
+ }
973
+ function resolveSchemeColorSlot(schemeVal, colorMap) {
974
+ return colorMap.get(schemeVal) ?? schemeVal;
975
+ }
976
+ const COLOR_TRANSFORM_TAGS = /* @__PURE__ */ new Map([
977
+ ["a:shade", "shade"],
978
+ ["a:tint", "tint"],
979
+ ["a:lumMod", "lumMod"],
980
+ ["a:lumOff", "lumOff"]
981
+ ]);
982
+ function readColorTransforms(container) {
983
+ const transforms = [];
984
+ for (const child of container.children) {
985
+ if (child.type !== "element") continue;
986
+ const kind = COLOR_TRANSFORM_TAGS.get(child.tag);
987
+ if (kind === void 0) continue;
988
+ const val = attr(child, "val");
989
+ if (val === void 0) continue;
990
+ transforms.push({
991
+ kind,
992
+ value: Number(val)
993
+ });
994
+ }
995
+ return transforms;
996
+ }
997
+ function readSchemeColor(schemeClrEl, colorMap, theme) {
998
+ const val = attr(schemeClrEl, "val");
999
+ if (val === void 0) return;
1000
+ const base = theme.colorScheme.get(resolveSchemeColorSlot(val, colorMap));
1001
+ return base === void 0 ? void 0 : applyColorTransforms(base, readColorTransforms(schemeClrEl));
1002
+ }
1003
+ function readSrgbColor(srgbClrEl) {
1004
+ const val = attr(srgbClrEl, "val");
1005
+ return val === void 0 ? void 0 : applyColorTransforms(rgbHexToColor(val), readColorTransforms(srgbClrEl));
1006
+ }
1007
+ function readSolidFillColor(solidFillEl, colorMap, theme) {
1008
+ if (solidFillEl === void 0) return;
1009
+ const schemeClr = childrenWithTag(solidFillEl, "a:schemeClr")[0];
1010
+ if (schemeClr !== void 0) return readSchemeColor(schemeClr, colorMap, theme);
1011
+ const srgbClr = childrenWithTag(solidFillEl, "a:srgbClr")[0];
1012
+ return srgbClr === void 0 ? void 0 : readSrgbColor(srgbClr);
1013
+ }
1014
+ function readGroupXfrm(xfrm) {
1015
+ const base = readXfrm(xfrm);
1016
+ if (base === void 0 || xfrm === void 0) return;
1017
+ const chOff = childrenWithTag(xfrm, "a:chOff")[0];
1018
+ const chExt = childrenWithTag(xfrm, "a:chExt")[0];
1019
+ if (chOff === void 0 || chExt === void 0) return;
1020
+ const cx = attr(chOff, "x");
1021
+ const cy = attr(chOff, "y");
1022
+ const ccx = attr(chExt, "cx");
1023
+ const ccy = attr(chExt, "cy");
1024
+ if (cx === void 0 || cy === void 0 || ccx === void 0 || ccy === void 0) return;
1025
+ return {
1026
+ offXPt: base.xPt,
1027
+ offYPt: base.yPt,
1028
+ extWidthPt: base.widthPt,
1029
+ extHeightPt: base.heightPt,
1030
+ childOffXPt: emuToPt(Number(cx)),
1031
+ childOffYPt: emuToPt(Number(cy)),
1032
+ childExtWidthPt: emuToPt(Number(ccx)),
1033
+ childExtHeightPt: emuToPt(Number(ccy))
1034
+ };
1035
+ }
1036
+ function applyGroupTransform(group, childFrame) {
1037
+ const scaleX = group.childExtWidthPt === 0 ? 1 : group.extWidthPt / group.childExtWidthPt;
1038
+ const scaleY = group.childExtHeightPt === 0 ? 1 : group.extHeightPt / group.childExtHeightPt;
1039
+ return {
1040
+ xPt: group.offXPt + (childFrame.xPt - group.childOffXPt) * scaleX,
1041
+ yPt: group.offYPt + (childFrame.yPt - group.childOffYPt) * scaleY,
1042
+ widthPt: childFrame.widthPt * scaleX,
1043
+ heightPt: childFrame.heightPt * scaleY
1044
+ };
1045
+ }
1046
+ //#endregion
1047
+ //#region src/typed/docx/styles.ts
1048
+ function mergeParagraphLayer(base, layer) {
1049
+ return {
1050
+ alignment: layer.alignment ?? base.alignment,
1051
+ spacingBeforePt: layer.spacingBeforePt ?? base.spacingBeforePt,
1052
+ spacingAfterPt: layer.spacingAfterPt ?? base.spacingAfterPt,
1053
+ lineSpacing: layer.lineSpacing ?? base.lineSpacing,
1054
+ indentLeftPt: layer.indentLeftPt ?? base.indentLeftPt,
1055
+ indentFirstLinePt: layer.indentFirstLinePt ?? base.indentFirstLinePt
1056
+ };
1057
+ }
1058
+ function mergeRunLayer(base, layer) {
1059
+ return {
1060
+ bold: layer.bold ?? base.bold,
1061
+ italic: layer.italic ?? base.italic,
1062
+ underline: layer.underline ?? base.underline,
1063
+ strike: layer.strike ?? base.strike,
1064
+ fontFamily: layer.fontFamily ?? base.fontFamily,
1065
+ sizePt: layer.sizePt ?? base.sizePt,
1066
+ color: layer.color ?? base.color
1067
+ };
1068
+ }
1069
+ function readToggle$1(el) {
1070
+ if (el === void 0) return;
1071
+ const val = attr(el, "w:val");
1072
+ return val === void 0 || val !== "0" && val !== "false" && val !== "off";
1073
+ }
1074
+ function readUnderline(u) {
1075
+ if (u === void 0) return;
1076
+ const val = attr(u, "w:val");
1077
+ return val !== void 0 && val !== "none";
1078
+ }
1079
+ function readRunColor(colorEl) {
1080
+ if (colorEl === void 0) return;
1081
+ const val = attr(colorEl, "w:val");
1082
+ return val === void 0 || val === "auto" ? void 0 : rgbHexToColor(val);
1083
+ }
1084
+ function readRunFontFamily(rFonts, theme) {
1085
+ if (rFonts === void 0) return;
1086
+ const ascii = attr(rFonts, "w:ascii");
1087
+ if (ascii !== void 0) return ascii;
1088
+ const asciiTheme = attr(rFonts, "w:asciiTheme");
1089
+ if (asciiTheme === "majorHAnsi" || asciiTheme === "majorAscii") return theme.majorFont;
1090
+ if (asciiTheme === "minorHAnsi" || asciiTheme === "minorAscii") return theme.minorFont;
1091
+ }
1092
+ function readRunPropertiesLayer(rPr, theme) {
1093
+ if (rPr === void 0) return {};
1094
+ const sz = childrenWithTag(rPr, "w:sz")[0];
1095
+ const szVal = sz === void 0 ? void 0 : attr(sz, "w:val");
1096
+ return {
1097
+ bold: readToggle$1(childrenWithTag(rPr, "w:b")[0]),
1098
+ italic: readToggle$1(childrenWithTag(rPr, "w:i")[0]),
1099
+ underline: readUnderline(childrenWithTag(rPr, "w:u")[0]),
1100
+ strike: readToggle$1(childrenWithTag(rPr, "w:strike")[0]),
1101
+ fontFamily: readRunFontFamily(childrenWithTag(rPr, "w:rFonts")[0], theme),
1102
+ sizePt: szVal === void 0 ? void 0 : halfPointsToPt(Number(szVal)),
1103
+ color: readRunColor(childrenWithTag(rPr, "w:color")[0])
1104
+ };
1105
+ }
1106
+ function readAlignment$1(jc) {
1107
+ const val = jc === void 0 ? void 0 : attr(jc, "w:val");
1108
+ if (val === "left" || val === "start") return "left";
1109
+ if (val === "center") return "center";
1110
+ if (val === "right" || val === "end") return "right";
1111
+ if (val === "both" || val === "distribute") return "justify";
1112
+ }
1113
+ function readParagraphPropertiesLayer(pPr) {
1114
+ if (pPr === void 0) return {};
1115
+ const spacing = childrenWithTag(pPr, "w:spacing")[0];
1116
+ const before = spacing === void 0 ? void 0 : attr(spacing, "w:before");
1117
+ const after = spacing === void 0 ? void 0 : attr(spacing, "w:after");
1118
+ const line = spacing === void 0 ? void 0 : attr(spacing, "w:line");
1119
+ const lineRule = spacing === void 0 ? void 0 : attr(spacing, "w:lineRule");
1120
+ const ind = childrenWithTag(pPr, "w:ind")[0];
1121
+ const left = ind === void 0 ? void 0 : attr(ind, "w:left") ?? attr(ind, "w:start");
1122
+ const firstLine = ind === void 0 ? void 0 : attr(ind, "w:firstLine");
1123
+ const hanging = ind === void 0 ? void 0 : attr(ind, "w:hanging");
1124
+ return {
1125
+ alignment: readAlignment$1(childrenWithTag(pPr, "w:jc")[0]),
1126
+ spacingBeforePt: before === void 0 ? void 0 : twipsToPt(Number(before)),
1127
+ spacingAfterPt: after === void 0 ? void 0 : twipsToPt(Number(after)),
1128
+ lineSpacing: line === void 0 || lineRule === "exact" || lineRule === "atLeast" ? void 0 : lineUnitsToMultiplier(Number(line)),
1129
+ indentLeftPt: left === void 0 ? void 0 : twipsToPt(Number(left)),
1130
+ indentFirstLinePt: firstLine !== void 0 ? twipsToPt(Number(firstLine)) : hanging !== void 0 ? -twipsToPt(Number(hanging)) : void 0
1131
+ };
1132
+ }
1133
+ function findStyle(stylesRoot, styleId, type) {
1134
+ return elementsWithTag([stylesRoot], "w:style").find((s) => attr(s, "w:type") === type && attr(s, "w:styleId") === styleId);
1135
+ }
1136
+ function findDefaultStyle(stylesRoot, type) {
1137
+ return elementsWithTag([stylesRoot], "w:style").find((s) => attr(s, "w:type") === type && attr(s, "w:default") === "1");
1138
+ }
1139
+ function resolveBasedOnChain(stylesRoot, styleId, type) {
1140
+ const chain = [];
1141
+ const visited = /* @__PURE__ */ new Set();
1142
+ let currentId = styleId;
1143
+ while (currentId !== void 0 && !visited.has(currentId)) {
1144
+ visited.add(currentId);
1145
+ const style = findStyle(stylesRoot, currentId, type);
1146
+ if (style === void 0) break;
1147
+ chain.unshift(style);
1148
+ const basedOn = childrenWithTag(style, "w:basedOn")[0];
1149
+ currentId = basedOn === void 0 ? void 0 : attr(basedOn, "w:val");
1150
+ }
1151
+ return chain;
1152
+ }
1153
+ function docDefaultsElement(stylesRoot, wrapperTag, innerTag) {
1154
+ const docDefaults = stylesRoot === void 0 ? void 0 : childrenWithTag(stylesRoot, "w:docDefaults")[0];
1155
+ const wrapper = docDefaults === void 0 ? void 0 : childrenWithTag(docDefaults, wrapperTag)[0];
1156
+ return wrapper === void 0 ? void 0 : childrenWithTag(wrapper, innerTag)[0];
1157
+ }
1158
+ function resolveParagraphProperties(paragraph, context) {
1159
+ const pPr = childrenWithTag(paragraph, "w:pPr")[0];
1160
+ const pStyleEl = pPr === void 0 ? void 0 : childrenWithTag(pPr, "w:pStyle")[0];
1161
+ const styleId = pStyleEl === void 0 ? void 0 : attr(pStyleEl, "w:val");
1162
+ let resolved = readParagraphPropertiesLayer(docDefaultsElement(context.stylesRoot, "w:pPrDefault", "w:pPr"));
1163
+ if (context.stylesRoot !== void 0) {
1164
+ const defaultStyle = findDefaultStyle(context.stylesRoot, "paragraph");
1165
+ if (defaultStyle !== void 0) resolved = mergeParagraphLayer(resolved, readParagraphPropertiesLayer(childrenWithTag(defaultStyle, "w:pPr")[0]));
1166
+ if (styleId !== void 0) for (const style of resolveBasedOnChain(context.stylesRoot, styleId, "paragraph")) resolved = mergeParagraphLayer(resolved, readParagraphPropertiesLayer(childrenWithTag(style, "w:pPr")[0]));
1167
+ }
1168
+ return mergeParagraphLayer(resolved, readParagraphPropertiesLayer(pPr));
1169
+ }
1170
+ function resolveRunProperties(run, paragraph, context) {
1171
+ const pPr = childrenWithTag(paragraph, "w:pPr")[0];
1172
+ const pStyleEl = pPr === void 0 ? void 0 : childrenWithTag(pPr, "w:pStyle")[0];
1173
+ const pStyleId = pStyleEl === void 0 ? void 0 : attr(pStyleEl, "w:val");
1174
+ let resolved = readRunPropertiesLayer(docDefaultsElement(context.stylesRoot, "w:rPrDefault", "w:rPr"), context.theme);
1175
+ if (context.stylesRoot !== void 0) {
1176
+ const defaultStyle = findDefaultStyle(context.stylesRoot, "paragraph");
1177
+ if (defaultStyle !== void 0) resolved = mergeRunLayer(resolved, readRunPropertiesLayer(childrenWithTag(defaultStyle, "w:rPr")[0], context.theme));
1178
+ if (pStyleId !== void 0) for (const style of resolveBasedOnChain(context.stylesRoot, pStyleId, "paragraph")) resolved = mergeRunLayer(resolved, readRunPropertiesLayer(childrenWithTag(style, "w:rPr")[0], context.theme));
1179
+ }
1180
+ const paragraphMarkRPr = pPr === void 0 ? void 0 : childrenWithTag(pPr, "w:rPr")[0];
1181
+ resolved = mergeRunLayer(resolved, readRunPropertiesLayer(paragraphMarkRPr, context.theme));
1182
+ const rPr = childrenWithTag(run, "w:rPr")[0];
1183
+ const rStyleEl = rPr === void 0 ? void 0 : childrenWithTag(rPr, "w:rStyle")[0];
1184
+ const rStyleId = rStyleEl === void 0 ? void 0 : attr(rStyleEl, "w:val");
1185
+ if (context.stylesRoot !== void 0 && rStyleId !== void 0) for (const style of resolveBasedOnChain(context.stylesRoot, rStyleId, "character")) resolved = mergeRunLayer(resolved, readRunPropertiesLayer(childrenWithTag(style, "w:rPr")[0], context.theme));
1186
+ return mergeRunLayer(resolved, readRunPropertiesLayer(rPr, context.theme));
1187
+ }
1188
+ //#endregion
1189
+ //#region src/typed/docx/read.ts
558
1190
  const CommentSchema = zod.z.object({
559
1191
  author: zod.z.string().optional(),
560
1192
  text: zod.z.string()
@@ -564,62 +1196,256 @@ const FootnoteSchema = zod.z.object({
564
1196
  text: zod.z.string()
565
1197
  });
566
1198
  const DocxDocumentSchema = zod.z.object({
567
- paragraphs: zod.z.array(ParagraphSchema),
568
- tables: zod.z.array(TableSchema),
569
- hyperlinks: zod.z.array(HyperlinkSchema),
1199
+ metadata: DocumentMetadataSchema,
1200
+ sections: zod.z.array(ContentSectionSchema),
570
1201
  comments: zod.z.array(CommentSchema),
571
1202
  footnotes: zod.z.array(FootnoteSchema),
572
1203
  headers: zod.z.array(zod.z.string()),
573
1204
  footers: zod.z.array(zod.z.string())
574
1205
  });
575
- function runPropertyOn(run, tag) {
576
- const rPr = run.children.find((child) => child.type === "element" && child.tag === "w:rPr");
577
- return rPr !== void 0 && elementsWithTag(rPr.children, tag).length > 0;
1206
+ const DOCUMENT_PART_PATH = "word/document.xml";
1207
+ const STYLES_PART_PATH = "word/styles.xml";
1208
+ const THEME_REL_SUFFIX$1 = "/theme";
1209
+ const DEFAULT_MARGIN_PT = 72;
1210
+ const DEFAULT_MARGINS = {
1211
+ topPt: DEFAULT_MARGIN_PT,
1212
+ rightPt: DEFAULT_MARGIN_PT,
1213
+ bottomPt: DEFAULT_MARGIN_PT,
1214
+ leftPt: DEFAULT_MARGIN_PT
1215
+ };
1216
+ function readPageSize(sectPr) {
1217
+ const pgSz = childrenWithTag(sectPr, "w:pgSz")[0];
1218
+ const w = pgSz === void 0 ? void 0 : attr(pgSz, "w:w");
1219
+ const h = pgSz === void 0 ? void 0 : attr(pgSz, "w:h");
1220
+ return w === void 0 || h === void 0 ? PAGE_SIZE_LETTER : {
1221
+ widthPt: twipsToPt(Number(w)),
1222
+ heightPt: twipsToPt(Number(h))
1223
+ };
578
1224
  }
579
- function readRun(run) {
580
- const result = { text: elementsWithTag(run.children, "w:t").map(textContent).join("") };
581
- if (runPropertyOn(run, "w:b")) result.bold = true;
582
- if (runPropertyOn(run, "w:i")) result.italic = true;
583
- return result;
1225
+ function readMargins(sectPr) {
1226
+ const pgMar = childrenWithTag(sectPr, "w:pgMar")[0];
1227
+ if (pgMar === void 0) return DEFAULT_MARGINS;
1228
+ const top = attr(pgMar, "w:top");
1229
+ const right = attr(pgMar, "w:right");
1230
+ const bottom = attr(pgMar, "w:bottom");
1231
+ const left = attr(pgMar, "w:left");
1232
+ return {
1233
+ topPt: top === void 0 ? DEFAULT_MARGIN_PT : twipsToPt(Number(top)),
1234
+ rightPt: right === void 0 ? DEFAULT_MARGIN_PT : twipsToPt(Number(right)),
1235
+ bottomPt: bottom === void 0 ? DEFAULT_MARGIN_PT : twipsToPt(Number(bottom)),
1236
+ leftPt: left === void 0 ? DEFAULT_MARGIN_PT : twipsToPt(Number(left))
1237
+ };
584
1238
  }
585
- function readListMembership(paragraph) {
586
- const pPr = childrenWithTag(paragraph, "w:pPr")[0];
587
- if (pPr === void 0) return;
588
- const numPr = childrenWithTag(pPr, "w:numPr")[0];
1239
+ function readListMembership(pPr) {
1240
+ const numPr = pPr === void 0 ? void 0 : childrenWithTag(pPr, "w:numPr")[0];
589
1241
  if (numPr === void 0) return;
590
1242
  const numIdEl = childrenWithTag(numPr, "w:numId")[0];
591
- const numId = numIdEl !== void 0 ? attr(numIdEl, "w:val") : void 0;
1243
+ const numId = numIdEl === void 0 ? void 0 : attr(numIdEl, "w:val");
592
1244
  if (numId === void 0) return;
593
1245
  const ilvlEl = childrenWithTag(numPr, "w:ilvl")[0];
594
- const ilvlVal = ilvlEl !== void 0 ? attr(ilvlEl, "w:val") : void 0;
1246
+ const ilvlVal = ilvlEl === void 0 ? void 0 : attr(ilvlEl, "w:val");
595
1247
  return {
596
1248
  numId,
597
- level: ilvlVal !== void 0 ? Number(ilvlVal) : 0
1249
+ level: ilvlVal === void 0 ? 0 : Number(ilvlVal)
598
1250
  };
599
1251
  }
600
- function readParagraph(paragraph) {
601
- const result = { runs: elementsWithTag(paragraph.children, "w:r").map(readRun) };
602
- const list = readListMembership(paragraph);
603
- if (list !== void 0) result.list = list;
604
- return result;
1252
+ function readToggle(el) {
1253
+ if (el === void 0) return false;
1254
+ const val = attr(el, "w:val");
1255
+ return val === void 0 || val !== "0" && val !== "false" && val !== "off";
1256
+ }
1257
+ function hasPageBreakBefore(paragraph) {
1258
+ const pPr = childrenWithTag(paragraph, "w:pPr")[0];
1259
+ return readToggle(pPr === void 0 ? void 0 : childrenWithTag(pPr, "w:pageBreakBefore")[0]);
1260
+ }
1261
+ function readRunText(run) {
1262
+ let text = "";
1263
+ for (const child of run.children) {
1264
+ if (child.type !== "element") continue;
1265
+ if (child.tag === "w:t") text += textContent(child);
1266
+ else if (child.tag === "w:tab") text += " ";
1267
+ else if (child.tag === "w:br" || child.tag === "w:cr") text += "\n";
1268
+ }
1269
+ return text;
605
1270
  }
606
- function readCell$1(cell) {
607
- return { paragraphs: childrenWithTag(cell, "w:p").map(readParagraph) };
1271
+ function readRun$1(run, paragraph, context) {
1272
+ const props = resolveRunProperties(run, paragraph, context);
1273
+ return {
1274
+ text: readRunText(run),
1275
+ bold: props.bold,
1276
+ italic: props.italic,
1277
+ underline: props.underline,
1278
+ strike: props.strike,
1279
+ fontFamily: props.fontFamily,
1280
+ sizePt: props.sizePt,
1281
+ color: props.color
1282
+ };
608
1283
  }
609
- function readRow(row) {
610
- return { cells: childrenWithTag(row, "w:tc").map(readCell$1) };
1284
+ function readParagraphRuns(paragraph, context, rels) {
1285
+ const runs = [];
1286
+ let fieldState = "none";
1287
+ function walk(nodes, hyperlinkTarget) {
1288
+ for (const node of nodes) {
1289
+ if (node.type !== "element") continue;
1290
+ if (node.tag === "w:r") {
1291
+ const fldChar = childrenWithTag(node, "w:fldChar")[0];
1292
+ if (fldChar !== void 0) {
1293
+ const type = attr(fldChar, "w:fldCharType");
1294
+ if (type === "begin") fieldState = "code";
1295
+ else if (type === "separate") fieldState = "result";
1296
+ else if (type === "end") fieldState = "none";
1297
+ continue;
1298
+ }
1299
+ if (fieldState === "code") continue;
1300
+ const run = readRun$1(node, paragraph, context);
1301
+ runs.push(hyperlinkTarget === void 0 ? run : {
1302
+ ...run,
1303
+ hyperlink: hyperlinkTarget
1304
+ });
1305
+ } else if (node.tag === "w:fldSimple") walk(node.children, hyperlinkTarget);
1306
+ else if (node.tag === "w:hyperlink") {
1307
+ const rId = attr(node, "r:id");
1308
+ const target = rId === void 0 ? void 0 : rels.get(rId)?.target;
1309
+ walk(node.children, target ?? hyperlinkTarget);
1310
+ } else if (node.tag === "w:ins") walk(node.children, hyperlinkTarget);
1311
+ }
1312
+ }
1313
+ walk(paragraph.children, void 0);
1314
+ return runs;
1315
+ }
1316
+ function readParagraph$1(paragraph, context, rels) {
1317
+ const pPr = childrenWithTag(paragraph, "w:pPr")[0];
1318
+ const pStyleEl = pPr === void 0 ? void 0 : childrenWithTag(pPr, "w:pStyle")[0];
1319
+ const props = resolveParagraphProperties(paragraph, context);
1320
+ return {
1321
+ kind: "paragraph",
1322
+ runs: readParagraphRuns(paragraph, context, rels),
1323
+ styleId: pStyleEl === void 0 ? void 0 : attr(pStyleEl, "w:val"),
1324
+ alignment: props.alignment,
1325
+ list: readListMembership(pPr),
1326
+ spacingBeforePt: props.spacingBeforePt,
1327
+ spacingAfterPt: props.spacingAfterPt,
1328
+ lineSpacing: props.lineSpacing,
1329
+ indentLeftPt: props.indentLeftPt,
1330
+ indentFirstLinePt: props.indentFirstLinePt
1331
+ };
611
1332
  }
612
- function readTable$1(table) {
613
- return { rows: childrenWithTag(table, "w:tr").map(readRow) };
1333
+ function readCellShading(tcPr) {
1334
+ const shd = tcPr === void 0 ? void 0 : childrenWithTag(tcPr, "w:shd")[0];
1335
+ const fill = shd === void 0 ? void 0 : attr(shd, "w:fill");
1336
+ return fill === void 0 || fill === "auto" || fill === "none" ? void 0 : rgbHexToColor(fill);
1337
+ }
1338
+ function readRawCell(tc, context, rels) {
1339
+ const tcPr = childrenWithTag(tc, "w:tcPr")[0];
1340
+ const gridSpanEl = tcPr === void 0 ? void 0 : childrenWithTag(tcPr, "w:gridSpan")[0];
1341
+ const gridSpanVal = gridSpanEl === void 0 ? void 0 : attr(gridSpanEl, "w:val");
1342
+ const vMerge = tcPr === void 0 ? void 0 : childrenWithTag(tcPr, "w:vMerge")[0];
1343
+ const vMergeVal = vMerge === void 0 ? void 0 : attr(vMerge, "w:val") ?? "continue";
1344
+ return {
1345
+ gridSpan: gridSpanVal === void 0 ? 1 : Number(gridSpanVal),
1346
+ isVMergeContinuation: vMergeVal === "continue",
1347
+ background: readCellShading(tcPr),
1348
+ blocks: readBodyBlocks(tc.children, context, rels)
1349
+ };
614
1350
  }
615
- function readHyperlink(hyperlink, rels) {
616
- const text = elementsWithTag(hyperlink.children, "w:t").map(textContent).join("");
617
- const rid = attr(hyperlink, "r:id");
1351
+ function readTable$1(tbl, context, rels) {
1352
+ const tblGrid = childrenWithTag(tbl, "w:tblGrid")[0];
1353
+ const columnWidthsPt = tblGrid === void 0 ? [] : childrenWithTag(tblGrid, "w:gridCol").map((col) => twipsToPt(Number(attr(col, "w:w") ?? "0")));
1354
+ const rawRows = childrenWithTag(tbl, "w:tr").map((tr) => childrenWithTag(tr, "w:tc").map((tc) => readRawCell(tc, context, rels)));
1355
+ const rowColumnIndices = rawRows.map((row) => {
1356
+ const indices = [];
1357
+ let col = 0;
1358
+ for (const cell of row) {
1359
+ indices.push(col);
1360
+ col += cell.gridSpan;
1361
+ }
1362
+ return indices;
1363
+ });
618
1364
  return {
619
- text,
620
- target: rid !== void 0 ? rels.get(rid)?.target ?? "" : ""
1365
+ kind: "table",
1366
+ columnWidthsPt,
1367
+ rows: rawRows.map((row, rowIndex) => ({ cells: row.map((cell, cellIndex) => {
1368
+ if (cell.isVMergeContinuation) return { blocks: [] };
1369
+ const colIndex = rowColumnIndices[rowIndex][cellIndex];
1370
+ let rowSpan = 1;
1371
+ for (let r = rowIndex + 1; r < rawRows.length; r++) {
1372
+ const matchIndex = rowColumnIndices[r].indexOf(colIndex);
1373
+ if (!(matchIndex === -1 ? void 0 : rawRows[r][matchIndex])?.isVMergeContinuation) break;
1374
+ rowSpan++;
1375
+ }
1376
+ return {
1377
+ blocks: cell.blocks,
1378
+ colSpan: cell.gridSpan > 1 ? cell.gridSpan : void 0,
1379
+ rowSpan: rowSpan > 1 ? rowSpan : void 0,
1380
+ background: cell.background
1381
+ };
1382
+ }) }))
621
1383
  };
622
1384
  }
1385
+ function readBodyBlocks(nodes, context, rels) {
1386
+ const blocks = [];
1387
+ for (const node of nodes) {
1388
+ if (node.type !== "element") continue;
1389
+ if (node.tag === "w:p") {
1390
+ if (hasPageBreakBefore(node)) blocks.push({ kind: "pageBreak" });
1391
+ blocks.push(readParagraph$1(node, context, rels));
1392
+ } else if (node.tag === "w:tbl") blocks.push(readTable$1(node, context, rels));
1393
+ else if (node.tag === "w:sdt") {
1394
+ const sdtContent = childrenWithTag(node, "w:sdtContent")[0];
1395
+ if (sdtContent !== void 0) blocks.push(...readBodyBlocks(sdtContent.children, context, rels));
1396
+ } else if (node.tag === "w:ins") blocks.push(...readBodyBlocks(node.children, context, rels));
1397
+ else if (node.tag === "mc:AlternateContent") {
1398
+ const target = childrenWithTag(node, "mc:Fallback")[0] ?? childrenWithTag(node, "mc:Choice")[0];
1399
+ if (target !== void 0) blocks.push(...readBodyBlocks(target.children, context, rels));
1400
+ }
1401
+ }
1402
+ return blocks;
1403
+ }
1404
+ function readSections(body, context, rels) {
1405
+ const sections = [];
1406
+ let currentBlocks = [];
1407
+ for (const node of body.children) {
1408
+ if (node.type !== "element") continue;
1409
+ if (node.tag === "w:sectPr") {
1410
+ sections.push({
1411
+ pageSize: readPageSize(node),
1412
+ margins: readMargins(node),
1413
+ blocks: currentBlocks
1414
+ });
1415
+ currentBlocks = [];
1416
+ continue;
1417
+ }
1418
+ if (node.tag === "w:p") {
1419
+ const pPr = childrenWithTag(node, "w:pPr")[0];
1420
+ const sectPr = pPr === void 0 ? void 0 : childrenWithTag(pPr, "w:sectPr")[0];
1421
+ if (hasPageBreakBefore(node)) currentBlocks.push({ kind: "pageBreak" });
1422
+ currentBlocks.push(readParagraph$1(node, context, rels));
1423
+ if (sectPr !== void 0) {
1424
+ sections.push({
1425
+ pageSize: readPageSize(sectPr),
1426
+ margins: readMargins(sectPr),
1427
+ blocks: currentBlocks
1428
+ });
1429
+ currentBlocks = [];
1430
+ }
1431
+ continue;
1432
+ }
1433
+ currentBlocks.push(...readBodyBlocks([node], context, rels));
1434
+ }
1435
+ if (currentBlocks.length > 0 || sections.length === 0) sections.push({
1436
+ pageSize: PAGE_SIZE_LETTER,
1437
+ margins: DEFAULT_MARGINS,
1438
+ blocks: currentBlocks
1439
+ });
1440
+ return sections;
1441
+ }
1442
+ function readDocumentTheme(pkg, docRels) {
1443
+ for (const rel of docRels.values()) if (rel.type.endsWith(THEME_REL_SUFFIX$1)) {
1444
+ const themeRoot = rootElement(pkg.parts[rel.target]);
1445
+ if (themeRoot !== void 0) return readTheme(themeRoot);
1446
+ }
1447
+ return EMPTY_THEME;
1448
+ }
623
1449
  function readComment(comment) {
624
1450
  const author = attr(comment, "w:author");
625
1451
  const result = { text: elementsWithTag(comment.children, "w:t").map(textContent).join("") };
@@ -659,14 +1485,18 @@ function readHeaderFooterText(pkg, prefix) {
659
1485
  return out;
660
1486
  }
661
1487
  function readDocx(pkg) {
662
- const part = pkg.parts["word/document.xml"];
663
- if (part === void 0) throw new Error("readDocx: package has no word/document.xml part");
664
- if (part.kind !== "xml") throw new Error("readDocx: word/document.xml is not an XML part");
665
- const rels = resolveRelationships(pkg, "word/document.xml");
666
- return {
667
- paragraphs: elementsWithTag(part.nodes, "w:p").map(readParagraph),
668
- tables: elementsWithTag(part.nodes, "w:tbl").map(readTable$1),
669
- hyperlinks: elementsWithTag(part.nodes, "w:hyperlink").map((h) => readHyperlink(h, rels)),
1488
+ const documentRoot = rootElement(pkg.parts[DOCUMENT_PART_PATH]);
1489
+ if (documentRoot === void 0) throw new Error(`readDocx: package has no ${DOCUMENT_PART_PATH} part`);
1490
+ const body = childrenWithTag(documentRoot, "w:body")[0];
1491
+ if (body === void 0) throw new Error(`readDocx: ${DOCUMENT_PART_PATH} has no w:body element`);
1492
+ const docRels = resolveRelationships(pkg, DOCUMENT_PART_PATH);
1493
+ const context = {
1494
+ stylesRoot: rootElement(pkg.parts[STYLES_PART_PATH]),
1495
+ theme: readDocumentTheme(pkg, docRels)
1496
+ };
1497
+ return {
1498
+ metadata: readCoreProperties(pkg),
1499
+ sections: readSections(body, context, docRels),
670
1500
  comments: readComments(pkg),
671
1501
  footnotes: readFootnotes(pkg),
672
1502
  headers: readHeaderFooterText(pkg, "word/header"),
@@ -674,72 +1504,434 @@ function readDocx(pkg) {
674
1504
  };
675
1505
  }
676
1506
  //#endregion
677
- //#region src/typed/pptx.ts
678
- const ShapeSchema = zod.z.object({ text: zod.z.string() });
679
- const PptxTableCellSchema = zod.z.object({ text: zod.z.string() });
680
- const PptxTableRowSchema = zod.z.object({ cells: zod.z.array(PptxTableCellSchema) });
681
- const PptxTableSchema = zod.z.object({ rows: zod.z.array(PptxTableRowSchema) });
682
- const SlideSchema = zod.z.object({
683
- index: zod.z.number().int(),
684
- text: zod.z.string(),
685
- shapes: zod.z.array(ShapeSchema),
686
- tables: zod.z.array(PptxTableSchema),
687
- notes: zod.z.string()
1507
+ //#region src/typed/pptx/inherit.ts
1508
+ const SLIDE_LAYOUT_REL_SUFFIX = "/slideLayout";
1509
+ const SLIDE_MASTER_REL_SUFFIX = "/slideMaster";
1510
+ const THEME_REL_SUFFIX = "/theme";
1511
+ function findRelTarget(pkg, partPath, typeSuffix) {
1512
+ for (const rel of resolveRelationships(pkg, partPath).values()) if (rel.type.endsWith(typeSuffix)) return rel.target;
1513
+ }
1514
+ function resolveSlideInheritance(pkg, slidePath) {
1515
+ const layoutPath = findRelTarget(pkg, slidePath, SLIDE_LAYOUT_REL_SUFFIX);
1516
+ const layoutRoot = layoutPath === void 0 ? void 0 : rootElement(pkg.parts[layoutPath]);
1517
+ const masterPath = layoutPath === void 0 ? void 0 : findRelTarget(pkg, layoutPath, SLIDE_MASTER_REL_SUFFIX);
1518
+ const masterRoot = masterPath === void 0 ? void 0 : rootElement(pkg.parts[masterPath]);
1519
+ const themePath = masterPath === void 0 ? void 0 : findRelTarget(pkg, masterPath, THEME_REL_SUFFIX);
1520
+ const themeRoot = themePath === void 0 ? void 0 : rootElement(pkg.parts[themePath]);
1521
+ return {
1522
+ layoutRoot,
1523
+ masterRoot,
1524
+ theme: themeRoot === void 0 ? EMPTY_THEME : readTheme(themeRoot),
1525
+ colorMap: readColorMap(masterRoot === void 0 ? void 0 : childrenWithTag(masterRoot, "p:clrMap")[0])
1526
+ };
1527
+ }
1528
+ const TYPE_NORMALIZATION = /* @__PURE__ */ new Map([["ctrTitle", "title"], ["subTitle", "body"]]);
1529
+ function normalizePlaceholderType(type) {
1530
+ return type === void 0 ? void 0 : TYPE_NORMALIZATION.get(type) ?? type;
1531
+ }
1532
+ function readPlaceholderKey(shape) {
1533
+ const ph = elementsWithTag([shape], "p:ph")[0];
1534
+ return ph === void 0 ? void 0 : {
1535
+ type: attr(ph, "type"),
1536
+ idx: attr(ph, "idx")
1537
+ };
1538
+ }
1539
+ function shapesOf(root) {
1540
+ return root === void 0 ? [] : elementsWithTag([root], "p:sp");
1541
+ }
1542
+ function findMatchingPlaceholder(root, key) {
1543
+ const shapes = shapesOf(root);
1544
+ if (key.idx !== void 0) {
1545
+ const byIdx = shapes.find((shape) => readPlaceholderKey(shape)?.idx === key.idx);
1546
+ if (byIdx !== void 0) return byIdx;
1547
+ }
1548
+ const normalizedTarget = normalizePlaceholderType(key.type);
1549
+ if (normalizedTarget === void 0) return;
1550
+ return shapes.find((shape) => normalizePlaceholderType(readPlaceholderKey(shape)?.type) === normalizedTarget);
1551
+ }
1552
+ function shapeXfrm(shape) {
1553
+ if (shape === void 0) return;
1554
+ const spPr = childrenWithTag(shape, "p:spPr")[0];
1555
+ return spPr === void 0 ? void 0 : readXfrm(childrenWithTag(spPr, "a:xfrm")[0]);
1556
+ }
1557
+ function resolvePlaceholderXfrm(key, context) {
1558
+ return shapeXfrm(findMatchingPlaceholder(context.layoutRoot, key)) ?? shapeXfrm(findMatchingPlaceholder(context.masterRoot, key));
1559
+ }
1560
+ function readRunPropertiesFromElement(rPr, context) {
1561
+ const sz = attr(rPr, "sz");
1562
+ const latin = childrenWithTag(rPr, "a:latin")[0];
1563
+ const typeface = latin === void 0 ? void 0 : attr(latin, "typeface");
1564
+ const solidFill = childrenWithTag(rPr, "a:solidFill")[0];
1565
+ const bold = attr(rPr, "b");
1566
+ const italic = attr(rPr, "i");
1567
+ return {
1568
+ fontFamily: typeface === void 0 ? void 0 : resolveThemeFontReference(typeface, context.theme),
1569
+ sizePt: sz === void 0 ? void 0 : drawingMlFontSizeToPt(Number(sz)),
1570
+ bold: bold === void 0 ? void 0 : bold === "1",
1571
+ italic: italic === void 0 ? void 0 : italic === "1",
1572
+ color: readSolidFillColor(solidFill, context.colorMap, context.theme)
1573
+ };
1574
+ }
1575
+ function txStyleTagFor(placeholderType) {
1576
+ const normalized = normalizePlaceholderType(placeholderType);
1577
+ if (normalized === "title") return "p:titleStyle";
1578
+ if (normalized === "body") return "p:bodyStyle";
1579
+ return "p:otherStyle";
1580
+ }
1581
+ function levelTag(level) {
1582
+ return `a:lvl${Math.min(Math.max(level, 0), 8) + 1}pPr`;
1583
+ }
1584
+ function resolveDefaultRunProperties(placeholderType, level, context) {
1585
+ if (context.masterRoot === void 0) return {};
1586
+ const txStyles = childrenWithTag(context.masterRoot, "p:txStyles")[0];
1587
+ const styleEl = txStyles === void 0 ? void 0 : childrenWithTag(txStyles, txStyleTagFor(placeholderType))[0];
1588
+ const lvlPPr = styleEl === void 0 ? void 0 : childrenWithTag(styleEl, levelTag(level))[0];
1589
+ const defRPr = lvlPPr === void 0 ? void 0 : childrenWithTag(lvlPPr, "a:defRPr")[0];
1590
+ return defRPr === void 0 ? {} : readRunPropertiesFromElement(defRPr, context);
1591
+ }
1592
+ //#endregion
1593
+ //#region src/typed/pptx/read.ts
1594
+ const PptxDocumentSchema = zod.z.object({
1595
+ metadata: DocumentMetadataSchema,
1596
+ slides: zod.z.array(ContentSlideSchema)
688
1597
  });
689
- const PptxPresentationSchema = zod.z.object({ slides: zod.z.array(SlideSchema) });
690
- const SLIDE_PATH = /^ppt\/slides\/slide(\d+)\.xml$/;
691
- function txBodyText(parent, txBodyTag) {
692
- const txBody = childrenWithTag(parent, txBodyTag)[0];
693
- if (txBody === void 0) return "";
694
- return elementsWithTag(txBody.children, "a:t").map(textContent).join("");
1598
+ const PRESENTATION_PATH = "ppt/presentation.xml";
1599
+ const TABLE_GRAPHIC_URI = "http://schemas.openxmlformats.org/drawingml/2006/table";
1600
+ function readSlideSize(presentationRoot) {
1601
+ const sldSz = presentationRoot === void 0 ? void 0 : childrenWithTag(presentationRoot, "p:sldSz")[0];
1602
+ const cx = sldSz === void 0 ? void 0 : attr(sldSz, "cx");
1603
+ const cy = sldSz === void 0 ? void 0 : attr(sldSz, "cy");
1604
+ return cx === void 0 || cy === void 0 ? SLIDE_SIZE_WIDESCREEN : {
1605
+ widthPt: emuToPt(Number(cx)),
1606
+ heightPt: emuToPt(Number(cy))
1607
+ };
1608
+ }
1609
+ function readSlidePathsInOrder(pkg, presentationRoot) {
1610
+ if (presentationRoot === void 0) return [];
1611
+ const sldIdLst = childrenWithTag(presentationRoot, "p:sldIdLst")[0];
1612
+ if (sldIdLst === void 0) return [];
1613
+ const presentationRels = resolveRelationships(pkg, PRESENTATION_PATH);
1614
+ const paths = [];
1615
+ for (const sldId of childrenWithTag(sldIdLst, "p:sldId")) {
1616
+ const rId = attr(sldId, "r:id");
1617
+ const rel = rId === void 0 ? void 0 : presentationRels.get(rId);
1618
+ if (rel !== void 0) paths.push(rel.target);
1619
+ }
1620
+ return paths;
1621
+ }
1622
+ function shapeName(shape) {
1623
+ const cNvPr = elementsWithTag([shape], "p:cNvPr")[0];
1624
+ return cNvPr === void 0 ? void 0 : attr(cNvPr, "name");
1625
+ }
1626
+ function mergeRunProperties(base, override) {
1627
+ return {
1628
+ fontFamily: override.fontFamily ?? base.fontFamily,
1629
+ sizePt: override.sizePt ?? base.sizePt,
1630
+ bold: override.bold ?? base.bold,
1631
+ italic: override.italic ?? base.italic,
1632
+ color: override.color ?? base.color
1633
+ };
1634
+ }
1635
+ function isUnderlined(rPr) {
1636
+ if (rPr === void 0) return;
1637
+ const u = attr(rPr, "u");
1638
+ return u === void 0 ? void 0 : u !== "none";
1639
+ }
1640
+ function isStrikethrough(rPr) {
1641
+ if (rPr === void 0) return;
1642
+ const strike = attr(rPr, "strike");
1643
+ return strike === void 0 ? void 0 : strike !== "noStrike";
1644
+ }
1645
+ function readHyperlink(rPr, slideRels) {
1646
+ if (rPr === void 0) return;
1647
+ const hlink = childrenWithTag(rPr, "a:hlinkClick")[0];
1648
+ const rId = hlink === void 0 ? void 0 : attr(hlink, "r:id");
1649
+ const rel = rId === void 0 ? void 0 : slideRels.get(rId);
1650
+ return rel?.targetMode === "External" ? rel.target : void 0;
1651
+ }
1652
+ function readRun(runEl, cascadeBase, context, slideRels) {
1653
+ const rPr = childrenWithTag(runEl, "a:rPr")[0];
1654
+ const merged = mergeRunProperties(cascadeBase, rPr === void 0 ? {} : readRunPropertiesFromElement(rPr, context));
1655
+ const tEl = childrenWithTag(runEl, "a:t")[0];
1656
+ return {
1657
+ text: tEl === void 0 ? "" : textContent(tEl),
1658
+ bold: merged.bold,
1659
+ italic: merged.italic,
1660
+ underline: isUnderlined(rPr),
1661
+ strike: isStrikethrough(rPr),
1662
+ fontFamily: merged.fontFamily,
1663
+ sizePt: merged.sizePt,
1664
+ color: merged.color,
1665
+ hyperlink: readHyperlink(rPr, slideRels)
1666
+ };
695
1667
  }
696
- function readShape(shape) {
697
- return { text: txBodyText(shape, "p:txBody") };
1668
+ function readAlignment(algn) {
1669
+ if (algn === "l") return "left";
1670
+ if (algn === "ctr") return "center";
1671
+ if (algn === "r") return "right";
1672
+ if (algn === "just" || algn === "justLow") return "justify";
1673
+ }
1674
+ function readAbsoluteSpacingPt(spc) {
1675
+ if (spc === void 0) return;
1676
+ const pts = childrenWithTag(spc, "a:spcPts")[0];
1677
+ const val = pts === void 0 ? void 0 : attr(pts, "val");
1678
+ return val === void 0 ? void 0 : drawingMlFontSizeToPt(Number(val));
1679
+ }
1680
+ function readLineSpacingMultiplier(pPr) {
1681
+ const lnSpc = pPr === void 0 ? void 0 : childrenWithTag(pPr, "a:lnSpc")[0];
1682
+ const pct = lnSpc === void 0 ? void 0 : childrenWithTag(lnSpc, "a:spcPct")[0];
1683
+ const val = pct === void 0 ? void 0 : attr(pct, "val");
1684
+ return val === void 0 ? void 0 : Number(val) / 1e5;
1685
+ }
1686
+ function readParagraph(pEl, placeholderType, context, slideRels) {
1687
+ const pPr = childrenWithTag(pEl, "a:pPr")[0];
1688
+ const masterDefaults = resolveDefaultRunProperties(placeholderType, pPr === void 0 ? 0 : Number(attr(pPr, "lvl") ?? "0"), context);
1689
+ const pPrDefRPr = pPr === void 0 ? void 0 : childrenWithTag(pPr, "a:defRPr")[0];
1690
+ const paragraphDefaults = pPrDefRPr === void 0 ? masterDefaults : mergeRunProperties(masterDefaults, readRunPropertiesFromElement(pPrDefRPr, context));
1691
+ const runs = [];
1692
+ for (const child of pEl.children) {
1693
+ if (child.type !== "element") continue;
1694
+ if (child.tag === "a:r" || child.tag === "a:fld") runs.push(readRun(child, paragraphDefaults, context, slideRels));
1695
+ else if (child.tag === "a:br") runs.push({ text: "\n" });
1696
+ }
1697
+ const marL = pPr === void 0 ? void 0 : attr(pPr, "marL");
1698
+ const indent = pPr === void 0 ? void 0 : attr(pPr, "indent");
1699
+ return {
1700
+ kind: "paragraph",
1701
+ runs,
1702
+ alignment: pPr === void 0 ? void 0 : readAlignment(attr(pPr, "algn")),
1703
+ spacingBeforePt: readAbsoluteSpacingPt(pPr === void 0 ? void 0 : childrenWithTag(pPr, "a:spcBef")[0]),
1704
+ spacingAfterPt: readAbsoluteSpacingPt(pPr === void 0 ? void 0 : childrenWithTag(pPr, "a:spcAft")[0]),
1705
+ lineSpacing: readLineSpacingMultiplier(pPr),
1706
+ indentLeftPt: marL === void 0 ? void 0 : emuToPt(Number(marL)),
1707
+ indentFirstLinePt: indent === void 0 ? void 0 : emuToPt(Number(indent))
1708
+ };
698
1709
  }
699
- function readTableCell(cell) {
700
- return { text: txBodyText(cell, "a:txBody") };
1710
+ function textBodyParagraphs(txBody, placeholderType, context, slideRels) {
1711
+ return txBody === void 0 ? [] : childrenWithTag(txBody, "a:p").map((p) => readParagraph(p, placeholderType, context, slideRels));
1712
+ }
1713
+ const DEFAULT_INSET_LEFT_RIGHT_EMU = 91440;
1714
+ const DEFAULT_INSET_TOP_BOTTOM_EMU = 45720;
1715
+ const NO_TEXT_BODY_EXTRAS = {
1716
+ insetLeftPt: 0,
1717
+ insetTopPt: 0,
1718
+ insetRightPt: 0,
1719
+ insetBottomPt: 0,
1720
+ fontScale: void 0,
1721
+ lineSpacingReduction: void 0
1722
+ };
1723
+ function readShapeTextExtras(txBody) {
1724
+ if (txBody === void 0) return NO_TEXT_BODY_EXTRAS;
1725
+ const bodyPr = childrenWithTag(txBody, "a:bodyPr")[0];
1726
+ const lIns = bodyPr === void 0 ? void 0 : attr(bodyPr, "lIns");
1727
+ const tIns = bodyPr === void 0 ? void 0 : attr(bodyPr, "tIns");
1728
+ const rIns = bodyPr === void 0 ? void 0 : attr(bodyPr, "rIns");
1729
+ const bIns = bodyPr === void 0 ? void 0 : attr(bodyPr, "bIns");
1730
+ const normAutofit = bodyPr === void 0 ? void 0 : childrenWithTag(bodyPr, "a:normAutofit")[0];
1731
+ const fontScale = normAutofit === void 0 ? void 0 : attr(normAutofit, "fontScale");
1732
+ const lnSpcReduction = normAutofit === void 0 ? void 0 : attr(normAutofit, "lnSpcReduction");
1733
+ return {
1734
+ insetLeftPt: emuToPt(lIns === void 0 ? DEFAULT_INSET_LEFT_RIGHT_EMU : Number(lIns)),
1735
+ insetTopPt: emuToPt(tIns === void 0 ? DEFAULT_INSET_TOP_BOTTOM_EMU : Number(tIns)),
1736
+ insetRightPt: emuToPt(rIns === void 0 ? DEFAULT_INSET_LEFT_RIGHT_EMU : Number(rIns)),
1737
+ insetBottomPt: emuToPt(bIns === void 0 ? DEFAULT_INSET_TOP_BOTTOM_EMU : Number(bIns)),
1738
+ fontScale: fontScale === void 0 ? void 0 : Number(fontScale) / 1e5,
1739
+ lineSpacingReduction: lnSpcReduction === void 0 ? void 0 : Number(lnSpcReduction) / 1e5
1740
+ };
701
1741
  }
702
- function readTableRow(row) {
703
- return { cells: childrenWithTag(row, "a:tc").map(readTableCell) };
1742
+ function resolveShapeFrame(shape, context, parentTransform) {
1743
+ const key = readPlaceholderKey(shape);
1744
+ const spPr = childrenWithTag(shape, "p:spPr")[0];
1745
+ const xfrm = (spPr === void 0 ? void 0 : readXfrm(childrenWithTag(spPr, "a:xfrm")[0])) ?? (key === void 0 ? void 0 : resolvePlaceholderXfrm(key, context));
1746
+ if (xfrm === void 0) return;
1747
+ const localFrame = {
1748
+ xPt: xfrm.xPt,
1749
+ yPt: xfrm.yPt,
1750
+ widthPt: xfrm.widthPt,
1751
+ heightPt: xfrm.heightPt
1752
+ };
1753
+ return {
1754
+ frame: parentTransform === void 0 ? localFrame : applyGroupTransform(parentTransform, localFrame),
1755
+ rotationDeg: xfrm.rotationDeg === 0 ? void 0 : xfrm.rotationDeg
1756
+ };
704
1757
  }
705
- function readTable(table) {
706
- return { rows: childrenWithTag(table, "a:tr").map(readTableRow) };
1758
+ function readSpShape(sp, context, slideRels, parentTransform) {
1759
+ const resolved = resolveShapeFrame(sp, context, parentTransform);
1760
+ if (resolved === void 0) return;
1761
+ const key = readPlaceholderKey(sp);
1762
+ const txBody = childrenWithTag(sp, "p:txBody")[0];
1763
+ const blocks = textBodyParagraphs(txBody, key?.type, context, slideRels);
1764
+ const extras = readShapeTextExtras(txBody);
1765
+ return {
1766
+ name: shapeName(sp),
1767
+ frame: resolved.frame,
1768
+ rotationDeg: resolved.rotationDeg,
1769
+ ...extras,
1770
+ blocks
1771
+ };
707
1772
  }
1773
+ function readPicShape(pic, context, slideRels, pkg, parentTransform) {
1774
+ const resolved = resolveShapeFrame(pic, context, parentTransform);
1775
+ if (resolved === void 0) return;
1776
+ const blipFill = childrenWithTag(pic, "p:blipFill")[0];
1777
+ const blip = blipFill === void 0 ? void 0 : childrenWithTag(blipFill, "a:blip")[0];
1778
+ const rId = blip === void 0 ? void 0 : attr(blip, "r:embed");
1779
+ const rel = rId === void 0 ? void 0 : slideRels.get(rId);
1780
+ const mediaPart = rel === void 0 ? void 0 : pkg.parts[rel.target];
1781
+ const blocks = [];
1782
+ if (mediaPart?.kind === "binary") {
1783
+ const format = sniffImageFormat(base64ToBytes(mediaPart.base64));
1784
+ if (format !== void 0) {
1785
+ const image = {
1786
+ kind: "image",
1787
+ format,
1788
+ base64: mediaPart.base64,
1789
+ widthPt: resolved.frame.widthPt,
1790
+ heightPt: resolved.frame.heightPt
1791
+ };
1792
+ blocks.push(image);
1793
+ }
1794
+ }
1795
+ return {
1796
+ name: shapeName(pic),
1797
+ frame: resolved.frame,
1798
+ rotationDeg: resolved.rotationDeg,
1799
+ ...NO_TEXT_BODY_EXTRAS,
1800
+ blocks
1801
+ };
1802
+ }
1803
+ function readTableCell(tc, context, slideRels) {
1804
+ const hMerge = attr(tc, "hMerge");
1805
+ const vMerge = attr(tc, "vMerge");
1806
+ if (hMerge === "1" || vMerge === "1") return { blocks: [] };
1807
+ const tcPr = childrenWithTag(tc, "a:tcPr")[0];
1808
+ const background = readSolidFillColor(tcPr === void 0 ? void 0 : childrenWithTag(tcPr, "a:solidFill")[0], context.colorMap, context.theme);
1809
+ const txBody = childrenWithTag(tc, "a:txBody")[0];
1810
+ const gridSpan = attr(tc, "gridSpan");
1811
+ const rowSpan = attr(tc, "rowSpan");
1812
+ return {
1813
+ blocks: textBodyParagraphs(txBody, void 0, context, slideRels),
1814
+ colSpan: gridSpan === void 0 ? void 0 : Number(gridSpan),
1815
+ rowSpan: rowSpan === void 0 ? void 0 : Number(rowSpan),
1816
+ background
1817
+ };
1818
+ }
1819
+ function readTable(tbl, context, slideRels) {
1820
+ const tblGrid = childrenWithTag(tbl, "a:tblGrid")[0];
1821
+ const columnWidthsPt = tblGrid === void 0 ? [] : childrenWithTag(tblGrid, "a:gridCol").map((col) => emuToPt(Number(attr(col, "w") ?? "0")));
1822
+ return {
1823
+ kind: "table",
1824
+ rows: childrenWithTag(tbl, "a:tr").map((tr) => {
1825
+ const h = attr(tr, "h");
1826
+ return {
1827
+ cells: childrenWithTag(tr, "a:tc").map((tc) => readTableCell(tc, context, slideRels)),
1828
+ heightPt: h === void 0 ? void 0 : emuToPt(Number(h))
1829
+ };
1830
+ }),
1831
+ columnWidthsPt
1832
+ };
1833
+ }
1834
+ function readGraphicFrameShape(gf, context, slideRels, parentTransform) {
1835
+ const xfrm = readXfrm(childrenWithTag(gf, "p:xfrm")[0]);
1836
+ if (xfrm === void 0) return;
1837
+ const localFrame = {
1838
+ xPt: xfrm.xPt,
1839
+ yPt: xfrm.yPt,
1840
+ widthPt: xfrm.widthPt,
1841
+ heightPt: xfrm.heightPt
1842
+ };
1843
+ const frame = parentTransform === void 0 ? localFrame : applyGroupTransform(parentTransform, localFrame);
1844
+ const rotationDeg = xfrm.rotationDeg === 0 ? void 0 : xfrm.rotationDeg;
1845
+ const graphic = childrenWithTag(gf, "a:graphic")[0];
1846
+ const graphicData = graphic === void 0 ? void 0 : childrenWithTag(graphic, "a:graphicData")[0];
1847
+ const tbl = (graphicData === void 0 ? void 0 : attr(graphicData, "uri")) === TABLE_GRAPHIC_URI && graphicData !== void 0 ? childrenWithTag(graphicData, "a:tbl")[0] : void 0;
1848
+ const blocks = tbl === void 0 ? [] : [readTable(tbl, context, slideRels)];
1849
+ return {
1850
+ name: shapeName(gf),
1851
+ frame,
1852
+ rotationDeg,
1853
+ ...NO_TEXT_BODY_EXTRAS,
1854
+ blocks
1855
+ };
1856
+ }
1857
+ function walkShapeTreeChildren(children, parentTransform, context, slideRels, pkg, out) {
1858
+ for (const node of children) {
1859
+ if (node.type !== "element") continue;
1860
+ if (node.tag === "p:sp") {
1861
+ const shape = readSpShape(node, context, slideRels, parentTransform);
1862
+ if (shape !== void 0) out.push(shape);
1863
+ } else if (node.tag === "p:pic") {
1864
+ const shape = readPicShape(node, context, slideRels, pkg, parentTransform);
1865
+ if (shape !== void 0) out.push(shape);
1866
+ } else if (node.tag === "p:graphicFrame") {
1867
+ const shape = readGraphicFrameShape(node, context, slideRels, parentTransform);
1868
+ if (shape !== void 0) out.push(shape);
1869
+ } else if (node.tag === "p:grpSp") {
1870
+ const grpSpPr = childrenWithTag(node, "p:grpSpPr")[0];
1871
+ const composed = composeGroupTransform(readGroupXfrm(grpSpPr === void 0 ? void 0 : childrenWithTag(grpSpPr, "a:xfrm")[0]), parentTransform);
1872
+ walkShapeTreeChildren(node.children, composed, context, slideRels, pkg, out);
1873
+ }
1874
+ }
1875
+ }
1876
+ function composeGroupTransform(own, parent) {
1877
+ if (own === void 0) return;
1878
+ if (parent === void 0) return own;
1879
+ const absolute = applyGroupTransform(parent, {
1880
+ xPt: own.offXPt,
1881
+ yPt: own.offYPt,
1882
+ widthPt: own.extWidthPt,
1883
+ heightPt: own.extHeightPt
1884
+ });
1885
+ return {
1886
+ ...own,
1887
+ offXPt: absolute.xPt,
1888
+ offYPt: absolute.yPt,
1889
+ extWidthPt: absolute.widthPt,
1890
+ extHeightPt: absolute.heightPt
1891
+ };
1892
+ }
1893
+ const NOTES_SLIDE_REL_SUFFIX = "/notesSlide";
708
1894
  function readNotes(pkg, slidePath) {
709
- const rels = resolveRelationships(pkg, slidePath);
710
1895
  let notesPath;
711
- for (const rel of rels.values()) if (rel.type.endsWith("/notesSlide")) {
1896
+ for (const rel of resolveRelationships(pkg, slidePath).values()) if (rel.type.endsWith(NOTES_SLIDE_REL_SUFFIX)) {
712
1897
  notesPath = rel.target;
713
1898
  break;
714
1899
  }
715
1900
  if (notesPath === void 0) return "";
716
- const part = pkg.parts[notesPath];
717
- if (part?.kind !== "xml") return "";
718
- return elementsWithTag(part.nodes, "a:t").map(textContent).join("");
1901
+ const notesRoot = rootElement(pkg.parts[notesPath]);
1902
+ if (notesRoot === void 0) return "";
1903
+ const bodyShape = elementsWithTag([notesRoot], "p:sp").find((shape) => {
1904
+ const key = readPlaceholderKey(shape);
1905
+ return key !== void 0 && (key.type === void 0 || key.type === "body");
1906
+ });
1907
+ if (bodyShape !== void 0) {
1908
+ const txBody = childrenWithTag(bodyShape, "p:txBody")[0];
1909
+ if (txBody !== void 0) return elementsWithTag(txBody.children, "a:t").map(textContent).join("");
1910
+ }
1911
+ return elementsWithTag([notesRoot], "a:t").map(textContent).join("");
1912
+ }
1913
+ function readSlide(pkg, slidePath, size) {
1914
+ const slideRoot = rootElement(pkg.parts[slidePath]);
1915
+ const context = resolveSlideInheritance(pkg, slidePath);
1916
+ const slideRels = resolveRelationships(pkg, slidePath);
1917
+ const cSld = slideRoot === void 0 ? void 0 : childrenWithTag(slideRoot, "p:cSld")[0];
1918
+ const spTree = cSld === void 0 ? void 0 : childrenWithTag(cSld, "p:spTree")[0];
1919
+ const shapes = [];
1920
+ if (spTree !== void 0) walkShapeTreeChildren(spTree.children, void 0, context, slideRels, pkg, shapes);
1921
+ return {
1922
+ size,
1923
+ shapes,
1924
+ notes: readNotes(pkg, slidePath)
1925
+ };
719
1926
  }
720
1927
  function readPptx(pkg) {
721
- const found = [];
722
- for (const [path, part] of Object.entries(pkg.parts)) {
723
- const match = SLIDE_PATH.exec(path);
724
- if (match === null) continue;
725
- const captured = match[1];
726
- if (captured === void 0) continue;
727
- if (part.kind !== "xml") continue;
728
- const index = Number(captured);
729
- const text = elementsWithTag(part.nodes, "a:t").map(textContent).join("");
730
- const shapes = elementsWithTag(part.nodes, "p:sp").map(readShape);
731
- const tables = elementsWithTag(part.nodes, "a:tbl").map(readTable);
732
- const notes = readNotes(pkg, path);
733
- found.push({
734
- index,
735
- text,
736
- shapes,
737
- tables,
738
- notes
739
- });
740
- }
741
- found.sort((a, b) => a.index - b.index);
742
- return { slides: found };
1928
+ const presentationRoot = rootElement(pkg.parts[PRESENTATION_PATH]);
1929
+ const size = readSlideSize(presentationRoot);
1930
+ const slides = readSlidePathsInOrder(pkg, presentationRoot).map((slidePath) => readSlide(pkg, slidePath, size));
1931
+ return {
1932
+ metadata: readCoreProperties(pkg),
1933
+ slides
1934
+ };
743
1935
  }
744
1936
  //#endregion
745
1937
  //#region src/typed/xlsx.ts
@@ -884,30 +2076,41 @@ function readXlsx(pkg) {
884
2076
  };
885
2077
  }
886
2078
  //#endregion
2079
+ exports.AlignmentSchema = AlignmentSchema;
887
2080
  exports.AttributeSchema = AttributeSchema;
888
2081
  exports.BinaryPartSchema = BinaryPartSchema;
2082
+ exports.BoxSchema = BoxSchema;
2083
+ exports.COLOR_BLACK = COLOR_BLACK;
2084
+ exports.ColorSchema = ColorSchema;
889
2085
  exports.CommentSchema = CommentSchema;
890
2086
  exports.CompactPackageSchema = CompactPackageSchema;
891
2087
  exports.CompactPartSchema = CompactPartSchema;
892
2088
  exports.CompactXmlNodeSchema = CompactXmlNodeSchema;
2089
+ exports.ContentBlockSchema = ContentBlockSchema;
2090
+ exports.ContentImageBlockSchema = ContentImageBlockSchema;
2091
+ exports.ContentListMembershipSchema = ContentListMembershipSchema;
2092
+ exports.ContentPageBreakSchema = ContentPageBreakSchema;
2093
+ exports.ContentParagraphSchema = ContentParagraphSchema;
2094
+ exports.ContentRunSchema = ContentRunSchema;
2095
+ exports.ContentSectionSchema = ContentSectionSchema;
2096
+ exports.ContentShapeSchema = ContentShapeSchema;
2097
+ exports.ContentSlideSchema = ContentSlideSchema;
2098
+ exports.ContentTableCellSchema = ContentTableCellSchema;
2099
+ exports.ContentTableRowSchema = ContentTableRowSchema;
2100
+ exports.ContentTableSchema = ContentTableSchema;
893
2101
  exports.DefinedNameSchema = DefinedNameSchema;
2102
+ exports.DocumentMetadataSchema = DocumentMetadataSchema;
894
2103
  exports.DocxDocumentSchema = DocxDocumentSchema;
895
2104
  exports.FootnoteSchema = FootnoteSchema;
896
- exports.HyperlinkSchema = HyperlinkSchema;
897
- exports.ListMembershipSchema = ListMembershipSchema;
2105
+ exports.MarginsSchema = MarginsSchema;
2106
+ exports.PAGE_SIZE_A4 = PAGE_SIZE_A4;
2107
+ exports.PAGE_SIZE_LETTER = PAGE_SIZE_LETTER;
898
2108
  exports.PackageSchema = PackageSchema;
899
- exports.ParagraphSchema = ParagraphSchema;
2109
+ exports.PageSizeSchema = PageSizeSchema;
900
2110
  exports.PartSchema = PartSchema;
901
- exports.PptxPresentationSchema = PptxPresentationSchema;
902
- exports.PptxTableCellSchema = PptxTableCellSchema;
903
- exports.PptxTableRowSchema = PptxTableRowSchema;
904
- exports.PptxTableSchema = PptxTableSchema;
905
- exports.RunSchema = RunSchema;
906
- exports.ShapeSchema = ShapeSchema;
907
- exports.SlideSchema = SlideSchema;
908
- exports.TableCellSchema = TableCellSchema;
909
- exports.TableRowSchema = TableRowSchema;
910
- exports.TableSchema = TableSchema;
2111
+ exports.PptxDocumentSchema = PptxDocumentSchema;
2112
+ exports.SLIDE_SIZE_STANDARD = SLIDE_SIZE_STANDARD;
2113
+ exports.SLIDE_SIZE_WIDESCREEN = SLIDE_SIZE_WIDESCREEN;
911
2114
  exports.XlsxCellSchema = XlsxCellSchema;
912
2115
  exports.XlsxSheetSchema = XlsxSheetSchema;
913
2116
  exports.XlsxWorkbookSchema = XlsxWorkbookSchema;
@@ -919,11 +2122,13 @@ exports.XmlNodeSchema = XmlNodeSchema;
919
2122
  exports.XmlPartSchema = XmlPartSchema;
920
2123
  exports.XmlPiSchema = XmlPiSchema;
921
2124
  exports.XmlTextSchema = XmlTextSchema;
2125
+ exports.applyColorTransforms = applyColorTransforms;
922
2126
  exports.attr = attr;
923
2127
  exports.base64ToBytes = base64ToBytes;
924
2128
  exports.buildXml = buildXml;
925
2129
  exports.bytesToBase64 = bytesToBase64;
926
2130
  exports.childrenWithTag = childrenWithTag;
2131
+ exports.colorToRgbHex = colorToRgbHex;
927
2132
  exports.compactCodec = compactCodec;
928
2133
  exports.compactPackageCodec = compactPackageCodec;
929
2134
  exports.decodeCompactPackage = decodeCompactPackage;
@@ -934,6 +2139,7 @@ exports.encodeCompactPackage = encodeCompactPackage;
934
2139
  exports.encodePackage = encodePackage;
935
2140
  exports.fromCompact = fromCompact;
936
2141
  exports.isCompactXmlNode = isCompactXmlNode;
2142
+ exports.isContentBlock = isContentBlock;
937
2143
  exports.isXmlNode = isXmlNode;
938
2144
  exports.packageCodec = packageCodec;
939
2145
  exports.parsePackage = parsePackage;
@@ -942,8 +2148,10 @@ exports.readDocx = readDocx;
942
2148
  exports.readPptx = readPptx;
943
2149
  exports.readXlsx = readXlsx;
944
2150
  exports.resolveRelationships = resolveRelationships;
2151
+ exports.rgbHexToColor = rgbHexToColor;
945
2152
  exports.rootElement = rootElement;
946
2153
  exports.serializePackage = serializePackage;
2154
+ exports.sniffImageFormat = sniffImageFormat;
947
2155
  exports.textContent = textContent;
948
2156
  exports.toCompact = toCompact;
949
2157
  exports.unzipPackage = unzipPackage;