@bendyline/squisq-formats 1.3.0 → 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 (224) 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/container/index.d.ts +7 -5
  24. package/dist/container/index.js +39 -70
  25. package/dist/container/index.js.map +1 -1
  26. package/dist/csv/index.d.ts +37 -0
  27. package/dist/csv/index.js +13 -0
  28. package/dist/csv/index.js.map +1 -0
  29. package/dist/docx/index.d.ts +128 -15
  30. package/dist/docx/index.js +19 -22
  31. package/dist/docx/index.js.map +1 -1
  32. package/dist/epub/index.d.ts +66 -11
  33. package/dist/epub/index.js +11 -18
  34. package/dist/epub/index.js.map +1 -1
  35. package/dist/html/index.d.ts +315 -15
  36. package/dist/html/index.js +32 -165
  37. package/dist/html/index.js.map +1 -1
  38. package/dist/index.d.ts +10 -38
  39. package/dist/index.js +80 -37
  40. package/dist/index.js.map +1 -1
  41. package/dist/ooxml/index.d.ts +353 -14
  42. package/dist/ooxml/index.js +116 -22
  43. package/dist/ooxml/index.js.map +1 -1
  44. package/dist/pdf/index.d.ts +143 -17
  45. package/dist/pdf/index.js +16 -25
  46. package/dist/pdf/index.js.map +1 -1
  47. package/dist/pptx/index.d.ts +98 -21
  48. package/dist/pptx/index.js +18 -34
  49. package/dist/pptx/index.js.map +1 -1
  50. package/dist/xlsx/index.d.ts +29 -25
  51. package/dist/xlsx/index.js +13 -44
  52. package/dist/xlsx/index.js.map +1 -1
  53. package/package.json +7 -2
  54. package/src/__tests__/csvImport.test.ts +51 -0
  55. package/src/__tests__/exportThemeReconciliation.test.ts +87 -0
  56. package/src/__tests__/htmlImport.test.ts +57 -0
  57. package/src/__tests__/plainHtml.test.ts +31 -0
  58. package/src/__tests__/pptxExport.test.ts +138 -0
  59. package/src/__tests__/pptxImport.test.ts +70 -0
  60. package/src/__tests__/roundTripMatrix.fixtures.ts +86 -0
  61. package/src/__tests__/roundTripMatrix.helpers.ts +154 -0
  62. package/src/__tests__/roundTripMatrix.test.ts +136 -0
  63. package/src/__tests__/xlsxImport.test.ts +80 -0
  64. package/src/csv/index.ts +165 -0
  65. package/src/docx/export.ts +27 -44
  66. package/src/docx/import.ts +1 -2
  67. package/src/epub/export.ts +10 -27
  68. package/src/html/import.ts +297 -0
  69. package/src/html/index.ts +4 -0
  70. package/src/html/plainHtml.ts +66 -16
  71. package/src/index.ts +10 -3
  72. package/src/ooxml/namespaces.ts +3 -0
  73. package/src/pdf/export.ts +10 -5
  74. package/src/pdf/import.ts +1 -1
  75. package/src/pptx/export.ts +225 -85
  76. package/src/pptx/import.ts +156 -0
  77. package/src/pptx/index.ts +10 -28
  78. package/src/shared/inlineRuns.ts +99 -0
  79. package/src/shared/text.ts +41 -0
  80. package/src/xlsx/import.ts +159 -0
  81. package/src/xlsx/index.ts +11 -28
  82. package/dist/__tests__/container.test.d.ts +0 -8
  83. package/dist/__tests__/container.test.d.ts.map +0 -1
  84. package/dist/__tests__/container.test.js +0 -147
  85. package/dist/__tests__/container.test.js.map +0 -1
  86. package/dist/__tests__/docxExport.test.d.ts +0 -8
  87. package/dist/__tests__/docxExport.test.d.ts.map +0 -1
  88. package/dist/__tests__/docxExport.test.js +0 -383
  89. package/dist/__tests__/docxExport.test.js.map +0 -1
  90. package/dist/__tests__/docxImport.test.d.ts +0 -8
  91. package/dist/__tests__/docxImport.test.d.ts.map +0 -1
  92. package/dist/__tests__/docxImport.test.js +0 -309
  93. package/dist/__tests__/docxImport.test.js.map +0 -1
  94. package/dist/__tests__/epub.test.d.ts +0 -8
  95. package/dist/__tests__/epub.test.d.ts.map +0 -1
  96. package/dist/__tests__/epub.test.js +0 -472
  97. package/dist/__tests__/epub.test.js.map +0 -1
  98. package/dist/__tests__/html.test.d.ts +0 -8
  99. package/dist/__tests__/html.test.d.ts.map +0 -1
  100. package/dist/__tests__/html.test.js +0 -317
  101. package/dist/__tests__/html.test.js.map +0 -1
  102. package/dist/__tests__/ooxml.test.d.ts +0 -5
  103. package/dist/__tests__/ooxml.test.d.ts.map +0 -1
  104. package/dist/__tests__/ooxml.test.js +0 -152
  105. package/dist/__tests__/ooxml.test.js.map +0 -1
  106. package/dist/__tests__/pdfExport.test.d.ts +0 -8
  107. package/dist/__tests__/pdfExport.test.d.ts.map +0 -1
  108. package/dist/__tests__/pdfExport.test.js +0 -275
  109. package/dist/__tests__/pdfExport.test.js.map +0 -1
  110. package/dist/__tests__/pdfImport.test.d.ts +0 -11
  111. package/dist/__tests__/pdfImport.test.d.ts.map +0 -1
  112. package/dist/__tests__/pdfImport.test.js +0 -254
  113. package/dist/__tests__/pdfImport.test.js.map +0 -1
  114. package/dist/__tests__/plainHtml.test.d.ts +0 -5
  115. package/dist/__tests__/plainHtml.test.d.ts.map +0 -1
  116. package/dist/__tests__/plainHtml.test.js +0 -327
  117. package/dist/__tests__/plainHtml.test.js.map +0 -1
  118. package/dist/__tests__/plainHtmlBundle.test.d.ts +0 -11
  119. package/dist/__tests__/plainHtmlBundle.test.d.ts.map +0 -1
  120. package/dist/__tests__/plainHtmlBundle.test.js +0 -210
  121. package/dist/__tests__/plainHtmlBundle.test.js.map +0 -1
  122. package/dist/__tests__/roundTrip.test.d.ts +0 -7
  123. package/dist/__tests__/roundTrip.test.d.ts.map +0 -1
  124. package/dist/__tests__/roundTrip.test.js +0 -173
  125. package/dist/__tests__/roundTrip.test.js.map +0 -1
  126. package/dist/chunk-33YRFXZZ.js.map +0 -1
  127. package/dist/chunk-67KIJHV2.js +0 -21
  128. package/dist/chunk-67KIJHV2.js.map +0 -1
  129. package/dist/chunk-7DEUGIOO.js.map +0 -1
  130. package/dist/chunk-ERZ627GR.js.map +0 -1
  131. package/dist/chunk-S3Y7H2BK.js.map +0 -1
  132. package/dist/chunk-UDS45KUJ.js.map +0 -1
  133. package/dist/chunk-VN2KEOYB.js.map +0 -1
  134. package/dist/chunk-YN5HFCEW.js +0 -120
  135. package/dist/chunk-YN5HFCEW.js.map +0 -1
  136. package/dist/container/index.d.ts.map +0 -1
  137. package/dist/docx/export.d.ts +0 -69
  138. package/dist/docx/export.d.ts.map +0 -1
  139. package/dist/docx/export.js +0 -985
  140. package/dist/docx/export.js.map +0 -1
  141. package/dist/docx/import.d.ts +0 -65
  142. package/dist/docx/import.d.ts.map +0 -1
  143. package/dist/docx/import.js +0 -779
  144. package/dist/docx/import.js.map +0 -1
  145. package/dist/docx/index.d.ts.map +0 -1
  146. package/dist/docx/styles.d.ts +0 -68
  147. package/dist/docx/styles.d.ts.map +0 -1
  148. package/dist/docx/styles.js +0 -125
  149. package/dist/docx/styles.js.map +0 -1
  150. package/dist/epub/export.d.ts +0 -72
  151. package/dist/epub/export.d.ts.map +0 -1
  152. package/dist/epub/export.js +0 -698
  153. package/dist/epub/export.js.map +0 -1
  154. package/dist/epub/index.d.ts.map +0 -1
  155. package/dist/html/docsHtmlBundle.d.ts +0 -53
  156. package/dist/html/docsHtmlBundle.d.ts.map +0 -1
  157. package/dist/html/docsHtmlBundle.js +0 -299
  158. package/dist/html/docsHtmlBundle.js.map +0 -1
  159. package/dist/html/htmlTemplate.d.ts +0 -70
  160. package/dist/html/htmlTemplate.d.ts.map +0 -1
  161. package/dist/html/htmlTemplate.js +0 -282
  162. package/dist/html/htmlTemplate.js.map +0 -1
  163. package/dist/html/imageUtils.d.ts +0 -29
  164. package/dist/html/imageUtils.d.ts.map +0 -1
  165. package/dist/html/imageUtils.js +0 -63
  166. package/dist/html/imageUtils.js.map +0 -1
  167. package/dist/html/index.d.ts.map +0 -1
  168. package/dist/html/plainHtml.d.ts +0 -79
  169. package/dist/html/plainHtml.d.ts.map +0 -1
  170. package/dist/html/plainHtml.js +0 -614
  171. package/dist/html/plainHtml.js.map +0 -1
  172. package/dist/html/plainHtmlBundle.d.ts +0 -93
  173. package/dist/html/plainHtmlBundle.d.ts.map +0 -1
  174. package/dist/html/plainHtmlBundle.js +0 -357
  175. package/dist/html/plainHtmlBundle.js.map +0 -1
  176. package/dist/index.d.ts.map +0 -1
  177. package/dist/ooxml/index.d.ts.map +0 -1
  178. package/dist/ooxml/namespaces.d.ts +0 -77
  179. package/dist/ooxml/namespaces.d.ts.map +0 -1
  180. package/dist/ooxml/namespaces.js +0 -104
  181. package/dist/ooxml/namespaces.js.map +0 -1
  182. package/dist/ooxml/reader.d.ts +0 -52
  183. package/dist/ooxml/reader.d.ts.map +0 -1
  184. package/dist/ooxml/reader.js +0 -190
  185. package/dist/ooxml/reader.js.map +0 -1
  186. package/dist/ooxml/types.d.ts +0 -82
  187. package/dist/ooxml/types.d.ts.map +0 -1
  188. package/dist/ooxml/types.js +0 -9
  189. package/dist/ooxml/types.js.map +0 -1
  190. package/dist/ooxml/writer.d.ts +0 -71
  191. package/dist/ooxml/writer.d.ts.map +0 -1
  192. package/dist/ooxml/writer.js +0 -200
  193. package/dist/ooxml/writer.js.map +0 -1
  194. package/dist/ooxml/xmlUtils.d.ts +0 -76
  195. package/dist/ooxml/xmlUtils.d.ts.map +0 -1
  196. package/dist/ooxml/xmlUtils.js +0 -108
  197. package/dist/ooxml/xmlUtils.js.map +0 -1
  198. package/dist/pdf/export.d.ts +0 -56
  199. package/dist/pdf/export.d.ts.map +0 -1
  200. package/dist/pdf/export.js +0 -768
  201. package/dist/pdf/export.js.map +0 -1
  202. package/dist/pdf/import.d.ts +0 -94
  203. package/dist/pdf/import.d.ts.map +0 -1
  204. package/dist/pdf/import.js +0 -796
  205. package/dist/pdf/import.js.map +0 -1
  206. package/dist/pdf/index.d.ts.map +0 -1
  207. package/dist/pdf/styles.d.ts +0 -142
  208. package/dist/pdf/styles.d.ts.map +0 -1
  209. package/dist/pdf/styles.js +0 -145
  210. package/dist/pdf/styles.js.map +0 -1
  211. package/dist/pptx/export.d.ts +0 -75
  212. package/dist/pptx/export.d.ts.map +0 -1
  213. package/dist/pptx/export.js +0 -724
  214. package/dist/pptx/export.js.map +0 -1
  215. package/dist/pptx/index.d.ts.map +0 -1
  216. package/dist/pptx/styles.d.ts +0 -54
  217. package/dist/pptx/styles.d.ts.map +0 -1
  218. package/dist/pptx/styles.js +0 -73
  219. package/dist/pptx/styles.js.map +0 -1
  220. package/dist/pptx/templates.d.ts +0 -24
  221. package/dist/pptx/templates.d.ts.map +0 -1
  222. package/dist/pptx/templates.js +0 -158
  223. package/dist/pptx/templates.js.map +0 -1
  224. package/dist/xlsx/index.d.ts.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/epub/export.ts"],"sourcesContent":["/**\n * EPUB 3 Export\n *\n * Converts a MarkdownDocument (or Doc) to an EPUB 3 file (.epub).\n *\n * An EPUB is a ZIP archive containing XHTML chapter files, images,\n * a package manifest (content.opf), and a navigation document (toc.xhtml).\n * Content is split into chapters at H1/H2 heading boundaries.\n *\n * Uses JSZip for packaging (already a dependency), escapeXml from the\n * OOXML utils, and image utilities from the HTML exporter.\n *\n * @example\n * ```ts\n * import { markdownDocToEpub } from '@bendyline/squisq-formats/epub';\n *\n * const epub = await markdownDocToEpub(markdownDoc, {\n * title: 'My Book',\n * author: 'Jane Doe',\n * });\n * ```\n */\n\nimport JSZip from 'jszip';\nimport type { Doc, AudioSegment } from '@bendyline/squisq/schemas';\nimport { resolveFontFamily } from '@bendyline/squisq/schemas';\nimport { resolveThemeForDoc } from '@bendyline/squisq/doc';\nimport type {\n MarkdownDocument,\n MarkdownBlockNode,\n MarkdownInlineNode,\n MarkdownHeading,\n MarkdownParagraph,\n MarkdownListItem,\n MarkdownTable,\n MarkdownTableRow,\n MarkdownTableCell,\n} from '@bendyline/squisq/markdown';\nimport { readFrontmatterThemeId } from '@bendyline/squisq/markdown';\nimport { escapeXml } from '../ooxml/xmlUtils.js';\nimport { inferMimeType, extractFilename } from '../html/imageUtils.js';\nimport { extractPlainText } from '../shared/text.js';\n\n// ── Public API ────────────────────────────────────────────────────\n\nexport interface EpubExportOptions {\n /** Book title (default: 'Untitled') */\n title?: string;\n /** Author name */\n author?: string;\n /** Book description / summary */\n description?: string;\n /** BCP-47 language code (default: 'en') */\n language?: string;\n /** Publisher name */\n publisher?: string;\n /** Squisq theme ID for CSS styling */\n themeId?: string;\n /** Pre-resolved image data keyed by relative path as it appears in the markdown */\n images?: Map<string, ArrayBuffer>;\n /** Cover image data (JPEG or PNG) */\n coverImage?: ArrayBuffer;\n /**\n * Audio narration data keyed by segment src/name.\n * When provided alongside audioSegments, EPUB 3 Media Overlays (SMIL)\n * are generated for synchronized audio playback.\n */\n audio?: Map<string, ArrayBuffer>;\n /**\n * Audio segment metadata (from Doc.audio.segments).\n * Required together with `audio` to generate Media Overlays.\n * Each segment's duration and startTime are used to build SMIL timing.\n */\n audioSegments?: AudioSegment[];\n /** Total document duration in seconds (used for Media Overlay metadata) */\n totalDuration?: number;\n}\n\n/**\n * Convert a MarkdownDocument to an EPUB 3 file.\n *\n * Chapters are split at H1/H2 heading boundaries. All referenced images\n * (provided via `options.images`) are embedded in the archive.\n */\nexport async function markdownDocToEpub(\n doc: MarkdownDocument,\n options: EpubExportOptions = {},\n): Promise<ArrayBuffer> {\n const fmTitle = doc.frontmatter?.title;\n const fmAuthor = doc.frontmatter?.author;\n const title = options.title ?? (typeof fmTitle === 'string' ? fmTitle : 'Untitled');\n const author = options.author ?? (typeof fmAuthor === 'string' ? fmAuthor : '');\n const language = options.language ?? 'en';\n const description = options.description ?? '';\n const publisher = options.publisher ?? '';\n const uuid = crypto.randomUUID();\n\n // Split document into chapters\n const chapters = splitIntoChapters(doc.children);\n\n // Collect images referenced in the document, deduplicating filenames\n const imageEntries = collectDocImages(doc.children);\n const resolvedImages = new Map<string, { data: ArrayBuffer; mime: string; filename: string }>();\n if (options.images) {\n const usedNames = new Set<string>();\n for (const src of imageEntries) {\n const data = options.images.get(src);\n if (data) {\n let filename = extractFilename(src);\n // Deduplicate: if two paths share a basename (e.g. a/hero.png and b/hero.png)\n if (usedNames.has(filename)) {\n const dot = filename.lastIndexOf('.');\n const base = dot > 0 ? filename.slice(0, dot) : filename;\n const ext = dot > 0 ? filename.slice(dot) : '';\n let counter = 2;\n while (usedNames.has(`${base}-${counter}${ext}`)) counter++;\n filename = `${base}-${counter}${ext}`;\n }\n usedNames.add(filename);\n resolvedImages.set(src, { data, mime: inferMimeType(filename), filename });\n }\n }\n }\n\n // Generate theme CSS — honor an explicit themeId, else the doc's frontmatter\n // theme (`squisq-theme` / legacy), mirroring the other export formats.\n const css = generateStylesheet(options.themeId ?? readFrontmatterThemeId(doc.frontmatter), doc);\n\n // Build the ZIP\n const zip = new JSZip();\n\n // mimetype must be first entry, stored (not compressed)\n zip.file('mimetype', 'application/epub+zip', { compression: 'STORE' });\n\n // META-INF/container.xml\n zip.file('META-INF/container.xml', CONTAINER_XML);\n\n // OEBPS/styles.css\n zip.file('OEBPS/styles.css', css);\n\n // OEBPS/images/*\n for (const [, img] of resolvedImages) {\n zip.file(`OEBPS/images/${img.filename}`, img.data);\n }\n\n // Cover image — detect PNG vs JPEG from magic bytes.\n // When provided, generates a cover.xhtml page in the spine so e-readers\n // (especially Kindle) display the cover as both thumbnail and first page.\n let coverFilename: string | undefined;\n if (options.coverImage) {\n const bytes = new Uint8Array(options.coverImage);\n const isPng =\n bytes.length >= 4 &&\n bytes[0] === 0x89 &&\n bytes[1] === 0x50 &&\n bytes[2] === 0x4e &&\n bytes[3] === 0x47;\n coverFilename = isPng ? 'cover.png' : 'cover.jpg';\n zip.file(`OEBPS/images/${coverFilename}`, options.coverImage);\n\n // Generate cover XHTML page — full-bleed image, no margins\n const coverXhtml = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:epub=\"http://www.idpf.org/2007/ops\">\n<head>\n <meta charset=\"UTF-8\"/>\n <title>Cover</title>\n <style>\n body { margin: 0; padding: 0; text-align: center; }\n img { max-width: 100%; max-height: 100%; }\n </style>\n</head>\n<body>\n <img src=\"../images/${escapeXml(coverFilename)}\" alt=\"Cover\"/>\n</body>\n</html>`;\n zip.file('OEBPS/chapters/cover.xhtml', coverXhtml);\n }\n\n // ── Audio narration ──────────────────────────────────────────────\n const audioMap = options.audio;\n const audioSegments = options.audioSegments;\n const hasAudio = audioMap && audioSegments && audioSegments.length > 0;\n // Per-segment audio file info, indexed by segment index (null if data missing)\n const segmentAudioFiles: ({ filename: string; mime: string } | null)[] = [];\n const allAudioFiles: { filename: string; mime: string }[] = [];\n\n if (hasAudio) {\n for (const seg of audioSegments) {\n const data = audioMap.get(seg.src) ?? audioMap.get(seg.name);\n if (data) {\n const filename = extractFilename(seg.src);\n const finalName = filename.includes('.') ? filename : `${filename}.mp3`;\n zip.file(`OEBPS/audio/${finalName}`, data);\n const info = { filename: finalName, mime: inferMimeType(finalName) };\n segmentAudioFiles.push(info);\n allAudioFiles.push(info);\n } else {\n segmentAudioFiles.push(null);\n }\n }\n }\n\n // Build chapter-to-audio mapping for SMIL overlays\n const chapterAudio: (ChapterAudioInfo | null)[] = [];\n if (hasAudio && allAudioFiles.length > 0) {\n if (chapters.length !== audioSegments.length) {\n console.warn(\n `EPUB: ${chapters.length} chapters but ${audioSegments.length} audio segments — ` +\n `extra chapters will reuse the last segment's audio`,\n );\n }\n for (let i = 0; i < chapters.length; i++) {\n const segIdx = Math.min(i, audioSegments.length - 1);\n const seg = audioSegments[segIdx];\n const audioFile = segmentAudioFiles[segIdx];\n if (audioFile) {\n chapterAudio.push({\n audioFilename: audioFile.filename,\n clipStart: 0,\n clipEnd: seg.duration,\n duration: seg.duration,\n });\n } else {\n chapterAudio.push(null);\n }\n }\n }\n\n // OEBPS/chapters/*.xhtml + optional SMIL overlays\n const chapterFiles: ChapterFileInfo[] = [];\n for (let i = 0; i < chapters.length; i++) {\n const chap = chapters[i];\n const num = String(i + 1).padStart(3, '0');\n const id = `chapter-${num}`;\n const filename = `${id}.xhtml`;\n const audioInfo = chapterAudio[i] ?? null;\n\n // Render XHTML with element IDs for SMIL references when audio is present\n const xhtml = renderChapterXhtml(chap.nodes, title, resolvedImages, audioInfo !== null);\n zip.file(`OEBPS/chapters/${filename}`, xhtml);\n\n let smilFilename: string | undefined;\n if (audioInfo) {\n smilFilename = `${id}.smil`;\n const smil = generateSmil(filename, audioInfo, chap.nodes);\n zip.file(`OEBPS/chapters/${smilFilename}`, smil);\n }\n\n chapterFiles.push({\n id,\n filename,\n title: chap.title,\n smilFilename,\n duration: audioInfo?.duration,\n });\n }\n\n // OEBPS/toc.xhtml (EPUB 3 nav)\n zip.file('OEBPS/toc.xhtml', generateTocXhtml(chapterFiles, title));\n\n // OEBPS/content.opf\n zip.file(\n 'OEBPS/content.opf',\n generateContentOpf({\n uuid,\n title,\n author,\n language,\n description,\n publisher,\n chapters: chapterFiles,\n images: resolvedImages,\n coverFilename,\n audioFiles: allAudioFiles,\n totalDuration: options.totalDuration,\n }),\n );\n\n const blob = await zip.generateAsync({\n type: 'arraybuffer',\n compression: 'DEFLATE',\n compressionOptions: { level: 6 },\n // mimetype was already set to STORE above; JSZip respects per-file options\n });\n\n return blob;\n}\n\n/**\n * Convert a squisq Doc to an EPUB 3 file.\n *\n * Convenience wrapper: Doc → MarkdownDocument → EPUB.\n * When the Doc has audio segments and `options.audio` is provided,\n * EPUB 3 Media Overlays are generated for narrated playback.\n */\nexport async function docToEpub(doc: Doc, options: EpubExportOptions = {}): Promise<ArrayBuffer> {\n const { docToMarkdown } = await import('@bendyline/squisq/doc');\n const markdownDoc = docToMarkdown(doc);\n\n // Thread audio segment metadata from the Doc into options\n const epubOptions: EpubExportOptions = { ...options };\n if (doc.audio?.segments?.length && !epubOptions.audioSegments) {\n epubOptions.audioSegments = doc.audio.segments;\n }\n if (doc.duration && !epubOptions.totalDuration) {\n epubOptions.totalDuration = doc.duration;\n }\n\n return markdownDocToEpub(markdownDoc, epubOptions);\n}\n\n// ── Chapter Splitting ─────────────────────────────────────────────\n\ninterface Chapter {\n title: string;\n nodes: MarkdownBlockNode[];\n}\n\ninterface ChapterFileInfo {\n id: string;\n filename: string;\n title: string;\n smilFilename?: string;\n duration?: number;\n}\n\ninterface ChapterAudioInfo {\n audioFilename: string;\n clipStart: number;\n clipEnd: number;\n duration: number;\n}\n\nfunction splitIntoChapters(nodes: MarkdownBlockNode[]): Chapter[] {\n const chapters: Chapter[] = [];\n let currentNodes: MarkdownBlockNode[] = [];\n let currentTitle = 'Untitled';\n\n for (const node of nodes) {\n if (node.type === 'heading' && node.depth <= 2) {\n // Flush previous chapter\n if (currentNodes.length > 0) {\n chapters.push({ title: currentTitle, nodes: currentNodes });\n }\n currentTitle = extractHeadingText(node);\n currentNodes = [node];\n } else {\n currentNodes.push(node);\n }\n }\n\n // Flush remaining\n if (currentNodes.length > 0) {\n chapters.push({ title: currentTitle, nodes: currentNodes });\n }\n\n // If no chapters were created, wrap everything as one\n if (chapters.length === 0) {\n chapters.push({ title: 'Untitled', nodes: [] });\n }\n\n return chapters;\n}\n\nfunction extractHeadingText(heading: MarkdownHeading): string {\n return extractPlainText(heading.children);\n}\n\n// ── Image Collection ──────────────────────────────────────────────\n\nfunction collectDocImages(nodes: MarkdownBlockNode[]): Set<string> {\n const images = new Set<string>();\n\n function walkBlock(node: MarkdownBlockNode): void {\n switch (node.type) {\n case 'paragraph':\n case 'heading':\n node.children.forEach(walkInline);\n break;\n case 'blockquote':\n node.children.forEach(walkBlock);\n break;\n case 'list':\n node.children.forEach((item) => item.children.forEach(walkBlock));\n break;\n case 'table':\n node.children.forEach((row) =>\n row.children.forEach((cell) => cell.children.forEach(walkInline)),\n );\n break;\n default:\n break;\n }\n }\n\n function walkInline(node: MarkdownInlineNode): void {\n if (node.type === 'image' && node.url && !node.url.startsWith('data:')) {\n images.add(node.url);\n }\n if ('children' in node && Array.isArray(node.children)) {\n (node.children as MarkdownInlineNode[]).forEach(walkInline);\n }\n }\n\n nodes.forEach(walkBlock);\n return images;\n}\n\n// ── XHTML Rendering ───────────────────────────────────────────────\n\ntype ImageMap = Map<string, { data: ArrayBuffer; mime: string; filename: string }>;\n\nfunction renderChapterXhtml(\n nodes: MarkdownBlockNode[],\n bookTitle: string,\n images: ImageMap,\n addIds = false,\n): string {\n let elementCounter = 0;\n const nextId = () => `p${++elementCounter}`;\n const body = nodes.map((n) => blockToXhtml(n, images, addIds ? nextId : undefined)).join('\\n');\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:epub=\"http://www.idpf.org/2007/ops\">\n<head>\n <meta charset=\"UTF-8\"/>\n <title>${escapeXml(bookTitle)}</title>\n <link rel=\"stylesheet\" type=\"text/css\" href=\"../styles.css\"/>\n</head>\n<body>\n${body}\n</body>\n</html>`;\n}\n\nfunction blockToXhtml(node: MarkdownBlockNode, images: ImageMap, nextId?: () => string): string {\n const idAttr = nextId ? ` id=\"${nextId()}\"` : '';\n\n switch (node.type) {\n case 'heading': {\n const tag = `h${node.depth}`;\n return `<${tag}${idAttr}>${inlinesToXhtml(node.children, images)}</${tag}>`;\n }\n\n case 'paragraph':\n return `<p${idAttr}>${inlinesToXhtml(node.children, images)}</p>`;\n\n case 'blockquote':\n return `<blockquote${idAttr}>\\n${node.children.map((c) => blockToXhtml(c, images, nextId)).join('\\n')}\\n</blockquote>`;\n\n case 'list': {\n const tag = node.ordered ? 'ol' : 'ul';\n const startAttr =\n node.ordered && node.start && node.start !== 1 ? ` start=\"${node.start}\"` : '';\n const items = node.children.map((item) => listItemToXhtml(item, images)).join('\\n');\n return `<${tag}${idAttr}${startAttr}>\\n${items}\\n</${tag}>`;\n }\n\n case 'code': {\n const langAttr = node.lang ? ` class=\"language-${escapeXml(node.lang)}\"` : '';\n return `<pre${idAttr}><code${langAttr}>${escapeXml(node.value)}</code></pre>`;\n }\n\n case 'thematicBreak':\n return `<hr${idAttr}/>`;\n\n case 'table':\n return tableToXhtml(node as MarkdownTable, images, idAttr);\n\n case 'htmlBlock':\n // Strip HTML tags for XHTML safety — raw HTML may not be well-formed XML\n return `<p${idAttr}>${escapeXml(node.rawHtml.replace(/<[^>]+>/g, ''))}</p>`;\n\n case 'math':\n return `<p${idAttr} class=\"math\">${escapeXml(node.value)}</p>`;\n\n default:\n return '';\n }\n}\n\nfunction listItemToXhtml(item: MarkdownListItem, images: ImageMap): string {\n const content = item.children.map((c) => blockToXhtml(c, images)).join('\\n');\n // Unwrap single <p> inside <li> for cleaner output\n const unwrapped =\n item.children.length === 1 && item.children[0].type === 'paragraph'\n ? inlinesToXhtml((item.children[0] as MarkdownParagraph).children, images)\n : content;\n return `<li>${unwrapped}</li>`;\n}\n\nfunction tableToXhtml(table: MarkdownTable, images: ImageMap, idAttr = ''): string {\n const rows = table.children;\n if (rows.length === 0) return `<table${idAttr}></table>`;\n\n const headerRow = rows[0];\n const bodyRows = rows.slice(1);\n const align = table.align ?? [];\n\n function cellToXhtml(cell: MarkdownTableCell, tag: 'th' | 'td', colIndex: number): string {\n const a = align[colIndex];\n const style = a ? ` style=\"text-align: ${a}\"` : '';\n return `<${tag}${style}>${inlinesToXhtml(cell.children, images)}</${tag}>`;\n }\n\n const thead = `<thead><tr>${headerRow.children.map((c, i) => cellToXhtml(c, 'th', i)).join('')}</tr></thead>`;\n const tbody =\n bodyRows.length > 0\n ? `<tbody>${bodyRows.map((row: MarkdownTableRow) => `<tr>${row.children.map((c, i) => cellToXhtml(c, 'td', i)).join('')}</tr>`).join('')}</tbody>`\n : '';\n\n return `<table${idAttr}>${thead}${tbody}</table>`;\n}\n\nfunction inlinesToXhtml(nodes: MarkdownInlineNode[], images: ImageMap): string {\n return nodes.map((n) => inlineToXhtml(n, images)).join('');\n}\n\nfunction inlineToXhtml(node: MarkdownInlineNode, images: ImageMap): string {\n switch (node.type) {\n case 'text':\n return escapeXml(node.value);\n\n case 'strong':\n return `<strong>${inlinesToXhtml(node.children, images)}</strong>`;\n\n case 'emphasis':\n return `<em>${inlinesToXhtml(node.children, images)}</em>`;\n\n case 'delete':\n return `<del>${inlinesToXhtml(node.children, images)}</del>`;\n\n case 'inlineCode':\n return `<code>${escapeXml(node.value)}</code>`;\n\n case 'link': {\n const titleAttr = node.title ? ` title=\"${escapeXml(node.title)}\"` : '';\n return `<a href=\"${escapeXml(node.url)}\"${titleAttr}>${inlinesToXhtml(node.children, images)}</a>`;\n }\n\n case 'image': {\n const alt = escapeXml(node.alt ?? '');\n const resolved = images.get(node.url);\n const src = resolved ? `../images/${resolved.filename}` : escapeXml(node.url);\n return `<img src=\"${src}\" alt=\"${alt}\"/>`;\n }\n\n case 'break':\n return '<br/>';\n\n case 'inlineMath':\n return `<span class=\"math\">${escapeXml(node.value)}</span>`;\n\n case 'htmlInline':\n // Strip tags for XHTML safety\n return escapeXml(node.rawHtml.replace(/<[^>]+>/g, ''));\n\n default:\n return '';\n }\n}\n\n// ── SMIL Media Overlays ───────────────────────────────────────────\n\n/**\n * Generate an EPUB 3 Media Overlay (SMIL) file for a chapter.\n * Maps block-level elements to audio clip ranges for synchronized narration.\n */\nfunction generateSmil(\n chapterFilename: string,\n audioInfo: ChapterAudioInfo,\n nodes: MarkdownBlockNode[],\n): string {\n // Count block elements to match the IDs generated by blockToXhtml.\n // Must mirror blockToXhtml's recursion: each block gets an ID,\n // blockquote children recurse (they pass nextId), but list items do not.\n let elementCount = 0;\n function countBlocks(node: MarkdownBlockNode): void {\n elementCount++;\n if (node.type === 'blockquote') node.children.forEach(countBlocks);\n }\n nodes.forEach(countBlocks);\n\n if (elementCount === 0) elementCount = 1;\n\n // Distribute audio duration evenly across elements (best effort without word-level timing)\n const clipDuration = audioInfo.duration / elementCount;\n const pars: string[] = [];\n\n for (let i = 0; i < elementCount; i++) {\n const clipStart = formatTime(audioInfo.clipStart + i * clipDuration, true);\n const clipEnd = formatTime(audioInfo.clipStart + (i + 1) * clipDuration, true);\n pars.push(\n ` <par id=\"par-${i + 1}\">` +\n `\\n <text src=\"${chapterFilename}#p${i + 1}\"/>` +\n `\\n <audio src=\"../audio/${escapeXml(audioInfo.audioFilename)}\" clipBegin=\"${clipStart}\" clipEnd=\"${clipEnd}\"/>` +\n `\\n </par>`,\n );\n }\n\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<smil xmlns=\"http://www.w3.org/ns/SMIL\" xmlns:epub=\"http://www.idpf.org/2007/ops\" version=\"3.0\">\n <body>\n <seq id=\"seq-1\" epub:textref=\"${chapterFilename}\">\n${pars.join('\\n')}\n </seq>\n </body>\n</smil>`;\n}\n\nfunction formatTime(seconds: number, fractional = false): string {\n const h = Math.floor(seconds / 3600);\n const m = Math.floor((seconds % 3600) / 60);\n const s = seconds % 60;\n const sPart = fractional ? s.toFixed(3).padStart(6, '0') : String(Math.floor(s)).padStart(2, '0');\n return `${h}:${String(m).padStart(2, '0')}:${sPart}`;\n}\n\n// ── Package Documents ─────────────────────────────────────────────\n\nconst CONTAINER_XML = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<container version=\"1.0\" xmlns=\"urn:oasis:names:tc:opendocument:xmlns:container\">\n <rootfiles>\n <rootfile full-path=\"OEBPS/content.opf\" media-type=\"application/oebps-package+xml\"/>\n </rootfiles>\n</container>`;\n\ninterface OpfParams {\n uuid: string;\n title: string;\n author: string;\n language: string;\n description: string;\n publisher: string;\n chapters: ChapterFileInfo[];\n images: ImageMap;\n coverFilename?: string;\n audioFiles?: { filename: string; mime: string }[];\n totalDuration?: number;\n}\n\nfunction generateContentOpf(params: OpfParams): string {\n const {\n uuid,\n title,\n author,\n language,\n description,\n publisher,\n chapters,\n images,\n coverFilename,\n audioFiles,\n totalDuration,\n } = params;\n const modified = new Date().toISOString().replace(/\\.\\d+Z$/, 'Z');\n const hasOverlays = chapters.some((c) => c.smilFilename);\n\n // Manifest items\n const manifestItems: string[] = [\n ' <item id=\"toc\" href=\"toc.xhtml\" media-type=\"application/xhtml+xml\" properties=\"nav\"/>',\n ' <item id=\"css\" href=\"styles.css\" media-type=\"text/css\"/>',\n ];\n\n if (coverFilename) {\n const mime = inferMimeType(coverFilename);\n manifestItems.push(\n ` <item id=\"cover-image\" href=\"images/${escapeXml(coverFilename)}\" media-type=\"${mime}\" properties=\"cover-image\"/>`,\n );\n manifestItems.push(\n ' <item id=\"cover-page\" href=\"chapters/cover.xhtml\" media-type=\"application/xhtml+xml\"/>',\n );\n }\n\n for (const chap of chapters) {\n const overlayAttr = chap.smilFilename ? ` media-overlay=\"${chap.id}-overlay\"` : '';\n manifestItems.push(\n ` <item id=\"${chap.id}\" href=\"chapters/${escapeXml(chap.filename)}\" media-type=\"application/xhtml+xml\"${overlayAttr}/>`,\n );\n if (chap.smilFilename) {\n manifestItems.push(\n ` <item id=\"${chap.id}-overlay\" href=\"chapters/${escapeXml(chap.smilFilename)}\" media-type=\"application/smil+xml\"/>`,\n );\n }\n }\n\n // Audio files in manifest\n if (audioFiles) {\n const usedAudioNames = new Set<string>();\n for (const af of audioFiles) {\n if (usedAudioNames.has(af.filename)) continue;\n usedAudioNames.add(af.filename);\n const audioId = `audio-${af.filename.replace(/[^a-zA-Z0-9]/g, '-')}`;\n manifestItems.push(\n ` <item id=\"${audioId}\" href=\"audio/${escapeXml(af.filename)}\" media-type=\"${af.mime}\"/>`,\n );\n }\n }\n\n const usedFilenames = new Set<string>();\n for (const [, img] of images) {\n if (usedFilenames.has(img.filename)) continue;\n usedFilenames.add(img.filename);\n const imgId = `img-${img.filename.replace(/[^a-zA-Z0-9]/g, '-')}`;\n manifestItems.push(\n ` <item id=\"${imgId}\" href=\"images/${escapeXml(img.filename)}\" media-type=\"${img.mime}\"/>`,\n );\n }\n\n // Spine — cover page first (if present), then chapters\n const spineEntries: string[] = [];\n if (coverFilename) {\n spineEntries.push(' <itemref idref=\"cover-page\"/>');\n }\n for (const chap of chapters) {\n spineEntries.push(` <itemref idref=\"${chap.id}\"/>`);\n }\n const spineItems = spineEntries.join('\\n');\n\n // Metadata\n const metaParts = [\n ` <dc:identifier id=\"uid\">urn:uuid:${uuid}</dc:identifier>`,\n ` <dc:title>${escapeXml(title)}</dc:title>`,\n ` <dc:language>${escapeXml(language)}</dc:language>`,\n ` <meta property=\"dcterms:modified\">${modified}</meta>`,\n ];\n if (author) metaParts.push(` <dc:creator>${escapeXml(author)}</dc:creator>`);\n if (description) metaParts.push(` <dc:description>${escapeXml(description)}</dc:description>`);\n if (publisher) metaParts.push(` <dc:publisher>${escapeXml(publisher)}</dc:publisher>`);\n\n // Media Overlay metadata\n if (hasOverlays && totalDuration) {\n metaParts.push(` <meta property=\"media:duration\">${formatTime(totalDuration)}</meta>`);\n metaParts.push(' <meta property=\"media:active-class\">epub-media-overlay-active</meta>');\n }\n\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<package xmlns=\"http://www.idpf.org/2007/opf\" version=\"3.0\" unique-identifier=\"uid\">\n <metadata xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n${metaParts.join('\\n')}\n </metadata>\n <manifest>\n${manifestItems.join('\\n')}\n </manifest>\n <spine>\n${spineItems}\n </spine>\n</package>`;\n}\n\nfunction generateTocXhtml(chapters: ChapterFileInfo[], bookTitle: string): string {\n const navItems = chapters\n .map(\n (chap) =>\n ` <li><a href=\"chapters/${escapeXml(chap.filename)}\">${escapeXml(chap.title)}</a></li>`,\n )\n .join('\\n');\n\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:epub=\"http://www.idpf.org/2007/ops\">\n<head>\n <meta charset=\"UTF-8\"/>\n <title>${escapeXml(bookTitle)}</title>\n <link rel=\"stylesheet\" type=\"text/css\" href=\"styles.css\"/>\n</head>\n<body>\n <nav epub:type=\"toc\">\n <h1>Table of Contents</h1>\n <ol>\n${navItems}\n </ol>\n </nav>\n</body>\n</html>`;\n}\n\n// ── Stylesheet ────────────────────────────────────────────────────\n\nfunction generateStylesheet(themeId: string | undefined, doc?: MarkdownDocument): string {\n let themeVars = '';\n if (themeId) {\n const theme = resolveThemeForDoc(doc, themeId);\n themeVars = `\n --epub-bg: ${theme.colors.background};\n --epub-text: ${theme.colors.text};\n --epub-primary: ${theme.colors.primary};\n --epub-heading-font: ${resolveFontFamily(theme.typography.titleFont, 'serif')};\n --epub-body-font: ${resolveFontFamily(theme.typography.bodyFont, 'sans-serif')};`;\n }\n\n return `/* Squisq EPUB Stylesheet */\n:root {${themeVars}\n}\n\nbody {\n font-family: var(--epub-body-font, Georgia, 'Times New Roman', serif);\n color: var(--epub-text, #1a1a1a);\n line-height: 1.7;\n margin: 1em 2em;\n max-width: 40em;\n}\n\nh1, h2, h3, h4, h5, h6 {\n font-family: var(--epub-heading-font, system-ui, sans-serif);\n color: var(--epub-primary, #1a1a1a);\n margin-top: 1.5em;\n margin-bottom: 0.5em;\n line-height: 1.3;\n}\n\nh1 { font-size: 2em; }\nh2 { font-size: 1.5em; }\nh3 { font-size: 1.25em; }\n\np {\n margin: 0.8em 0;\n}\n\na {\n color: var(--epub-primary, #2563eb);\n}\n\nimg {\n max-width: 100%;\n height: auto;\n}\n\npre {\n background: #f5f5f5;\n padding: 1em;\n overflow-x: auto;\n border-radius: 4px;\n font-size: 0.9em;\n line-height: 1.4;\n}\n\ncode {\n font-family: 'Courier New', Courier, monospace;\n font-size: 0.9em;\n}\n\np > code, li > code {\n background: #f0f0f0;\n padding: 0.1em 0.3em;\n border-radius: 3px;\n}\n\nblockquote {\n border-left: 3px solid var(--epub-primary, #d1d5db);\n margin: 1em 0;\n padding: 0.5em 1em;\n color: #4b5563;\n}\n\ntable {\n border-collapse: collapse;\n width: 100%;\n margin: 1em 0;\n}\n\nth, td {\n border: 1px solid #d1d5db;\n padding: 0.5em 0.75em;\n text-align: left;\n}\n\nth {\n background: #f3f4f6;\n font-weight: 600;\n}\n\nhr {\n border: none;\n border-top: 1px solid #d1d5db;\n margin: 2em 0;\n}\n\nul, ol {\n margin: 0.8em 0;\n padding-left: 1.5em;\n}\n\nli {\n margin: 0.3em 0;\n}\n\n.math {\n font-family: 'Courier New', Courier, monospace;\n font-style: italic;\n}\n\n/* Media Overlay active highlight (narration sync) */\n.epub-media-overlay-active {\n background-color: rgba(37, 99, 235, 0.12);\n}\n`;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,32 @@
