@bendyline/squisq-formats 1.3.1 → 1.4.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.
Files changed (76) hide show
  1. package/dist/chunk-6M7Z25LA.js +46 -0
  2. package/dist/chunk-6M7Z25LA.js.map +1 -0
  3. package/dist/{chunk-S3Y7H2BK.js → chunk-APSIAEXL.js} +9 -8
  4. package/dist/chunk-APSIAEXL.js.map +1 -0
  5. package/dist/{chunk-UDS45KUJ.js → chunk-BJQIJ4S4.js} +36 -52
  6. package/dist/chunk-BJQIJ4S4.js.map +1 -0
  7. package/dist/{chunk-33YRFXZZ.js → chunk-CRTC6DEX.js} +259 -13
  8. package/dist/chunk-CRTC6DEX.js.map +1 -0
  9. package/dist/chunk-FMOIGA5T.js +201 -0
  10. package/dist/chunk-FMOIGA5T.js.map +1 -0
  11. package/dist/{chunk-VN2KEOYB.js → chunk-I2GFTEOV.js} +321 -91
  12. package/dist/chunk-I2GFTEOV.js.map +1 -0
  13. package/dist/chunk-JBNVE2GV.js +116 -0
  14. package/dist/chunk-JBNVE2GV.js.map +1 -0
  15. package/dist/chunk-L53YIGYS.js +141 -0
  16. package/dist/chunk-L53YIGYS.js.map +1 -0
  17. package/dist/{chunk-ERZ627GR.js → chunk-ON232HJR.js} +11 -26
  18. package/dist/chunk-ON232HJR.js.map +1 -0
  19. package/dist/chunk-PN52A5AA.js +32 -0
  20. package/dist/chunk-PN52A5AA.js.map +1 -0
  21. package/dist/{chunk-7DEUGIOO.js → chunk-QSE7EWE7.js} +12 -87
  22. package/dist/chunk-QSE7EWE7.js.map +1 -0
  23. package/dist/csv/index.d.ts +37 -0
  24. package/dist/csv/index.js +13 -0
  25. package/dist/csv/index.js.map +1 -0
  26. package/dist/docx/index.js +5 -3
  27. package/dist/epub/index.js +2 -1
  28. package/dist/html/index.d.ts +39 -2
  29. package/dist/html/index.js +7 -1
  30. package/dist/index.d.ts +2 -1
  31. package/dist/index.js +31 -13
  32. package/dist/ooxml/index.js +16 -16
  33. package/dist/pdf/index.js +1 -1
  34. package/dist/pptx/index.d.ts +20 -18
  35. package/dist/pptx/index.js +6 -2
  36. package/dist/xlsx/index.d.ts +20 -19
  37. package/dist/xlsx/index.js +2 -1
  38. package/package.json +7 -2
  39. package/src/__tests__/csvImport.test.ts +51 -0
  40. package/src/__tests__/exportThemeReconciliation.test.ts +87 -0
  41. package/src/__tests__/htmlImport.test.ts +57 -0
  42. package/src/__tests__/plainHtml.test.ts +31 -0
  43. package/src/__tests__/pptxExport.test.ts +138 -0
  44. package/src/__tests__/pptxImport.test.ts +70 -0
  45. package/src/__tests__/roundTripMatrix.fixtures.ts +86 -0
  46. package/src/__tests__/roundTripMatrix.helpers.ts +154 -0
  47. package/src/__tests__/roundTripMatrix.test.ts +136 -0
  48. package/src/__tests__/xlsxImport.test.ts +80 -0
  49. package/src/csv/index.ts +165 -0
  50. package/src/docx/export.ts +27 -44
  51. package/src/docx/import.ts +1 -2
  52. package/src/epub/export.ts +10 -27
  53. package/src/html/import.ts +297 -0
  54. package/src/html/index.ts +4 -0
  55. package/src/html/plainHtml.ts +66 -16
  56. package/src/index.ts +10 -3
  57. package/src/ooxml/namespaces.ts +3 -0
  58. package/src/pdf/export.ts +10 -5
  59. package/src/pdf/import.ts +1 -1
  60. package/src/pptx/export.ts +225 -85
  61. package/src/pptx/import.ts +156 -0
  62. package/src/pptx/index.ts +10 -28
  63. package/src/shared/inlineRuns.ts +99 -0
  64. package/src/shared/text.ts +41 -0
  65. package/src/xlsx/import.ts +159 -0
  66. package/src/xlsx/index.ts +11 -28
  67. package/dist/chunk-33YRFXZZ.js.map +0 -1
  68. package/dist/chunk-67KIJHV2.js +0 -21
  69. package/dist/chunk-67KIJHV2.js.map +0 -1
  70. package/dist/chunk-7DEUGIOO.js.map +0 -1
  71. package/dist/chunk-ERZ627GR.js.map +0 -1
  72. package/dist/chunk-S3Y7H2BK.js.map +0 -1
  73. package/dist/chunk-UDS45KUJ.js.map +0 -1
  74. package/dist/chunk-VN2KEOYB.js.map +0 -1
  75. package/dist/chunk-YN5HFCEW.js +0 -120
  76. package/dist/chunk-YN5HFCEW.js.map +0 -1