1
+ // src/shared/text.ts
2
+ function stripHtmlTags(html) {
3
+ return html.replace(/<[^>]*>/g, "");
4
+ }
5
+ function inlineToPlainText(node) {
6
+ switch (node.type) {
7
+ case "text":
8
+ case "inlineCode":
9
+ case "inlineMath":
10
+ return node.value;
11
+ case "emphasis":
12
+ case "strong":
13
+ case "delete":
14
+ case "link":
15
+ return extractPlainText(node.children);
16
+ case "image":
17
+ return node.alt ?? "";
18
+ case "break":
19
+ return " ";
20
+ default:
21
+ return "";
22
+ }
23
+ }
24
+ function extractPlainText(nodes) {
25
+ return nodes.map(inlineToPlainText).join("");
26
+ }
27
+
28
+ export {
29
+ stripHtmlTags,
30
+ extractPlainText
31
+ };
32
+ //# sourceMappingURL=chunk-PN52A5AA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/shared/text.ts"],"sourcesContent":["/**\n * Shared plain-text helpers used by every format exporter.\n *\n * These were previously copy-pasted into the docx / pptx / epub exporters with\n * subtle drift (e.g. some handled `inlineMath`, some handled `break`). Keeping a\n * single implementation here means a fix or a newly-supported inline node type\n * only has to be added in one place.\n */\n\nimport type { MarkdownInlineNode } from '@bendyline/squisq/markdown';\n\n/** Strip HTML tags from a string, keeping only the text content. */\nexport function stripHtmlTags(html: string): string {\n return html.replace(/<[^>]*>/g, '');\n}\n\n/** Flatten a single inline node to its plain-text content. */\nexport function inlineToPlainText(node: MarkdownInlineNode): string {\n switch (node.type) {\n case 'text':\n case 'inlineCode':\n case 'inlineMath':\n return node.value;\n case 'emphasis':\n case 'strong':\n case 'delete':\n case 'link':\n return extractPlainText(node.children);\n case 'image':\n return node.alt ?? '';\n case 'break':\n return ' ';\n default:\n return '';\n }\n}\n\n/** Flatten an array of inline nodes to their concatenated plain-text content. */\nexport function extractPlainText(nodes: MarkdownInlineNode[]): string {\n return nodes.map(inlineToPlainText).join('');\n}\n"],"mappings":";AAYO,SAAS,cAAc,MAAsB;AAClD,SAAO,KAAK,QAAQ,YAAY,EAAE;AACpC;AAGO,SAAS,kBAAkB,MAAkC;AAClE,UAAQ,KAAK,MAAM;AAAA,IACjB,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO,KAAK;AAAA,IACd,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO,iBAAiB,KAAK,QAAQ;AAAA,IACvC,KAAK;AACH,aAAO,KAAK,OAAO;AAAA,IACrB,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAGO,SAAS,iBAAiB,OAAqC;AACpE,SAAO,MAAM,IAAI,iBAAiB,EAAE,KAAK,EAAE;AAC7C;","names":[]}
@@ -2,50 +2,17 @@ import {
2
2
  escapeXml,
3
3
  xmlDeclaration
4
4
  } from "./chunk-U4MRIFKL.js";