@@ -1,3 +1,18 @@
1
+ import {
2
+ inlineNodeToRuns,
3
+ inlineNodesToRuns
4
+ } from "./chunk-6M7Z25LA.js";
5
+ import {
6
+ extractPlainText,
7
+ stripHtmlTags
8
+ } from "./chunk-PN52A5AA.js";
9
+ import {
10
+ createPackage
11
+ } from "./chunk-QSE7EWE7.js";
12
+ import {
13
+ escapeXml,
14
+ xmlDeclaration
15
+ } from "./chunk-U4MRIFKL.js";
1
16
  import {
2
17
  CONTENT_TYPE_PPTX_PRESENTATION,
3
18
  CONTENT_TYPE_PPTX_SLIDE,
@@ -5,7 +20,9 @@ import {
5
20
  CONTENT_TYPE_PPTX_SLIDE_MASTER,
6
21
  CONTENT_TYPE_PPTX_THEME,
7
22
  NS_DRAWINGML,
23
+ NS_MC,
8
24
  NS_PML,
25
+ NS_PML_2010,
9
26
  NS_R,
10
27
  REL_HYPERLINK,
11
28
  REL_IMAGE,
@@ -14,16 +31,17 @@ import {
14
31
  REL_SLIDE_LAYOUT,
15
32
  REL_SLIDE_MASTER,
16
33
  REL_THEME,
17
- createPackage
18
- } from "./chunk-7DEUGIOO.js";
34
+ getPartRelationships,
35
+ getPartXml,
36
+ openPackage
37
+ } from "./chunk-FMOIGA5T.js";
19
38
  import {
20
- escapeXml,
21
- xmlDeclaration
22
- } from "./chunk-U4MRIFKL.js";
39
+ inferMimeType
40
+ } from "./chunk-A3FHLTY5.js";
23
41
 
24
42
  // src/pptx/export.ts
25
- import { resolveTheme, resolveFontFamily } from "@bendyline/squisq/schemas";
26
- import { docToMarkdown } from "@bendyline/squisq/doc";
43
+ import { resolveFontFamily } from "@bendyline/squisq/schemas";
44
+ import { docToMarkdown, resolveThemeForDoc } from "@bendyline/squisq/doc";
27
45
  import { readFrontmatterThemeId } from "@bendyline/squisq/markdown";
28
46
 
29
47
  // src/pptx/styles.ts
@@ -65,7 +83,7 @@ function buildThemeXml() {
65
83
  // src/pptx/export.ts
66
84
  async function markdownDocToPptx(doc, options = {}) {
67
85
  const themeId = options.themeId ?? readFrontmatterThemeId(doc.frontmatter);
68
- const style = resolveSlideStyle(themeId, options);
86
+ const style = resolveSlideStyle(themeId, options, doc);
69
87
  const slides = segmentIntoSlides(doc.children, options.slideBreak ?? "h2");
70
88
  if (slides.length === 0) {
71
89
  slides.push({ bodyNodes: [] });
@@ -87,7 +105,7 @@ async function docToPptx(doc, options = {}) {
87
105
  }
88
106
  return markdownDocToPptx(markdownDoc, options);
89
107
  }
90
- function resolveSlideStyle(themeId, options) {
108
+ function resolveSlideStyle(themeId, options, doc) {
91
109
  if (!themeId) {
92
110
  return {
93
111
  background: "FFFFFF",
@@ -101,7 +119,7 @@ function resolveSlideStyle(themeId, options) {
101
119
  hasTheme: false
102
120
  };
103
121
  }
104
- const theme = resolveTheme(themeId);
122
+ const theme = resolveThemeForDoc(doc, themeId);
105
123
  const c = theme.colors;
106
124
  return {
107
125
  background: stripHash(c.background),
@@ -128,6 +146,7 @@ function segmentIntoSlides(children, slideBreak) {
128
146
  current = {
129
147
  title: extractPlainText(node.children),
130
148
  titleDepth: node.depth,
149
+ transition: node.attributes?.blockMeta?.transition,
131
150
  bodyNodes: []
132
151
  };
133
152
  } else {
@@ -140,36 +159,6 @@ function segmentIntoSlides(children, slideBreak) {
140
159
  if (current) slides.push(current);
141
160
  return slides;
142
161
  }
143
- function extractPlainText(nodes) {
144
- const parts = [];
145
- for (const node of nodes) {
146
- switch (node.type) {
147
- case "text":
148
- parts.push(node.value);
149
- break;
150
- case "inlineCode":
151
- parts.push(node.value);
152
- break;
153
- case "strong":
154
- case "emphasis":
155
- case "delete":
156
- parts.push(extractPlainText(node.children));
157
- break;
158
- case "link":
159
- parts.push(extractPlainText(node.children));
160
- break;
161
- case "image":
162
- parts.push(node.alt ?? "");
163
- break;
164
- case "inlineMath":
165
- parts.push(node.value);
166
- break;
167
- default:
168
- break;
169
- }
170
- }
171
- return parts.join("");
172
- }
173
162
  var SlideContext = class {
174
163
  // 1=group, 2=title, 3=body
175
164
  constructor(style, images, slideIndex) {
@@ -273,7 +262,175 @@ function buildSlideXml(slide, ctx) {
273
262
  );
274
263
  }
275
264
  const bgXml = ctx.style.hasTheme ? `<p:bg><p:bgPr><a:solidFill><a:srgbClr val="${ctx.style.background}"/></a:solidFill><a:effectLst/></p:bgPr></p:bg>` : "";
276
- return xmlDeclaration() + `<p:sld xmlns:a="${NS_DRAWINGML}" xmlns:r="${NS_R}" xmlns:p="${NS_PML}"><p:cSld>` + bgXml + `<p:spTree>` + shapes.join("") + `</p:spTree></p:cSld></p:sld>`;
265
+ const transitionXml = buildTransitionXml(slide.transition);
266
+ const extensionAttrs = transitionXml.includes("p14:") ? ` xmlns:mc="${NS_MC}" xmlns:p14="${NS_PML_2010}" mc:Ignorable="p14"` : "";
267
+ return xmlDeclaration() + `<p:sld xmlns:a="${NS_DRAWINGML}" xmlns:r="${NS_R}" xmlns:p="${NS_PML}"${extensionAttrs}><p:cSld>` + bgXml + `<p:spTree>` + shapes.join("") + `</p:spTree></p:cSld>` + transitionXml + `</p:sld>`;
268
+ }
269
+ function buildTransitionXml(transition) {
270
+ if (!transition || transition.type === "cut") return "";
271
+ const child = buildTransitionChildXml(transition);
272
+ const spd = pptxSpeedForDuration(transition.duration);
273
+ return `<p:transition spd="${spd}">${child.xml}</p:transition>`;
274
+ }
275
+ function buildTransitionChildXml(transition) {
276
+ const type = transition.type;
277
+ switch (type) {
278
+ case "fade":
279
+ case "morph":
280
+ return p("fade");
281
+ case "dissolve":
282
+ return p("dissolve");
283
+ case "push":
284
+ return p("push", ` dir="${sideDir(transition.direction, "left")}"`);
285
+ case "slideLeft":
286
+ return p("push", ` dir="l"`);
287
+ case "slideRight":
288
+ return p("push", ` dir="r"`);
289
+ case "slideUp":
290
+ return p("push", ` dir="u"`);
291
+ case "slideDown":
292
+ return p("push", ` dir="d"`);
293
+ case "wipe":
294
+ return p("wipe", ` dir="${sideDir(transition.direction, "left")}"`);
295
+ case "split":
296
+ return p("split", ` orient="${orientation(transition.direction)}" dir="out"`);
297
+ case "randomBars":
298
+ case "randomBar":
299
+ return p("randomBar", ` dir="${orientation(transition.direction)}"`);
300
+ case "shape":
301
+ case "circle":
302
+ return p("circle");
303
+ case "diamond":
304
+ return p("diamond");
305
+ case "plus":
306
+ return p("plus");
307
+ case "uncover":
308
+ case "pull":
309
+ return p("pull", ` dir="${sideDir(transition.direction, "left")}"`);
310
+ case "cover":
311
+ return p("cover", ` dir="${sideDir(transition.direction, "left")}"`);
312
+ case "checkerboard":
313
+ case "checker":
314
+ return p("checker", ` dir="${orientation(transition.direction)}"`);
315
+ case "blinds":
316
+ return p("blinds", ` dir="${orientation(transition.direction)}"`);
317
+ case "comb":
318
+ return p("comb", ` dir="${orientation(transition.direction)}"`);
319
+ case "clock":
320
+ case "wheel":
321
+ return p("wheel", ` spokes="4"`);
322
+ case "wheelReverse":
323
+ return p14("wheelReverse");
324
+ case "newsflash":
325
+ return p("newsflash");
326
+ case "random":
327
+ return p("random");
328
+ case "strips":
329
+ return p("strips", ` dir="${cornerDir(transition.direction)}"`);
330
+ case "wedge":
331
+ return p("wedge");
332
+ case "zoom":
333
+ case "box":
334
+ return p("zoom", ` dir="${inOutDir(transition.direction, "in")}"`);
335
+ case "flash":
336
+ return p14("flash");
337
+ case "vortex":
338
+ case "orbit":
339
+ case "rotate":
340
+ return p14("vortex");
341
+ case "switch":
342
+ case "cube":
343
+ return p14("switch");
344
+ case "flip":
345
+ case "fallOver":
346
+ return p14("flip");
347
+ case "ripple":
348
+ return p14("ripple");
349
+ case "glitter":
350
+ case "prestige":
351
+ return p14("glitter");
352
+ case "honeycomb":
353
+ return p14("honeycomb");
354
+ case "prism":
355
+ return p14("prism");
356
+ case "doors":
357
+ case "drape":
358
+ case "curtains":
359
+ return p14("doors");
360
+ case "window":
361
+ return p14("window");
362
+ case "shred":
363
+ case "fracture":
364
+ case "crush":
365
+ return p14("shred");
366
+ case "ferris":
367
+ case "ferrisWheel":
368
+ return p14("ferris");
369
+ case "flythrough":
370
+ case "flyThrough":
371
+ case "airplane":
372
+ case "origami":
373
+ return p14("flythrough");
374
+ case "warp":
375
+ case "pageCurl":
376
+ case "pageCurlDouble":
377
+ case "pageCurlSingle":
378
+ case "peelOff":
379
+ return p14("warp");
380
+ case "gallery":
381
+ return p14("gallery");
382
+ case "conveyor":
383
+ return p14("conveyor");
384
+ case "pan":
385
+ case "wind":
386
+ return p14("pan");
387
+ case "reveal":
388
+ return p14("reveal");
389
+ default:
390
+ return p("fade");
391
+ }
392
+ }
393
+ function p(tag, attrs = "") {
394
+ return { xml: `<p:${tag}${attrs}/>` };
395
+ }
396
+ function p14(tag, attrs = "") {
397
+ return { xml: `<p14:${tag}${attrs}/>` };
398
+ }
399
+ function pptxSpeedForDuration(duration) {
400
+ if (duration != null && duration <= 0.5) return "fast";
401
+ if (duration != null && duration >= 1.2) return "slow";
402
+ return "med";
403
+ }
404
+ function sideDir(direction, fallback) {
405
+ switch (direction ?? fallback) {
406
+ case "right":
407
+ return "r";
408
+ case "up":
409
+ return "u";
410
+ case "down":
411
+ return "d";
412
+ case "left":
413
+ default:
414
+ return "l";
415
+ }
416
+ }
417
+ function cornerDir(direction) {
418
+ switch (direction) {
419
+ case "right":
420
+ case "down":
421
+ return "rd";
422
+ case "up":
423
+ return "lu";
424
+ case "left":
425
+ default:
426
+ return "ld";
427
+ }
428
+ }
429
+ function orientation(direction) {
430
+ return direction === "vertical" || direction === "up" || direction === "down" ? "vert" : "horz";
431
+ }
432
+ function inOutDir(direction, fallback) {
433
+ return direction === "out" ? "out" : direction === "in" ? "in" : fallback;
277
434
  }
278
435
  function buildTitleShape(title, style) {
279
436
  return `<p:sp><p:nvSpPr><p:cNvPr id="2" name="Title"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="title"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="${TITLE_LEFT}" y="${TITLE_TOP}"/><a:ext cx="${TITLE_WIDTH}" cy="${TITLE_HEIGHT}"/></a:xfrm></p:spPr><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:r><a:rPr lang="en-US" sz="${DEFAULT_TITLE_SIZE}" dirty="0"><a:solidFill><a:srgbClr val="${style.titleColor}"/></a:solidFill><a:latin typeface="${escapeXml(style.titleFont)}"/></a:rPr><a:t>${escapeXml(title)}</a:t></a:r></a:p></p:txBody></p:sp>`;
@@ -420,38 +577,19 @@ function convertHtmlBlock(node, ctx) {
420
577
  function convertMathBlock(node) {
421
578
  return `<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" i="1"><a:latin typeface="Cambria Math"/></a:rPr><a:t>${escapeXml(node.value)}</a:t></a:r></a:p>`;
422
579
  }
580
+ function pptxRunHandlers(ctx) {
581
+ return {
582
+ run: (text, format) => makeRun(text, format, ctx.style),
583
+ link: (node, format) => convertLink(node, ctx, format),
584
+ image: (node, format) => convertImage(node, format, ctx),
585
+ lineBreak: () => `<a:br/>`
586
+ };
587
+ }
423
588
  function convertInlines(nodes, ctx, format = {}) {
424
- const parts = [];
425
- for (const node of nodes) {
426
- parts.push(convertInline(node, ctx, format));
427
- }
428
- return parts.join("");
589
+ return inlineNodesToRuns(nodes, pptxRunHandlers(ctx), format);
429
590
  }
430
591
  function convertInline(node, ctx, format) {
431
- switch (node.type) {
432
- case "text":
433
- return makeRun(node.value, format, ctx.style);
434
- case "strong":
435
- return convertInlines(node.children, ctx, { ...format, bold: true });
436
- case "emphasis":
437
- return convertInlines(node.children, ctx, { ...format, italic: true });
438
- case "delete":
439
- return convertInlines(node.children, ctx, { ...format, strike: true });
440
- case "inlineCode":
441
- return makeRun(node.value, { ...format, code: true }, ctx.style);
442
- case "link":
443
- return convertLink(node, ctx, format);
444
- case "image":
445
- return convertImage(node, format, ctx);
446
- case "break":
447
- return `<a:br/>`;
448
- case "htmlInline":
449
- return makeRun(stripHtmlTags(node.rawHtml), format, ctx.style);
450
- case "inlineMath":
451
- return makeRun(node.value, { ...format, code: true }, ctx.style);
452
- default:
453
- return "";
454
- }
592
+ return inlineNodeToRuns(node, pptxRunHandlers(ctx), format);
455
593
  }
456
594
  function makeRun(text, format, style) {
457
595
  if (!text) return "";
@@ -593,35 +731,127 @@ async function buildPptxPackage(slideXmls, slideContexts, options) {
593
731
  }
594
732
  return pkg.toArrayBuffer();
595
733
  }
596
- function stripHtmlTags(html) {
597
- return html.replace(/<[^>]*>/g, "");
598
- }
599
734
  function inferExtension(path) {
600
735
  const dot = path.lastIndexOf(".");
601
736
  if (dot === -1) return "png";
602
737
  const ext = path.substring(dot + 1).toLowerCase().split("?")[0];
603
738
  return ext || "png";
604
739
  }
605
- function inferMimeType(ext) {
606
- const mimeTypes = {
607
- jpg: "image/jpeg",
608
- jpeg: "image/jpeg",
609
- png: "image/png",
610
- gif: "image/gif",
611
- webp: "image/webp",
612
- svg: "image/svg+xml",
613
- bmp: "image/bmp",
614
- avif: "image/avif"
615
- };
616
- return mimeTypes[ext] || "image/png";
617
- }
618
740
 
619
741
  // src/pptx/index.ts
620
- async function pptxToMarkdownDoc(_data, _options) {
621
- throw new Error("PPTX import is not yet implemented");
742
+ import { markdownToDoc } from "@bendyline/squisq/doc";
743
+
744
+ // src/pptx/import.ts
745
+ function attrNS(el, ns, local, fallback) {
746
+ return el.getAttributeNS(ns, local) ?? el.getAttribute(fallback);
747
+ }
748
+ function resolveTarget(baseDir, target) {
749
+ if (target.startsWith("/")) return target.replace(/^\//, "");
750
+ const stack = baseDir ? baseDir.split("/") : [];
751
+ for (const seg of target.split("/")) {
752
+ if (seg === "..") stack.pop();
753
+ else if (seg !== ".") stack.push(seg);
754
+ }
755
+ return stack.join("/");
756
+ }
757
+ async function orderedSlidePaths(pkg) {
758
+ const pres = await getPartXml(pkg, "ppt/presentation.xml");
759
+ if (!pres) return [];
760
+ const rels = await getPartRelationships(pkg, "ppt/presentation.xml");
761
+ const relById = new Map(rels.map((r) => [r.id, r.target]));
762
+ const out = [];
763
+ const ids = pres.getElementsByTagNameNS(NS_PML, "sldId");
764
+ for (let i = 0; i < ids.length; i++) {
765
+ const rid = attrNS(ids[i], NS_R, "id", "r:id");
766
+ const target = rid ? relById.get(rid) : void 0;
767
+ if (target) out.push(resolveTarget("ppt", target));
768
+ }
769
+ return out;
770
+ }
771
+ function paragraphText(para) {
772
+ const ts = para.getElementsByTagNameNS(NS_DRAWINGML, "t");
773
+ let s = "";
774
+ for (let i = 0; i < ts.length; i++) s += ts[i].textContent ?? "";
775
+ return s.trim();
776
+ }
777
+ function isTitleShape(sp) {
778
+ const ph = sp.getElementsByTagNameNS(NS_PML, "ph");
779
+ if (!ph.length) return false;
780
+ const type = ph[0].getAttribute("type");
781
+ return type === "title" || type === "ctrTitle";
782
+ }
783
+ function tableToMarkdown(tbl) {
784
+ const rows = [];
785
+ const trs = tbl.getElementsByTagNameNS(NS_DRAWINGML, "tr");
786
+ for (let r = 0; r < trs.length; r++) {
787
+ const tcs = trs[r].getElementsByTagNameNS(NS_DRAWINGML, "tc");
788
+ const cells = [];
789
+ for (let c = 0; c < tcs.length; c++) {
790
+ const paras = tcs[c].getElementsByTagNameNS(NS_DRAWINGML, "p");
791
+ const text = Array.from({ length: paras.length }, (_, i) => paragraphText(paras[i])).filter(Boolean).join(" ");
792
+ cells.push({
793
+ type: "tableCell",
794
+ ...r === 0 ? { isHeader: true } : {},
795
+ children: text ? [{ type: "text", value: text }] : []
796
+ });
797
+ }
798
+ rows.push({ type: "tableRow", children: cells });
799
+ }
800
+ return { type: "table", children: rows };
801
+ }
802
+ async function convertSlide(pkg, path, index) {
803
+ const doc = await getPartXml(pkg, path);
804
+ if (!doc) return [];
805
+ const out = [];
806
+ let title = "";
807
+ const bullets = [];
808
+ const shapes = doc.getElementsByTagNameNS(NS_PML, "sp");
809
+ for (let s = 0; s < shapes.length; s++) {
810
+ const sp = shapes[s];
811
+ const txBody = sp.getElementsByTagNameNS(NS_PML, "txBody");
812
+ if (!txBody.length) continue;
813
+ const paras = txBody[0].getElementsByTagNameNS(NS_DRAWINGML, "p");
814
+ const texts = [];
815
+ for (let p2 = 0; p2 < paras.length; p2++) {
816
+ const t = paragraphText(paras[p2]);
817
+ if (t) texts.push(t);
818
+ }
819
+ if (texts.length === 0) continue;
820
+ if (isTitleShape(sp) && !title) {
821
+ title = texts.join(" ");
822
+ } else {
823
+ bullets.push(...texts);
824
+ }
825
+ }
826
+ out.push({
827
+ type: "heading",
828
+ depth: 2,
829
+ children: [{ type: "text", value: title || `Slide ${index + 1}` }]
830
+ });
831
+ if (bullets.length > 0) {
832
+ const items = bullets.map((text) => ({
833
+ type: "listItem",
834
+ children: [{ type: "paragraph", children: [{ type: "text", value: text }] }]
835
+ }));
836
+ out.push({ type: "list", ordered: false, children: items });
837
+ }
838
+ const tbls = doc.getElementsByTagNameNS(NS_DRAWINGML, "tbl");
839
+ for (let t = 0; t < tbls.length; t++) out.push(tableToMarkdown(tbls[t]));
840
+ return out;
841
+ }
842
+ async function pptxToMarkdownDoc(data, _options = {}) {
843
+ const pkg = await openPackage(data);
844
+ const paths = await orderedSlidePaths(pkg);
845
+ const children = [];
846
+ for (let i = 0; i < paths.length; i++) {
847
+ children.push(...await convertSlide(pkg, paths[i], i));
848
+ }
849
+ return { type: "document", children };
622
850
  }
623
- async function pptxToDoc(_data, _options) {
624
- throw new Error("PPTX import is not yet implemented");
851
+
852
+ // src/pptx/index.ts
853
+ async function pptxToDoc(data, options) {
854
+ return markdownToDoc(await pptxToMarkdownDoc(data, options));
625
855
  }
626
856
 
627
857
  export {
@@ -630,4 +860,4 @@ export {
630
860
  pptxToMarkdownDoc,
631
861
  pptxToDoc
632
862
  };
633
- //# sourceMappingURL=chunk-VN2KEOYB.js.map
863
+ //# sourceMappingURL=chunk-I2GFTEOV.js.map