5
-
6
- // src/ooxml/namespaces.ts
7
- var NS_RELATIONSHIPS = "http://schemas.openxmlformats.org/package/2006/relationships";
8
- var NS_CONTENT_TYPES = "http://schemas.openxmlformats.org/package/2006/content-types";
9
- var REL_OFFICE_DOCUMENT = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
10
- var REL_CORE_PROPERTIES = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
11
- var REL_EXTENDED_PROPERTIES = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties";
12
- var REL_STYLES = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
13
- var REL_NUMBERING = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering";
14
- var REL_FONT_TABLE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable";
15
- var REL_SETTINGS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings";
16
- var REL_HYPERLINK = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
17
- var REL_IMAGE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
18
- var REL_FOOTNOTES = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes";
19
- var REL_THEME = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
20
- var NS_WML = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
21
- var NS_PML = "http://schemas.openxmlformats.org/presentationml/2006/main";
22
- var NS_SML = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
23
- var NS_DRAWINGML = "http://schemas.openxmlformats.org/drawingml/2006/main";
24
- var NS_WP_DRAWING = "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing";
25
- var NS_PICTURE = "http://schemas.openxmlformats.org/drawingml/2006/picture";
26
- var NS_DC = "http://purl.org/dc/elements/1.1/";
27
- var NS_DCTERMS = "http://purl.org/dc/terms/";
28
- var NS_CORE_PROPERTIES = "http://schemas.openxmlformats.org/package/2006/metadata/core-properties";
29
- var NS_XSI = "http://www.w3.org/2001/XMLSchema-instance";
30
- var NS_MC = "http://schemas.openxmlformats.org/markup-compatibility/2006";
31
- var NS_R = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
32
- var CONTENT_TYPE_RELATIONSHIPS = "application/vnd.openxmlformats-package.relationships+xml";
33
- var CONTENT_TYPE_CORE_PROPERTIES = "application/vnd.openxmlformats-package.core-properties+xml";
34
- var CONTENT_TYPE_DOCX_DOCUMENT = "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml";
35
- var CONTENT_TYPE_DOCX_STYLES = "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml";
36
- var CONTENT_TYPE_DOCX_NUMBERING = "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml";
37
- var CONTENT_TYPE_DOCX_SETTINGS = "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml";
38
- var CONTENT_TYPE_DOCX_FONT_TABLE = "application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml";
39
- var CONTENT_TYPE_DOCX_FOOTNOTES = "application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml";
40
- var CONTENT_TYPE_PPTX_PRESENTATION = "application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml";
41
- var CONTENT_TYPE_PPTX_SLIDE = "application/vnd.openxmlformats-officedocument.presentationml.slide+xml";
42
- var CONTENT_TYPE_PPTX_SLIDE_LAYOUT = "application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml";
43
- var CONTENT_TYPE_PPTX_SLIDE_MASTER = "application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml";
44
- var CONTENT_TYPE_PPTX_THEME = "application/vnd.openxmlformats-officedocument.theme+xml";
45
- var REL_SLIDE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide";
46
- var REL_SLIDE_LAYOUT = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout";
47
- var REL_SLIDE_MASTER = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster";
48
- var CONTENT_TYPE_XLSX_WORKBOOK = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml";
5
+ import {
6
+ CONTENT_TYPE_CORE_PROPERTIES,
7
+ CONTENT_TYPE_RELATIONSHIPS,
8
+ NS_CONTENT_TYPES,
9
+ NS_CORE_PROPERTIES,
10
+ NS_DC,
11
+ NS_DCTERMS,
12
+ NS_RELATIONSHIPS,
13
+ NS_XSI,
14
+ REL_CORE_PROPERTIES
15
+ } from "./chunk-FMOIGA5T.js";
49
16
 
50
17
  // src/ooxml/writer.ts
51
18
  import JSZip from "jszip";
@@ -209,48 +176,6 @@ function groupRelationshipsBySource(pending) {
209
176
  }
210
177
 
211
178
  export {
212
- NS_RELATIONSHIPS,
213
- NS_CONTENT_TYPES,
214
- REL_OFFICE_DOCUMENT,
215
- REL_CORE_PROPERTIES,
216
- REL_EXTENDED_PROPERTIES,
217
- REL_STYLES,
218
- REL_NUMBERING,
219
- REL_FONT_TABLE,
220
- REL_SETTINGS,
221
- REL_HYPERLINK,
222
- REL_IMAGE,
223
- REL_FOOTNOTES,
224
- REL_THEME,
225
- NS_WML,
226
- NS_PML,
227
- NS_SML,
228
- NS_DRAWINGML,
229
- NS_WP_DRAWING,
230
- NS_PICTURE,
231
- NS_DC,
232
- NS_DCTERMS,
233
- NS_CORE_PROPERTIES,
234
- NS_XSI,
235
- NS_MC,
236
- NS_R,
237
- CONTENT_TYPE_RELATIONSHIPS,
238
- CONTENT_TYPE_CORE_PROPERTIES,
239
- CONTENT_TYPE_DOCX_DOCUMENT,
240
- CONTENT_TYPE_DOCX_STYLES,
241
- CONTENT_TYPE_DOCX_NUMBERING,
242
- CONTENT_TYPE_DOCX_SETTINGS,
243
- CONTENT_TYPE_DOCX_FONT_TABLE,
244
- CONTENT_TYPE_DOCX_FOOTNOTES,
245
- CONTENT_TYPE_PPTX_PRESENTATION,
246
- CONTENT_TYPE_PPTX_SLIDE,
247
- CONTENT_TYPE_PPTX_SLIDE_LAYOUT,
248
- CONTENT_TYPE_PPTX_SLIDE_MASTER,
249
- CONTENT_TYPE_PPTX_THEME,
250
- REL_SLIDE,
251
- REL_SLIDE_LAYOUT,
252
- REL_SLIDE_MASTER,
253
- CONTENT_TYPE_XLSX_WORKBOOK,
254
179
  createPackage
255
180
  };
256
- //# sourceMappingURL=chunk-7DEUGIOO.js.map
181
+ //# sourceMappingURL=chunk-QSE7EWE7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ooxml/writer.ts"],"sourcesContent":["/**\n * OOXML Package Writer\n *\n * Builds OOXML archives (.docx, .pptx, .xlsx) from parts.\n * Handles automatic generation of [Content_Types].xml and\n * _rels/*.rels files from the registered parts and relationships.\n */\n\nimport JSZip from 'jszip';\nimport type { CoreProperties, PackagePart, PendingRelationship, Relationship } from './types.js';\nimport {\n NS_CONTENT_TYPES,\n NS_RELATIONSHIPS,\n NS_CORE_PROPERTIES,\n NS_DC,\n NS_DCTERMS,\n NS_XSI,\n CONTENT_TYPE_RELATIONSHIPS,\n CONTENT_TYPE_CORE_PROPERTIES,\n REL_CORE_PROPERTIES,\n} from './namespaces.js';\nimport { xmlDeclaration, escapeXml } from './xmlUtils.js';\n\n// ============================================\n// Package Builder\n// ============================================\n\n/**\n * Mutable builder for constructing an OOXML package.\n *\n * Add parts, relationships, and core properties, then call `toBlob()`\n * or `toArrayBuffer()` to produce the final ZIP archive.\n *\n * @example\n * ```ts\n * const builder = createPackage();\n * builder.addPart('word/document.xml', documentXml, CONTENT_TYPE_DOCX_DOCUMENT);\n * builder.addRelationship('', {\n * id: 'rId1',\n * type: REL_OFFICE_DOCUMENT,\n * target: 'word/document.xml',\n * });\n * const blob = await builder.toBlob();\n * ```\n */\nexport interface OoxmlPackageBuilder {\n /**\n * Add an XML or text part to the package.\n *\n * @param path - Path within the archive (e.g., \"word/document.xml\")\n * @param content - XML string content\n * @param contentType - MIME content type for [Content_Types].xml\n */\n addPart(path: string, content: string, contentType: string): void;\n\n /**\n * Add a binary part to the package (e.g., an image).\n *\n * @param path - Path within the archive (e.g., \"word/media/image1.png\")\n * @param data - Binary content\n * @param contentType - MIME content type (e.g., \"image/png\")\n */\n addBinaryPart(path: string, data: ArrayBuffer | Uint8Array, contentType: string): void;\n\n /**\n * Register a relationship.\n *\n * @param sourcePart - The part this relationship belongs to (e.g., \"word/document.xml\").\n * Use \"\" (empty string) for root-level relationships (_rels/.rels).\n * @param rel - The relationship entry\n */\n addRelationship(sourcePart: string, rel: Relationship): void;\n\n /**\n * Set core document properties (docProps/core.xml).\n * Calling this multiple times overwrites previous values.\n */\n setCoreProperties(props: CoreProperties): void;\n\n /**\n * Assemble the final OOXML package as a Blob.\n * Generates [Content_Types].xml and all _rels/*.rels files automatically.\n */\n toBlob(): Promise<Blob>;\n\n /**\n * Assemble the final OOXML package as an ArrayBuffer.\n */\n toArrayBuffer(): Promise<ArrayBuffer>;\n}\n\n/**\n * Create a new OOXML package builder.\n */\nexport function createPackage(): OoxmlPackageBuilder {\n const parts: PackagePart[] = [];\n const relationships: PendingRelationship[] = [];\n let coreProps: CoreProperties | undefined;\n\n return {\n addPart(path, content, contentType) {\n parts.push({ path, content, contentType });\n },\n\n addBinaryPart(path, data, contentType) {\n parts.push({ path, binaryContent: data, contentType });\n },\n\n addRelationship(sourcePart, rel) {\n relationships.push({ sourcePart, relationship: rel });\n },\n\n setCoreProperties(props) {\n coreProps = props;\n },\n\n async toBlob() {\n const zip = assemble(parts, relationships, coreProps);\n return zip.generateAsync({ type: 'blob' });\n },\n\n async toArrayBuffer() {\n const zip = assemble(parts, relationships, coreProps);\n return zip.generateAsync({ type: 'arraybuffer' });\n },\n };\n}\n\n// ============================================\n// Assembly\n// ============================================\n\n/**\n * Assemble a JSZip archive from parts, relationships, and core properties.\n */\nfunction assemble(\n parts: PackagePart[],\n relationships: PendingRelationship[],\n coreProps?: CoreProperties,\n): JSZip {\n const zip = new JSZip();\n\n // Write content parts\n for (const part of parts) {\n if (part.content !== undefined) {\n zip.file(part.path, part.content);\n } else if (part.binaryContent !== undefined) {\n zip.file(part.path, part.binaryContent);\n }\n }\n\n // Add core properties if set\n if (coreProps) {\n const coreXml = buildCorePropertiesXml(coreProps);\n zip.file('docProps/core.xml', coreXml);\n\n // Add relationship to core properties\n relationships.push({\n sourcePart: '',\n relationship: {\n id: `rId${relationships.length + 100}`,\n type: REL_CORE_PROPERTIES,\n target: 'docProps/core.xml',\n },\n });\n }\n\n // Build and write [Content_Types].xml\n zip.file('[Content_Types].xml', buildContentTypesXml(parts, coreProps));\n\n // Build and write _rels/*.rels files\n const relsBySource = groupRelationshipsBySource(relationships);\n for (const [sourcePart, rels] of relsBySource) {\n const relsPath = sourcePart === '' ? '_rels/.rels' : buildRelsPath(sourcePart);\n zip.file(relsPath, buildRelationshipsXml(rels));\n }\n\n return zip;\n}\n\n// ============================================\n// [Content_Types].xml\n// ============================================\n\nfunction buildContentTypesXml(parts: PackagePart[], coreProps?: CoreProperties): string {\n const lines: string[] = [xmlDeclaration()];\n lines.push(`<Types xmlns=\"${NS_CONTENT_TYPES}\">`);\n\n // Default extension types\n const extensionTypes = new Map<string, string>();\n extensionTypes.set('rels', CONTENT_TYPE_RELATIONSHIPS);\n extensionTypes.set('xml', 'application/xml');\n\n // Collect extensions from binary parts (e.g., png, jpeg)\n for (const part of parts) {\n if (part.binaryContent !== undefined) {\n const ext = getExtension(part.path);\n if (ext && !extensionTypes.has(ext)) {\n extensionTypes.set(ext, part.contentType);\n }\n }\n }\n\n for (const [ext, ct] of extensionTypes) {\n lines.push(` <Default Extension=\"${escapeXml(ext)}\" ContentType=\"${escapeXml(ct)}\"/>`);\n }\n\n // Override entries for each XML part\n for (const part of parts) {\n if (part.content !== undefined) {\n lines.push(\n ` <Override PartName=\"/${escapeXml(part.path)}\" ContentType=\"${escapeXml(part.contentType)}\"/>`,\n );\n }\n }\n\n // Core properties override\n if (coreProps) {\n lines.push(\n ` <Override PartName=\"/docProps/core.xml\" ContentType=\"${CONTENT_TYPE_CORE_PROPERTIES}\"/>`,\n );\n }\n\n lines.push('</Types>');\n return lines.join('\\n');\n}\n\n// ============================================\n// Relationships XML\n// ============================================\n\nfunction buildRelationshipsXml(rels: Relationship[]): string {\n const lines: string[] = [xmlDeclaration()];\n lines.push(`<Relationships xmlns=\"${NS_RELATIONSHIPS}\">`);\n\n for (const rel of rels) {\n const attrs: string[] = [\n `Id=\"${escapeXml(rel.id)}\"`,\n `Type=\"${escapeXml(rel.type)}\"`,\n `Target=\"${escapeXml(rel.target)}\"`,\n ];\n if (rel.targetMode) {\n attrs.push(`TargetMode=\"${escapeXml(rel.targetMode)}\"`);\n }\n lines.push(` <Relationship ${attrs.join(' ')}/>`);\n }\n\n lines.push('</Relationships>');\n return lines.join('\\n');\n}\n\n// ============================================\n// Core Properties XML\n// ============================================\n\nfunction buildCorePropertiesXml(props: CoreProperties): string {\n const lines: string[] = [xmlDeclaration()];\n lines.push(\n `<cp:coreProperties` +\n ` xmlns:cp=\"${NS_CORE_PROPERTIES}\"` +\n ` xmlns:dc=\"${NS_DC}\"` +\n ` xmlns:dcterms=\"${NS_DCTERMS}\"` +\n ` xmlns:xsi=\"${NS_XSI}\">`,\n );\n\n if (props.title) lines.push(` <dc:title>${escapeXml(props.title)}</dc:title>`);\n if (props.subject) lines.push(` <dc:subject>${escapeXml(props.subject)}</dc:subject>`);\n if (props.creator) lines.push(` <dc:creator>${escapeXml(props.creator)}</dc:creator>`);\n if (props.description)\n lines.push(` <dc:description>${escapeXml(props.description)}</dc:description>`);\n if (props.keywords) lines.push(` <cp:keywords>${escapeXml(props.keywords)}</cp:keywords>`);\n if (props.lastModifiedBy)\n lines.push(` <cp:lastModifiedBy>${escapeXml(props.lastModifiedBy)}</cp:lastModifiedBy>`);\n if (props.revision) lines.push(` <cp:revision>${escapeXml(props.revision)}</cp:revision>`);\n if (props.created) {\n lines.push(\n ` <dcterms:created xsi:type=\"dcterms:W3CDTF\">${escapeXml(props.created)}</dcterms:created>`,\n );\n }\n if (props.modified) {\n lines.push(\n ` <dcterms:modified xsi:type=\"dcterms:W3CDTF\">${escapeXml(props.modified)}</dcterms:modified>`,\n );\n }\n\n lines.push('</cp:coreProperties>');\n return lines.join('\\n');\n}\n\n// ============================================\n// Helpers\n// ============================================\n\nfunction getExtension(path: string): string | undefined {\n const dot = path.lastIndexOf('.');\n if (dot === -1) return undefined;\n return path.substring(dot + 1).toLowerCase();\n}\n\nfunction buildRelsPath(partPath: string): string {\n const lastSlash = partPath.lastIndexOf('/');\n if (lastSlash === -1) {\n return `_rels/${partPath}.rels`;\n }\n const dir = partPath.substring(0, lastSlash);\n const file = partPath.substring(lastSlash + 1);\n return `${dir}/_rels/${file}.rels`;\n}\n\nfunction groupRelationshipsBySource(pending: PendingRelationship[]): Map<string, Relationship[]> {\n const grouped = new Map<string, Relationship[]>();\n for (const { sourcePart, relationship } of pending) {\n let list = grouped.get(sourcePart);\n if (!list) {\n list = [];\n grouped.set(sourcePart, list);\n }\n list.push(relationship);\n }\n return grouped;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAQA,OAAO,WAAW;AAsFX,SAAS,gBAAqC;AACnD,QAAM,QAAuB,CAAC;AAC9B,QAAM,gBAAuC,CAAC;AAC9C,MAAI;AAEJ,SAAO;AAAA,IACL,QAAQ,MAAM,SAAS,aAAa;AAClC,YAAM,KAAK,EAAE,MAAM,SAAS,YAAY,CAAC;AAAA,IAC3C;AAAA,IAEA,cAAc,MAAM,MAAM,aAAa;AACrC,YAAM,KAAK,EAAE,MAAM,eAAe,MAAM,YAAY,CAAC;AAAA,IACvD;AAAA,IAEA,gBAAgB,YAAY,KAAK;AAC/B,oBAAc,KAAK,EAAE,YAAY,cAAc,IAAI,CAAC;AAAA,IACtD;AAAA,IAEA,kBAAkB,OAAO;AACvB,kBAAY;AAAA,IACd;AAAA,IAEA,MAAM,SAAS;AACb,YAAM,MAAM,SAAS,OAAO,eAAe,SAAS;AACpD,aAAO,IAAI,cAAc,EAAE,MAAM,OAAO,CAAC;AAAA,IAC3C;AAAA,IAEA,MAAM,gBAAgB;AACpB,YAAM,MAAM,SAAS,OAAO,eAAe,SAAS;AACpD,aAAO,IAAI,cAAc,EAAE,MAAM,cAAc,CAAC;AAAA,IAClD;AAAA,EACF;AACF;AASA,SAAS,SACP,OACA,eACA,WACO;AACP,QAAM,MAAM,IAAI,MAAM;AAGtB,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,YAAY,QAAW;AAC9B,UAAI,KAAK,KAAK,MAAM,KAAK,OAAO;AAAA,IAClC,WAAW,KAAK,kBAAkB,QAAW;AAC3C,UAAI,KAAK,KAAK,MAAM,KAAK,aAAa;AAAA,IACxC;AAAA,EACF;AAGA,MAAI,WAAW;AACb,UAAM,UAAU,uBAAuB,SAAS;AAChD,QAAI,KAAK,qBAAqB,OAAO;AAGrC,kBAAc,KAAK;AAAA,MACjB,YAAY;AAAA,MACZ,cAAc;AAAA,QACZ,IAAI,MAAM,cAAc,SAAS,GAAG;AAAA,QACpC,MAAM;AAAA,QACN,QAAQ;AAAA,MACV;AAAA,IACF,CAAC;AAAA,EACH;AAGA,MAAI,KAAK,uBAAuB,qBAAqB,OAAO,SAAS,CAAC;AAGtE,QAAM,eAAe,2BAA2B,aAAa;AAC7D,aAAW,CAAC,YAAY,IAAI,KAAK,cAAc;AAC7C,UAAM,WAAW,eAAe,KAAK,gBAAgB,cAAc,UAAU;AAC7E,QAAI,KAAK,UAAU,sBAAsB,IAAI,CAAC;AAAA,EAChD;AAEA,SAAO;AACT;AAMA,SAAS,qBAAqB,OAAsB,WAAoC;AACtF,QAAM,QAAkB,CAAC,eAAe,CAAC;AACzC,QAAM,KAAK,iBAAiB,gBAAgB,IAAI;AAGhD,QAAM,iBAAiB,oBAAI,IAAoB;AAC/C,iBAAe,IAAI,QAAQ,0BAA0B;AACrD,iBAAe,IAAI,OAAO,iBAAiB;AAG3C,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,kBAAkB,QAAW;AACpC,YAAM,MAAM,aAAa,KAAK,IAAI;AAClC,UAAI,OAAO,CAAC,eAAe,IAAI,GAAG,GAAG;AACnC,uBAAe,IAAI,KAAK,KAAK,WAAW;AAAA,MAC1C;AAAA,IACF;AAAA,EACF;AAEA,aAAW,CAAC,KAAK,EAAE,KAAK,gBAAgB;AACtC,UAAM,KAAK,yBAAyB,UAAU,GAAG,CAAC,kBAAkB,UAAU,EAAE,CAAC,KAAK;AAAA,EACxF;AAGA,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,YAAY,QAAW;AAC9B,YAAM;AAAA,QACJ,0BAA0B,UAAU,KAAK,IAAI,CAAC,kBAAkB,UAAU,KAAK,WAAW,CAAC;AAAA,MAC7F;AAAA,IACF;AAAA,EACF;AAGA,MAAI,WAAW;AACb,UAAM;AAAA,MACJ,0DAA0D,4BAA4B;AAAA,IACxF;AAAA,EACF;AAEA,QAAM,KAAK,UAAU;AACrB,SAAO,MAAM,KAAK,IAAI;AACxB;AAMA,SAAS,sBAAsB,MAA8B;AAC3D,QAAM,QAAkB,CAAC,eAAe,CAAC;AACzC,QAAM,KAAK,yBAAyB,gBAAgB,IAAI;AAExD,aAAW,OAAO,MAAM;AACtB,UAAM,QAAkB;AAAA,MACtB,OAAO,UAAU,IAAI,EAAE,CAAC;AAAA,MACxB,SAAS,UAAU,IAAI,IAAI,CAAC;AAAA,MAC5B,WAAW,UAAU,IAAI,MAAM,CAAC;AAAA,IAClC;AACA,QAAI,IAAI,YAAY;AAClB,YAAM,KAAK,eAAe,UAAU,IAAI,UAAU,CAAC,GAAG;AAAA,IACxD;AACA,UAAM,KAAK,mBAAmB,MAAM,KAAK,GAAG,CAAC,IAAI;AAAA,EACnD;AAEA,QAAM,KAAK,kBAAkB;AAC7B,SAAO,MAAM,KAAK,IAAI;AACxB;AAMA,SAAS,uBAAuB,OAA+B;AAC7D,QAAM,QAAkB,CAAC,eAAe,CAAC;AACzC,QAAM;AAAA,IACJ,gCACgB,kBAAkB,eAClB,KAAK,oBACA,UAAU,gBACd,MAAM;AAAA,EACzB;AAEA,MAAI,MAAM,MAAO,OAAM,KAAK,eAAe,UAAU,MAAM,KAAK,CAAC,aAAa;AAC9E,MAAI,MAAM,QAAS,OAAM,KAAK,iBAAiB,UAAU,MAAM,OAAO,CAAC,eAAe;AACtF,MAAI,MAAM,QAAS,OAAM,KAAK,iBAAiB,UAAU,MAAM,OAAO,CAAC,eAAe;AACtF,MAAI,MAAM;AACR,UAAM,KAAK,qBAAqB,UAAU,MAAM,WAAW,CAAC,mBAAmB;AACjF,MAAI,MAAM,SAAU,OAAM,KAAK,kBAAkB,UAAU,MAAM,QAAQ,CAAC,gBAAgB;AAC1F,MAAI,MAAM;AACR,UAAM,KAAK,wBAAwB,UAAU,MAAM,cAAc,CAAC,sBAAsB;AAC1F,MAAI,MAAM,SAAU,OAAM,KAAK,kBAAkB,UAAU,MAAM,QAAQ,CAAC,gBAAgB;AAC1F,MAAI,MAAM,SAAS;AACjB,UAAM;AAAA,MACJ,gDAAgD,UAAU,MAAM,OAAO,CAAC;AAAA,IAC1E;AAAA,EACF;AACA,MAAI,MAAM,UAAU;AAClB,UAAM;AAAA,MACJ,iDAAiD,UAAU,MAAM,QAAQ,CAAC;AAAA,IAC5E;AAAA,EACF;AAEA,QAAM,KAAK,sBAAsB;AACjC,SAAO,MAAM,KAAK,IAAI;AACxB;AAMA,SAAS,aAAa,MAAkC;AACtD,QAAM,MAAM,KAAK,YAAY,GAAG;AAChC,MAAI,QAAQ,GAAI,QAAO;AACvB,SAAO,KAAK,UAAU,MAAM,CAAC,EAAE,YAAY;AAC7C;AAEA,SAAS,cAAc,UAA0B;AAC/C,QAAM,YAAY,SAAS,YAAY,GAAG;AAC1C,MAAI,cAAc,IAAI;AACpB,WAAO,SAAS,QAAQ;AAAA,EAC1B;AACA,QAAM,MAAM,SAAS,UAAU,GAAG,SAAS;AAC3C,QAAM,OAAO,SAAS,UAAU,YAAY,CAAC;AAC7C,SAAO,GAAG,GAAG,UAAU,IAAI;AAC7B;AAEA,SAAS,2BAA2B,SAA6D;AAC/F,QAAM,UAAU,oBAAI,IAA4B;AAChD,aAAW,EAAE,YAAY,aAAa,KAAK,SAAS;AAClD,QAAI,OAAO,QAAQ,IAAI,UAAU;AACjC,QAAI,CAAC,MAAM;AACT,aAAO,CAAC;AACR,cAAQ,IAAI,YAAY,IAAI;AAAA,IAC9B;AACA,SAAK,KAAK,YAAY;AAAA,EACxB;AACA,SAAO;AACT;","names":[]}
@@ -1,3 +1,5 @@
1
+ import { ContentContainer, MemoryContentContainer } from '@bendyline/squisq/storage';
2
+
1
3
  /**
2
4
  * Container ZIP serialization — convert between ContentContainer and ZIP archives.
3
5
  *
@@ -10,8 +12,7 @@
10
12
  * audio/narration.mp3
11
13
  * timing.json
12
14
  */
13
- import type { ContentContainer } from '@bendyline/squisq/storage';
14
- import { MemoryContentContainer } from '@bendyline/squisq/storage';
15
+
15
16
  /**
16
17
  * Serialize a ContentContainer to a ZIP blob.
17
18
  *
@@ -21,7 +22,7 @@ import { MemoryContentContainer } from '@bendyline/squisq/storage';
21
22
  * @param container — The container to serialize
22
23
  * @returns A Blob containing the ZIP archive
23
24
  */
24
- export declare function containerToZip(container: ContentContainer): Promise<Blob>;
25
+ declare function containerToZip(container: ContentContainer): Promise<Blob>;
25
26
  /**
26
27
  * Deserialize a ZIP archive into a MemoryContentContainer.
27
28
  *
@@ -32,5 +33,6 @@ export declare function containerToZip(container: ContentContainer): Promise<Blo
32
33
  * @param zipData — The ZIP archive as ArrayBuffer, Uint8Array, or Blob
33
34
  * @returns A MemoryContentContainer populated with the ZIP's contents
34
35
  */
35
- export declare function zipToContainer(zipData: ArrayBuffer | Uint8Array | Blob): Promise<MemoryContentContainer>;
36
- //# sourceMappingURL=index.d.ts.map
36
+ declare function zipToContainer(zipData: ArrayBuffer | Uint8Array | Blob): Promise<MemoryContentContainer>;
37
+
38
+ export { containerToZip, zipToContainer };
@@ -1,74 +1,43 @@
1
- /**
2
- * Container ZIP serialization — convert between ContentContainer and ZIP archives.
3
- *
4
- * Uses JSZip (already a formats dependency) to serialize a ContentContainer to
5
- * a ZIP blob and to deserialize a ZIP blob into a MemoryContentContainer.
6
- *
7
- * ZIP structure mirrors the container's flat path hierarchy directly:
8
- * index.md
9
- * images/hero.jpg
10
- * audio/narration.mp3
11
- * timing.json
12
- */
13
- import JSZip from 'jszip';
14
- import { MemoryContentContainer } from '@bendyline/squisq/storage';
15
- /**
16
- * Serialize a ContentContainer to a ZIP blob.
17
- *
18
- * All files in the container are written to the ZIP archive preserving
19
- * their path structure. The resulting blob can be saved as a .zip file.
20
- *
21
- * @param container — The container to serialize
22
- * @returns A Blob containing the ZIP archive
23
- */
24
- export async function containerToZip(container) {
25
- const zip = new JSZip();
26
- const entries = await container.listFiles();
27
- for (const entry of entries) {
28
- const data = await container.readFile(entry.path);
29
- if (data) {
30
- zip.file(entry.path, new Uint8Array(data));
31
- }
1
+ // src/container/index.ts
2
+ import JSZip from "jszip";
3
+ import { MemoryContentContainer } from "@bendyline/squisq/storage";
4
+ async function containerToZip(container) {
5
+ const zip = new JSZip();
6
+ const entries = await container.listFiles();
7
+ for (const entry of entries) {
8
+ const data = await container.readFile(entry.path);
9
+ if (data) {
10
+ zip.file(entry.path, new Uint8Array(data));
32
11
  }
33
- return zip.generateAsync({
34
- type: 'blob',
35
- compression: 'DEFLATE',
36
- compressionOptions: { level: 6 },
37
- });
12
+ }
13
+ return zip.generateAsync({
14
+ type: "blob",
15
+ compression: "DEFLATE",
16
+ compressionOptions: { level: 6 }
17
+ });
38
18
  }
39
- /**
40
- * Deserialize a ZIP archive into a MemoryContentContainer.
41
- *
42
- * Reads all files from the ZIP and writes them into a new MemoryContentContainer.
43
- * Directory entries are skipped. The resulting container can be used immediately
44
- * for rendering, editing, or saving to persistent storage.
45
- *
46
- * @param zipData — The ZIP archive as ArrayBuffer, Uint8Array, or Blob
47
- * @returns A MemoryContentContainer populated with the ZIP's contents
48
- */
49
- export async function zipToContainer(zipData) {
50
- const zip = await JSZip.loadAsync(zipData);
51
- const container = new MemoryContentContainer();
52
- const filePromises = [];
53
- zip.forEach((relativePath, zipEntry) => {
54
- // Skip directories
55
- if (zipEntry.dir)
56
- return;
57
- // Strip leading slash if present
58
- const entryPath = relativePath.startsWith('/') ? relativePath.slice(1) : relativePath;
59
- if (!entryPath)
60
- return;
61
- // Path-traversal protection: reject absolute paths, backslashes, and .. segments
62
- if (entryPath.startsWith('/') ||
63
- entryPath.includes('\\') ||
64
- entryPath.split('/').some((seg) => seg === '..')) {
65
- return;
66
- }
67
- filePromises.push(zipEntry.async('arraybuffer').then((data) => {
68
- return container.writeFile(entryPath, data);
69
- }));
70
- });
71
- await Promise.all(filePromises);
72
- return container;
19
+ async function zipToContainer(zipData) {
20
+ const zip = await JSZip.loadAsync(zipData);
21
+ const container = new MemoryContentContainer();
22
+ const filePromises = [];
23
+ zip.forEach((relativePath, zipEntry) => {
24
+ if (zipEntry.dir) return;
25
+ const entryPath = relativePath.startsWith("/") ? relativePath.slice(1) : relativePath;
26
+ if (!entryPath) return;
27
+ if (entryPath.startsWith("/") || entryPath.includes("\\") || entryPath.split("/").some((seg) => seg === "..")) {
28
+ return;
29
+ }
30
+ filePromises.push(
31
+ zipEntry.async("arraybuffer").then((data) => {
32
+ return container.writeFile(entryPath, data);
33
+ })
34
+ );
35
+ });
36
+ await Promise.all(filePromises);
37
+ return container;
73
38
  }
39
+ export {
40
+ containerToZip,
41
+ zipToContainer
42
+ };
74
43
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/container/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAEnE;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,SAA2B;IAC9D,MAAM,GAAG,GAAG,IAAI,KAAK,EAAE,CAAC;IACxB,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,SAAS,EAAE,CAAC;IAE5C,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAClD,IAAI,IAAI,EAAE,CAAC;YACT,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IAED,OAAO,GAAG,CAAC,aAAa,CAAC;QACvB,IAAI,EAAE,MAAM;QACZ,WAAW,EAAE,SAAS;QACtB,kBAAkB,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE;KACjC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAAwC;IAExC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAC3C,MAAM,SAAS,GAAG,IAAI,sBAAsB,EAAE,CAAC;IAE/C,MAAM,YAAY,GAAoB,EAAE,CAAC;IAEzC,GAAG,CAAC,OAAO,CAAC,CAAC,YAAY,EAAE,QAAQ,EAAE,EAAE;QACrC,mBAAmB;QACnB,IAAI,QAAQ,CAAC,GAAG;YAAE,OAAO;QAEzB,iCAAiC;QACjC,MAAM,SAAS,GAAG,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;QACtF,IAAI,CAAC,SAAS;YAAE,OAAO;QAEvB,iFAAiF;QACjF,IACE,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC;YACzB,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC;YACxB,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,KAAK,IAAI,CAAC,EAChD,CAAC;YACD,OAAO;QACT,CAAC;QAED,YAAY,CAAC,IAAI,CACf,QAAQ,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;YAC1C,OAAO,SAAS,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QAC9C,CAAC,CAAC,CACH,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAChC,OAAO,SAAS,CAAC;AACnB,CAAC"}
1
+ {"version":3,"sources":["../../src/container/index.ts"],"sourcesContent":["/**\n * Container ZIP serialization — convert between ContentContainer and ZIP archives.\n *\n * Uses JSZip (already a formats dependency) to serialize a ContentContainer to\n * a ZIP blob and to deserialize a ZIP blob into a MemoryContentContainer.\n *\n * ZIP structure mirrors the container's flat path hierarchy directly:\n * index.md\n * images/hero.jpg\n * audio/narration.mp3\n * timing.json\n */\n\nimport JSZip from 'jszip';\nimport type { ContentContainer } from '@bendyline/squisq/storage';\nimport { MemoryContentContainer } from '@bendyline/squisq/storage';\n\n/**\n * Serialize a ContentContainer to a ZIP blob.\n *\n * All files in the container are written to the ZIP archive preserving\n * their path structure. The resulting blob can be saved as a .zip file.\n *\n * @param container — The container to serialize\n * @returns A Blob containing the ZIP archive\n */\nexport async function containerToZip(container: ContentContainer): Promise<Blob> {\n const zip = new JSZip();\n const entries = await container.listFiles();\n\n for (const entry of entries) {\n const data = await container.readFile(entry.path);\n if (data) {\n zip.file(entry.path, new Uint8Array(data));\n }\n }\n\n return zip.generateAsync({\n type: 'blob',\n compression: 'DEFLATE',\n compressionOptions: { level: 6 },\n });\n}\n\n/**\n * Deserialize a ZIP archive into a MemoryContentContainer.\n *\n * Reads all files from the ZIP and writes them into a new MemoryContentContainer.\n * Directory entries are skipped. The resulting container can be used immediately\n * for rendering, editing, or saving to persistent storage.\n *\n * @param zipData — The ZIP archive as ArrayBuffer, Uint8Array, or Blob\n * @returns A MemoryContentContainer populated with the ZIP's contents\n */\nexport async function zipToContainer(\n zipData: ArrayBuffer | Uint8Array | Blob,\n): Promise<MemoryContentContainer> {\n const zip = await JSZip.loadAsync(zipData);\n const container = new MemoryContentContainer();\n\n const filePromises: Promise<void>[] = [];\n\n zip.forEach((relativePath, zipEntry) => {\n // Skip directories\n if (zipEntry.dir) return;\n\n // Strip leading slash if present\n const entryPath = relativePath.startsWith('/') ? relativePath.slice(1) : relativePath;\n if (!entryPath) return;\n\n // Path-traversal protection: reject absolute paths, backslashes, and .. segments\n if (\n entryPath.startsWith('/') ||\n entryPath.includes('\\\\') ||\n entryPath.split('/').some((seg) => seg === '..')\n ) {\n return;\n }\n\n filePromises.push(\n zipEntry.async('arraybuffer').then((data) => {\n return container.writeFile(entryPath, data);\n }),\n );\n });\n\n await Promise.all(filePromises);\n return container;\n}\n"],"mappings":";AAaA,OAAO,WAAW;AAElB,SAAS,8BAA8B;AAWvC,eAAsB,eAAe,WAA4C;AAC/E,QAAM,MAAM,IAAI,MAAM;AACtB,QAAM,UAAU,MAAM,UAAU,UAAU;AAE1C,aAAW,SAAS,SAAS;AAC3B,UAAM,OAAO,MAAM,UAAU,SAAS,MAAM,IAAI;AAChD,QAAI,MAAM;AACR,UAAI,KAAK,MAAM,MAAM,IAAI,WAAW,IAAI,CAAC;AAAA,IAC3C;AAAA,EACF;AAEA,SAAO,IAAI,cAAc;AAAA,IACvB,MAAM;AAAA,IACN,aAAa;AAAA,IACb,oBAAoB,EAAE,OAAO,EAAE;AAAA,EACjC,CAAC;AACH;AAYA,eAAsB,eACpB,SACiC;AACjC,QAAM,MAAM,MAAM,MAAM,UAAU,OAAO;AACzC,QAAM,YAAY,IAAI,uBAAuB;AAE7C,QAAM,eAAgC,CAAC;AAEvC,MAAI,QAAQ,CAAC,cAAc,aAAa;AAEtC,QAAI,SAAS,IAAK;AAGlB,UAAM,YAAY,aAAa,WAAW,GAAG,IAAI,aAAa,MAAM,CAAC,IAAI;AACzE,QAAI,CAAC,UAAW;AAGhB,QACE,UAAU,WAAW,GAAG,KACxB,UAAU,SAAS,IAAI,KACvB,UAAU,MAAM,GAAG,EAAE,KAAK,CAAC,QAAQ,QAAQ,IAAI,GAC/C;AACA;AAAA,IACF;AAEA,iBAAa;AAAA,MACX,SAAS,MAAM,aAAa,EAAE,KAAK,CAAC,SAAS;AAC3C,eAAO,UAAU,UAAU,WAAW,IAAI;AAAA,MAC5C,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AAED,QAAM,QAAQ,IAAI,YAAY;AAC9B,SAAO;AACT;","names":[]}
@@ -0,0 +1,37 @@
1
+ import { MarkdownDocument } from '@bendyline/squisq/markdown';
2
+ import { Doc } from '@bendyline/squisq/schemas';
3
+
4
+ /**
5
+ * @bendyline/squisq-formats CSV Module
6
+ *
7
+ * Bridges CSV ↔ the squisq markdown table model. CSV isn't OOXML, so this
8
+ * module is self-contained (no jszip / DOMParser): a small RFC-4180 parser on
9
+ * the import side and a serializer on the export side. The first row is treated
10
+ * as the table header by default.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * import { csvToMarkdownDoc, markdownDocToCsv } from '@bendyline/squisq-formats/csv';
15
+ * ```
16
+ */
17
+
18
+ interface CsvImportOptions {
19
+ /** Field delimiter. Default `,`. */
20
+ delimiter?: string;
21
+ /** Treat the first row as a header row. Default true. */
22
+ hasHeader?: boolean;
23
+ }
24
+ interface CsvExportOptions {
25
+ /** Field delimiter. Default `,`. */
26
+ delimiter?: string;
27
+ }
28
+ /** Parse CSV text into a grid of string cells (RFC 4180: quotes, escaped quotes). */
29
+ declare function parseCsv(text: string, delimiter?: string): string[][];
30
+ /** Convert CSV to a MarkdownDocument containing a single table. */
31
+ declare function csvToMarkdownDoc(data: ArrayBuffer | Blob | string, options?: CsvImportOptions): Promise<MarkdownDocument>;
32
+ /** Convert CSV to a squisq Doc. */
33
+ declare function csvToDoc(data: ArrayBuffer | Blob | string, options?: CsvImportOptions): Promise<Doc>;
34
+ /** Serialize the first table in a MarkdownDocument to CSV text. */
35
+ declare function markdownDocToCsv(doc: MarkdownDocument, options?: CsvExportOptions): string;
36
+
37
+ export { type CsvExportOptions, type CsvImportOptions, csvToDoc, csvToMarkdownDoc, markdownDocToCsv, parseCsv };
@@ -0,0 +1,13 @@
1
+ import {
2
+ csvToDoc,
3
+ csvToMarkdownDoc,
4
+ markdownDocToCsv,
5
+ parseCsv
6
+ } from "../chunk-JBNVE2GV.js";
7
+ export {
8
+ csvToDoc,
9
+ csvToMarkdownDoc,
10
+ markdownDocToCsv,
11
+ parseCsv
12
+ };
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}