@bendyline/squisq-formats 2.1.0 → 2.2.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 (195) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE.md +20 -0
  3. package/README.md +1 -1
  4. package/dist/{chunk-NNHKUXKA.js → chunk-26ISNJ7Y.js} +85 -65
  5. package/dist/{chunk-NKAJPJ4G.js → chunk-2JJ5RFDZ.js} +0 -1
  6. package/dist/{chunk-WQSHGBLN.js → chunk-3NKXBZSR.js} +193 -42
  7. package/dist/{chunk-KURGXM4I.js → chunk-4V3KCHAP.js} +3 -4
  8. package/dist/{chunk-MLX2BOJC.js → chunk-6RQOV3B3.js} +1 -2
  9. package/dist/{chunk-EW54IRRS.js → chunk-6S6GU3ZG.js} +5 -6
  10. package/dist/{chunk-FE6OJV6O.js → chunk-7AWFHP5U.js} +1 -1
  11. package/dist/{chunk-RFAPOKHJ.js → chunk-AD2WT564.js} +59 -9
  12. package/dist/{chunk-O3GVVND4.js → chunk-AONELFLA.js} +0 -1
  13. package/dist/{chunk-SC67HYQJ.js → chunk-EJTNGKEA.js} +5 -8
  14. package/dist/chunk-GX7RAUME.js +121 -0
  15. package/dist/{chunk-SSUPBUF5.js → chunk-IIQYS2YH.js} +0 -1
  16. package/dist/{chunk-RLU7UFYU.js → chunk-IPN56VLW.js} +83 -58
  17. package/dist/{chunk-DTDF6QDP.js → chunk-JE6LSIHE.js} +81 -20
  18. package/dist/{chunk-U4MRIFKL.js → chunk-JU2RHXUB.js} +0 -1
  19. package/dist/{chunk-4VUWTSGM.js → chunk-K6XRMVPW.js} +64 -31
  20. package/dist/{chunk-ODL3SSPT.js → chunk-KXOZMWBS.js} +0 -1
  21. package/dist/chunk-OGS5VCGJ.js +446 -0
  22. package/dist/{chunk-GVS2XXV6.js → chunk-PJXJI2LY.js} +449 -57
  23. package/dist/{chunk-74GO3FVS.js → chunk-PU7REGWV.js} +5 -8
  24. package/dist/{chunk-PN52A5AA.js → chunk-SBUW7NHR.js} +0 -1
  25. package/dist/{chunk-QFLDYKCR.js → chunk-TAAENIRB.js} +5 -8
  26. package/dist/{chunk-7ARKUCQT.js → chunk-X2DEAXNK.js} +54 -2
  27. package/dist/container/index.js +1 -2
  28. package/dist/csv/index.d.ts +27 -2
  29. package/dist/csv/index.js +1 -2
  30. package/dist/docx/index.d.ts +5 -1
  31. package/dist/docx/index.js +9 -11
  32. package/dist/epub/index.d.ts +2 -0
  33. package/dist/epub/index.js +5 -6
  34. package/dist/{export-D2NkylDT.d.ts → export-D9msROJS.d.ts} +18 -6
  35. package/dist/extract-MN7LA3NL.js +13 -0
  36. package/dist/html/index.d.ts +11 -4
  37. package/dist/html/index.js +3 -4
  38. package/dist/images-ESPQKVTW.js +6 -0
  39. package/dist/{import-K8mfc0fz.d.ts → import-C3htUTss.d.ts} +5 -1
  40. package/dist/{import-DTkDxHmZ.d.ts → import-C8whCC7_.d.ts} +6 -0
  41. package/dist/index.d.ts +7 -7
  42. package/dist/index.js +28 -26
  43. package/dist/infer/index.d.ts +3 -3
  44. package/dist/infer/index.js +7 -9
  45. package/dist/{layouts-BHrgZ5FS.d.ts → layouts-CTdPlB-u.d.ts} +1 -1
  46. package/dist/layouts-DRWZGSPD.js +10 -0
  47. package/dist/{mapTheme-IR27S6IV.js → mapTheme-4TWH25FT.js} +1 -2
  48. package/dist/ooxml/index.d.ts +3 -3
  49. package/dist/ooxml/index.js +14 -13
  50. package/dist/pdf/index.d.ts +18 -0
  51. package/dist/pdf/index.js +2 -3
  52. package/dist/pptx/index.d.ts +4 -4
  53. package/dist/pptx/index.js +11 -13
  54. package/dist/{reader-B9L8Ucbj.d.ts → reader-B_m1aKZC.d.ts} +30 -1
  55. package/dist/registry/index.d.ts +21 -5
  56. package/dist/registry/index.js +9 -6
  57. package/dist/{themeReader-DJKErl_j.d.ts → themeReader-DCtwC83Q.d.ts} +1 -1
  58. package/dist/xlsx/index.d.ts +3 -3
  59. package/dist/xlsx/index.js +6 -7
  60. package/package.json +6 -3
  61. package/dist/chunk-4VUWTSGM.js.map +0 -1
  62. package/dist/chunk-6M7Z25LA.js +0 -46
  63. package/dist/chunk-6M7Z25LA.js.map +0 -1
  64. package/dist/chunk-74GO3FVS.js.map +0 -1
  65. package/dist/chunk-7ARKUCQT.js.map +0 -1
  66. package/dist/chunk-DTDF6QDP.js.map +0 -1
  67. package/dist/chunk-EW54IRRS.js.map +0 -1
  68. package/dist/chunk-FE6OJV6O.js.map +0 -1
  69. package/dist/chunk-GVS2XXV6.js.map +0 -1
  70. package/dist/chunk-KURGXM4I.js.map +0 -1
  71. package/dist/chunk-MLX2BOJC.js.map +0 -1
  72. package/dist/chunk-NKAJPJ4G.js.map +0 -1
  73. package/dist/chunk-NNHKUXKA.js.map +0 -1
  74. package/dist/chunk-O3GVVND4.js.map +0 -1
  75. package/dist/chunk-ODL3SSPT.js.map +0 -1
  76. package/dist/chunk-PN52A5AA.js.map +0 -1
  77. package/dist/chunk-QFLDYKCR.js.map +0 -1
  78. package/dist/chunk-RFAPOKHJ.js.map +0 -1
  79. package/dist/chunk-RLU7UFYU.js.map +0 -1
  80. package/dist/chunk-SC67HYQJ.js.map +0 -1
  81. package/dist/chunk-SSUPBUF5.js.map +0 -1
  82. package/dist/chunk-U4MRIFKL.js.map +0 -1
  83. package/dist/chunk-UGYF5AZE.js +0 -275
  84. package/dist/chunk-UGYF5AZE.js.map +0 -1
  85. package/dist/chunk-WQSHGBLN.js.map +0 -1
  86. package/dist/chunk-YRT7GQ5Y.js +0 -28
  87. package/dist/chunk-YRT7GQ5Y.js.map +0 -1
  88. package/dist/container/index.js.map +0 -1
  89. package/dist/csv/index.js.map +0 -1
  90. package/dist/docx/index.js.map +0 -1
  91. package/dist/epub/index.js.map +0 -1
  92. package/dist/extract-OJ7ZQV6P.js +0 -15
  93. package/dist/extract-OJ7ZQV6P.js.map +0 -1
  94. package/dist/html/index.js.map +0 -1
  95. package/dist/images-7FBWPKE3.js +0 -7
  96. package/dist/images-7FBWPKE3.js.map +0 -1
  97. package/dist/index.js.map +0 -1
  98. package/dist/infer/index.js.map +0 -1
  99. package/dist/layouts-5VDIRPIJ.js +0 -12
  100. package/dist/layouts-5VDIRPIJ.js.map +0 -1
  101. package/dist/mapTheme-IR27S6IV.js.map +0 -1
  102. package/dist/ooxml/index.js.map +0 -1
  103. package/dist/pdf/index.js.map +0 -1
  104. package/dist/pptx/index.js.map +0 -1
  105. package/dist/registry/index.js.map +0 -1
  106. package/dist/xlsx/index.js.map +0 -1
  107. package/src/__tests__/container.test.ts +0 -230
  108. package/src/__tests__/convert.test.ts +0 -495
  109. package/src/__tests__/csvImport.test.ts +0 -84
  110. package/src/__tests__/docxExport.test.ts +0 -491
  111. package/src/__tests__/docxImport.test.ts +0 -531
  112. package/src/__tests__/epub.test.ts +0 -649
  113. package/src/__tests__/exportThemeReconciliation.test.ts +0 -87
  114. package/src/__tests__/formatRegistry.test.ts +0 -174
  115. package/src/__tests__/html.test.ts +0 -439
  116. package/src/__tests__/htmlImport.test.ts +0 -57
  117. package/src/__tests__/inferTheme.test.ts +0 -135
  118. package/src/__tests__/lossyWarnings.test.ts +0 -146
  119. package/src/__tests__/ooxml.test.ts +0 -271
  120. package/src/__tests__/ooxmlCancellation.test.ts +0 -113
  121. package/src/__tests__/ooxmlThemeReader.test.ts +0 -92
  122. package/src/__tests__/pdfExport.test.ts +0 -322
  123. package/src/__tests__/pdfImport.test.ts +0 -384
  124. package/src/__tests__/plainHtml.test.ts +0 -417
  125. package/src/__tests__/plainHtmlBundle.test.ts +0 -253
  126. package/src/__tests__/pptxExport.test.ts +0 -138
  127. package/src/__tests__/pptxImport.test.ts +0 -145
  128. package/src/__tests__/pptxInferFixtures.ts +0 -314
  129. package/src/__tests__/pptxLayoutInfer.test.ts +0 -395
  130. package/src/__tests__/roundTrip.test.ts +0 -201
  131. package/src/__tests__/roundTripAssets.test.ts +0 -50
  132. package/src/__tests__/roundTripMatrix.fixtures.ts +0 -86
  133. package/src/__tests__/roundTripMatrix.helpers.ts +0 -154
  134. package/src/__tests__/roundTripMatrix.test.ts +0 -142
  135. package/src/__tests__/sharedContainer.test.ts +0 -41
  136. package/src/__tests__/sharedImages.test.ts +0 -61
  137. package/src/__tests__/xlsxExport.test.ts +0 -164
  138. package/src/__tests__/xlsxImport.test.ts +0 -80
  139. package/src/__tests__/zipSafety.test.ts +0 -317
  140. package/src/container/index.ts +0 -94
  141. package/src/csv/index.ts +0 -188
  142. package/src/docx/export.ts +0 -1375
  143. package/src/docx/import.ts +0 -1250
  144. package/src/docx/index.ts +0 -26
  145. package/src/docx/styles.ts +0 -145
  146. package/src/epub/export.ts +0 -968
  147. package/src/epub/index.ts +0 -20
  148. package/src/html/docsHtmlBundle.ts +0 -373
  149. package/src/html/htmlTemplate.ts +0 -385
  150. package/src/html/imageUtils.ts +0 -61
  151. package/src/html/import.ts +0 -297
  152. package/src/html/index.ts +0 -212
  153. package/src/html/plainHtml.ts +0 -790
  154. package/src/html/plainHtmlBundle.ts +0 -421
  155. package/src/index.ts +0 -109
  156. package/src/infer/extract.ts +0 -127
  157. package/src/infer/index.ts +0 -199
  158. package/src/infer/mapTheme.ts +0 -176
  159. package/src/infer/types.ts +0 -27
  160. package/src/ooxml/index.ts +0 -111
  161. package/src/ooxml/namespaces.ts +0 -217
  162. package/src/ooxml/readUtils.ts +0 -44
  163. package/src/ooxml/reader.ts +0 -318
  164. package/src/ooxml/themeReader.ts +0 -197
  165. package/src/ooxml/types.ts +0 -103
  166. package/src/ooxml/writer.ts +0 -339
  167. package/src/ooxml/xmlUtils.ts +0 -123
  168. package/src/pdf/export.ts +0 -1084
  169. package/src/pdf/import.ts +0 -1164
  170. package/src/pdf/index.ts +0 -29
  171. package/src/pdf/styles.ts +0 -180
  172. package/src/pptx/export.ts +0 -1184
  173. package/src/pptx/import.ts +0 -455
  174. package/src/pptx/index.ts +0 -52
  175. package/src/pptx/layouts.ts +0 -1222
  176. package/src/pptx/styles.ts +0 -96
  177. package/src/pptx/templates.ts +0 -187
  178. package/src/registry/convert.ts +0 -433
  179. package/src/registry/defaultFormats.ts +0 -413
  180. package/src/registry/errors.ts +0 -46
  181. package/src/registry/index.ts +0 -43
  182. package/src/registry/registry.ts +0 -48
  183. package/src/registry/types.ts +0 -170
  184. package/src/shared/boundedZipArchive.ts +0 -383
  185. package/src/shared/container.ts +0 -28
  186. package/src/shared/fidelity.ts +0 -130
  187. package/src/shared/images.ts +0 -44
  188. package/src/shared/inlineRuns.ts +0 -99
  189. package/src/shared/text.ts +0 -41
  190. package/src/shared/zipEntryCount.ts +0 -151
  191. package/src/shared/zipLimits.ts +0 -296
  192. package/src/shared/zipSafety.ts +0 -19
  193. package/src/xlsx/export.ts +0 -253
  194. package/src/xlsx/import.ts +0 -160
  195. package/src/xlsx/index.ts +0 -35
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Bendyline LLC
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/NOTICE.md ADDED
@@ -0,0 +1,20 @@
1
+ # Third-Party Notices for @bendyline/squisq-formats
2
+
3
+ This notice applies to the `@bendyline/squisq-formats` npm package.
4
+ Squisq-authored code is licensed under the MIT license in `LICENSE`.
5
+ Third-party components remain under their respective license terms.
6
+
7
+ ## Runtime dependencies
8
+
9
+ | Package | Version | License | Repository |
10
+ | ----------------- | ------- | ----------------------- | ----------------------------------- |
11
+ | @bendyline/squisq | 2.1.0 | MIT | https://github.com/bendyline/squisq |
12
+ | @pdf-lib/upng | 1.0.1 | MIT | https://github.com/Hopding/upng |
13
+ | @xmldom/xmldom | 0.9.10 | MIT | https://github.com/xmldom/xmldom |
14
+ | jszip | 3.10.1 | MIT OR GPL-3.0-or-later | https://github.com/Stuk/jszip |
15
+ | pdf-lib | 1.17.1 | MIT | https://pdf-lib.js.org |
16
+ | pdfjs-dist | 4.10.38 | Apache-2.0 | https://mozilla.github.io/pdf.js |
17
+
18
+ Squisq uses jszip under its MIT license option. Copyright and complete license
19
+ texts for these dependencies are included in their respective npm
20
+ distributions and source repositories.
package/README.md CHANGED
@@ -87,7 +87,7 @@ const imported = await pdfToMarkdownDoc(pdfBuffer);
87
87
  const container = await pdfToContainer(pdfBuffer);
88
88
  ```
89
89
 
90
- **Fidelity:** export uses pdf-lib's standard 14 fonts (`themeId` affects colors only). PDF has no semantic structure, so import is heuristic and best-effort: headings are detected by font size, and tables / code blocks / blockquotes / links via the `detectTables` / `detectCodeBlocks` / `detectBlockquotes` / `detectLinks` options (all default true). `pdfToMarkdownDoc` is text-only; `pdfToContainer` also extracts embedded images, placed **by page** — each image is inserted after the last content block from its page (image-only pages fall back to the nearest preceding page with content, else the document end). Placement is page-level only. Image extraction needs a browser canvas to encode PNG **under Node it is skipped** (with a `console.warn`) and no images are emitted.
90
+ **Fidelity:** export uses pdf-lib's standard 14 fonts (`themeId` affects colors only). PDF has no semantic structure, so import is heuristic and best-effort: headings are detected by font size, and tables / code blocks / blockquotes / links via the `detectTables` / `detectCodeBlocks` / `detectBlockquotes` / `detectLinks` options (all default true). `pdfToMarkdownDoc` is text-only; `pdfToContainer` also extracts embedded XObject and inline raster images in browsers and Node, placed **by page** — each image is inserted after the last content block from its page (image-only pages fall back to the nearest preceding page with content, else the document end). Placement is page-level only; masks, vector artwork, and images that PDF.js cannot expose as decoded pixels are not emitted.
91
91
 
92
92
  ### HTML
93
93
 
@@ -1,21 +1,20 @@
1
1
  import {
2
+ RelIdAllocator,
2
3
  inlineNodeToRuns,
3
- inlineNodesToRuns
4
- } from "./chunk-6M7Z25LA.js";
4
+ inlineNodesToRuns,
5
+ normalizeOoxmlHex,
6
+ sanitizeOfficeHyperlink
7
+ } from "./chunk-GX7RAUME.js";
5
8
  import {
6
9
  stripHtmlTags
7
- } from "./chunk-PN52A5AA.js";
8
- import {
9
- baseDirOf,
10
- resolveTarget
11
- } from "./chunk-YRT7GQ5Y.js";
10
+ } from "./chunk-SBUW7NHR.js";
12
11
  import {
13
12
  createPackage
14
- } from "./chunk-KURGXM4I.js";
13
+ } from "./chunk-4V3KCHAP.js";
15
14
  import {
16
15
  escapeXml,
17
16
  xmlDeclaration
18
- } from "./chunk-U4MRIFKL.js";
17
+ } from "./chunk-JU2RHXUB.js";
19
18
  import {
20
19
  CONTENT_TYPE_DOCX_DOCUMENT,
21
20
  CONTENT_TYPE_DOCX_FONT_TABLE,
@@ -38,17 +37,20 @@ import {
38
37
  REL_OFFICE_DOCUMENT,
39
38
  REL_SETTINGS,
40
39
  REL_STYLES,
40
+ baseDirOf,
41
41
  getPartBinary,
42
42
  getPartRelationships,
43
43
  getPartXml,
44
- openPackage
45
- } from "./chunk-7ARKUCQT.js";
44
+ openPackage,
45
+ requireMainPartPath,
46
+ resolveTarget
47
+ } from "./chunk-X2DEAXNK.js";
46
48
  import {
47
49
  buildContainer
48
- } from "./chunk-SSUPBUF5.js";
50
+ } from "./chunk-IIQYS2YH.js";
49
51
  import {
50
52
  extToMime
51
- } from "./chunk-O3GVVND4.js";
53
+ } from "./chunk-AONELFLA.js";
52
54
 
53
55
  // src/docx/export.ts
54
56
  import { resolveFontFamily } from "@bendyline/squisq/schemas";
@@ -111,6 +113,7 @@ function pointsToTwips(points) {
111
113
 
112
114
  // src/docx/export.ts
113
115
  async function markdownDocToDocx(doc, options = {}) {
116
+ options.signal?.throwIfAborted();
114
117
  const resolvedOptions = options.themeId !== void 0 ? options : { ...options, themeId: readFrontmatterThemeId(doc.frontmatter) };
115
118
  const ctx = new ExportContext(resolvedOptions, doc);
116
119
  const stories = partitionDocumentStories(doc.children);
@@ -142,7 +145,14 @@ async function docToDocx(doc, options = {}) {
142
145
  }
143
146
  var ExportContext = class {
144
147
  constructor(options, doc) {
145
- this.nextRelId = 1;
148
+ /**
149
+ * One id source per rels part — see `RelIdAllocator`. Hyperlink, image AND
150
+ * fixed (styles/numbering/settings/…) rels all draw from this, keyed by the
151
+ * story part they belong to, so `word/_rels/document.xml.rels` cannot
152
+ * contain a duplicate `Id` no matter how many hyperlinks/images a document
153
+ * has.
154
+ */
155
+ this.relIds = new RelIdAllocator();
146
156
  this.nextNumId = 1;
147
157
  this.nextFootnoteId = 1;
148
158
  // 0 is separator, start user footnotes at 1
@@ -172,11 +182,10 @@ var ExportContext = class {
172
182
  const theme = resolveThemeForDoc(doc, options.themeId, options.themeRegistry);
173
183
  themeFont = firstFontFromStack(resolveFontFamily(theme.typography?.bodyFont, ""));
174
184
  themeTitleFont = firstFontFromStack(resolveFontFamily(theme.typography?.titleFont, ""));
175
- const stripHash = (c) => c.startsWith("#") ? c.slice(1) : c;
176
- if (theme.colors?.primary) themeHeadingColor = stripHash(theme.colors.primary);
177
- if (theme.colors?.text) themeBodyColor = stripHash(theme.colors.text);
178
- if (theme.colors?.textMuted) themeMutedColor = stripHash(theme.colors.textMuted);
179
- if (theme.colors?.background) themeBackgroundColor = stripHash(theme.colors.background);
185
+ themeHeadingColor = normalizeOoxmlHex(theme.colors?.primary);
186
+ themeBodyColor = normalizeOoxmlHex(theme.colors?.text);
187
+ themeMutedColor = normalizeOoxmlHex(theme.colors?.textMuted);
188
+ themeBackgroundColor = normalizeOoxmlHex(theme.colors?.background);
180
189
  }
181
190
  this.font = options.defaultFont ?? themeFont ?? DEFAULT_FONT;
182
191
  this.headingFont = themeTitleFont ?? this.font;
@@ -186,21 +195,31 @@ var ExportContext = class {
186
195
  this.mutedColor = themeMutedColor;
187
196
  this.backgroundColor = themeBackgroundColor;
188
197
  this.resolvedImages = options.images ?? /* @__PURE__ */ new Map();
198
+ this.allowRelativeHyperlinks = options.allowRelativeHyperlinks ?? false;
199
+ this.signal = options.signal;
189
200
  }
190
- /** Allocate a new relationship ID */
201
+ /** Allocate a relationship ID on the story part currently being converted. */
191
202
  allocRelId() {
192
- return `rId${this.nextRelId++}`;
203
+ return this.allocRelIdFor(this.relationshipSource);
204
+ }
205
+ /** Allocate a relationship ID on a specific story part. */
206
+ allocRelIdFor(source) {
207
+ return this.relIds.alloc(docxStoryPartPath(source));
193
208
  }
194
209
  setRelationshipSource(source) {
195
210
  this.relationshipSource = source;
196
211
  }
197
212
  /** Add a hyperlink relationship and return the rId */
198
213
  addHyperlink(url) {
214
+ const target = sanitizeOfficeHyperlink(url, {
215
+ allowRelative: this.allowRelativeHyperlinks
216
+ });
217
+ if (!target) return null;
199
218
  const id = this.allocRelId();
200
219
  this.relationships.push({
201
220
  id,
202
221
  type: REL_HYPERLINK,
203
- target: url,
222
+ target,
204
223
  targetMode: "External",
205
224
  source: this.relationshipSource
206
225
  });
@@ -238,6 +257,11 @@ var ExportContext = class {
238
257
  return id;
239
258
  }
240
259
  };
260
+ function docxStoryPartPath(source) {
261
+ if (source === "header") return "word/header1.xml";
262
+ if (source === "footer") return "word/footer1.xml";
263
+ return "word/document.xml";
264
+ }
241
265
  function firstFontFromStack(stack) {
242
266
  if (!stack) return "";
243
267
  const generics = /* @__PURE__ */ new Set([
@@ -264,7 +288,9 @@ function firstFontFromStack(stack) {
264
288
  }
265
289
  function convertBlocks(nodes, ctx) {
266
290
  const parts = [];
267
- for (const node of nodes) {
291
+ for (let index = 0; index < nodes.length; index++) {
292
+ if ((index & 255) === 0) ctx.signal?.throwIfAborted();
293
+ const node = nodes[index];
268
294
  parts.push(convertBlock(node, ctx, 0));
269
295
  }
270
296
  return parts.join("");
@@ -426,21 +452,20 @@ function convertInline(node, ctx, format) {
426
452
  function makeRun(text, format) {
427
453
  if (!text) return "";
428
454
  const rPrParts = [];
455
+ if (format.code) {
456
+ rPrParts.push(`<w:rFonts w:ascii="${DEFAULT_CODE_FONT}" w:hAnsi="${DEFAULT_CODE_FONT}"/>`);
457
+ }
429
458
  if (format.bold) rPrParts.push("<w:b/>");
430
459
  if (format.italic) rPrParts.push("<w:i/>");
431
460
  if (format.strike) rPrParts.push("<w:strike/>");
432
461
  if (format.color) rPrParts.push(`<w:color w:val="${format.color}"/>`);
433
- if (format.code) {
434
- rPrParts.push(
435
- `<w:rFonts w:ascii="${DEFAULT_CODE_FONT}" w:hAnsi="${DEFAULT_CODE_FONT}"/>`,
436
- `<w:sz w:val="${DEFAULT_CODE_FONT_SIZE}"/>`
437
- );
438
- }
462
+ if (format.code) rPrParts.push(`<w:sz w:val="${DEFAULT_CODE_FONT_SIZE}"/>`);
439
463
  const rPr = rPrParts.length > 0 ? `<w:rPr>${rPrParts.join("")}</w:rPr>` : "";
440
464
  return `<w:r>${rPr}<w:t xml:space="preserve">${escapeXml(text)}</w:t></w:r>`;
441
465
  }
442
466
  function convertLink(node, ctx, format) {
443
467
  const rId = ctx.addHyperlink(node.url);
468
+ if (!rId) return convertInlines(node.children, ctx, format);
444
469
  const styledRuns = convertInlinesWithHyperlinkStyle(node.children, ctx, format);
445
470
  return `<w:hyperlink r:id="${rId}">${styledRuns}</w:hyperlink>`;
446
471
  }
@@ -457,13 +482,10 @@ function convertInlinesWithHyperlinkStyle(nodes, ctx, format) {
457
482
  }
458
483
  function makeHyperlinkRun(text, format) {
459
484
  if (!text) return "";
460
- const rPrParts = [
461
- '<w:rStyle w:val="Hyperlink"/>',
462
- `<w:color w:val="${HYPERLINK_COLOR}"/>`,
463
- '<w:u w:val="single"/>'
464
- ];
485
+ const rPrParts = ['<w:rStyle w:val="Hyperlink"/>'];
465
486
  if (format.bold) rPrParts.push("<w:b/>");
466
487
  if (format.italic) rPrParts.push("<w:i/>");
488
+ rPrParts.push(`<w:color w:val="${HYPERLINK_COLOR}"/>`, '<w:u w:val="single"/>');
467
489
  return `<w:r><w:rPr>${rPrParts.join("")}</w:rPr><w:t xml:space="preserve">${escapeXml(text)}</w:t></w:r>`;
468
490
  }
469
491
  function convertImage(node, ctx) {
@@ -536,22 +558,16 @@ function convertFootnoteRef(node, ctx) {
536
558
  }
537
559
  async function buildDocxPackage(bodyXml, headerXml, footerXml, ctx, options) {
538
560
  const pkg = createPackage();
539
- let relCounter = 100;
540
- const stylesRelId = `rId${relCounter++}`;
541
- const numberingRelId = `rId${relCounter++}`;
542
- const settingsRelId = `rId${relCounter++}`;
543
- const fontTableRelId = `rId${relCounter++}`;
544
- const footnotesRelId = `rId${relCounter++}`;
545
- const headerRelId = `rId${relCounter++}`;
546
- const footerRelId = `rId${relCounter++}`;
547
561
  const hasHeader = headerXml.trim().length > 0;
548
562
  const hasFooter = footerXml.trim().length > 0;
549
- const documentXml = buildDocumentXml(
550
- bodyXml,
551
- ctx.backgroundColor,
552
- hasHeader ? headerRelId : void 0,
553
- hasFooter ? footerRelId : void 0
554
- );
563
+ const stylesRelId = ctx.allocRelIdFor("document");
564
+ const settingsRelId = ctx.allocRelIdFor("document");
565
+ const fontTableRelId = ctx.allocRelIdFor("document");
566
+ const numberingRelId = ctx.hasLists ? ctx.allocRelIdFor("document") : void 0;
567
+ const footnotesRelId = ctx.hasFootnotes ? ctx.allocRelIdFor("document") : void 0;
568
+ const headerRelId = hasHeader ? ctx.allocRelIdFor("document") : void 0;
569
+ const footerRelId = hasFooter ? ctx.allocRelIdFor("document") : void 0;
570
+ const documentXml = buildDocumentXml(bodyXml, ctx.backgroundColor, headerRelId, footerRelId);
555
571
  pkg.addPart("word/document.xml", documentXml, CONTENT_TYPE_DOCX_DOCUMENT);
556
572
  if (hasHeader) {
557
573
  pkg.addPart("word/header1.xml", buildStoryXml("header", headerXml), CONTENT_TYPE_DOCX_HEADER);
@@ -593,28 +609,28 @@ async function buildDocxPackage(bodyXml, headerXml, footerXml, ctx, options) {
593
609
  type: REL_FONT_TABLE,
594
610
  target: "fontTable.xml"
595
611
  });
596
- if (ctx.hasLists) {
612
+ if (numberingRelId) {
597
613
  pkg.addRelationship("word/document.xml", {
598
614
  id: numberingRelId,
599
615
  type: REL_NUMBERING,
600
616
  target: "numbering.xml"
601
617
  });
602
618
  }
603
- if (ctx.hasFootnotes) {
619
+ if (footnotesRelId) {
604
620
  pkg.addRelationship("word/document.xml", {
605
621
  id: footnotesRelId,
606
622
  type: REL_FOOTNOTES,
607
623
  target: "footnotes.xml"
608
624
  });
609
625
  }
610
- if (hasHeader) {
626
+ if (headerRelId) {
611
627
  pkg.addRelationship("word/document.xml", {
612
628
  id: headerRelId,
613
629
  type: REL_HEADER,
614
630
  target: "header1.xml"
615
631
  });
616
632
  }
617
- if (hasFooter) {
633
+ if (footerRelId) {
618
634
  pkg.addRelationship("word/document.xml", {
619
635
  id: footerRelId,
620
636
  type: REL_FOOTER,
@@ -622,8 +638,7 @@ async function buildDocxPackage(bodyXml, headerXml, footerXml, ctx, options) {
622
638
  });
623
639
  }
624
640
  for (const rel of ctx.relationships) {
625
- const sourcePart = rel.source === "header" ? "word/header1.xml" : rel.source === "footer" ? "word/footer1.xml" : "word/document.xml";
626
- pkg.addRelationship(sourcePart, {
641
+ pkg.addRelationship(docxStoryPartPath(rel.source), {
627
642
  id: rel.id,
628
643
  type: rel.type,
629
644
  target: rel.target,
@@ -726,12 +741,14 @@ function buildFootnotesXml(ctx) {
726
741
  // src/docx/import.ts
727
742
  import { markdownToDoc } from "@bendyline/squisq/doc";
728
743
  import { stringifyMarkdown } from "@bendyline/squisq/markdown";
744
+ var DOCX_MAIN_PART = "word/document.xml";
729
745
  async function docxToMarkdownDoc(data, options = {}) {
730
746
  const pkg = await openPackage(data, options);
731
- const ctx = await buildImportContext(pkg, options);
732
- const documentXml = await getPartXml(pkg, "word/document.xml");
747
+ const mainPart = requireMainPartPath(pkg, DOCX_MAIN_PART, "DOCX");
748
+ const ctx = await buildImportContext(pkg, options, mainPart);
749
+ const documentXml = await getPartXml(pkg, mainPart);
733
750
  if (!documentXml) {
734
- return { type: "document", children: [] };
751
+ throw new Error(`Invalid DOCX package: main document part "${mainPart}" could not be parsed.`);
735
752
  }
736
753
  const body = getFirstElement(documentXml, "body");
737
754
  if (!body) {
@@ -746,16 +763,19 @@ async function docxToDoc(data, options = {}) {
746
763
  }
747
764
  async function docxToContainer(data, options = {}) {
748
765
  const pkg = await openPackage(data, options);
749
- const ctx = await buildImportContext(pkg, { ...options, extractImages: true });
750
- const documentXml = await getPartXml(pkg, "word/document.xml");
751
- if (!documentXml) return buildContainer("", []);
766
+ const mainPart = requireMainPartPath(pkg, DOCX_MAIN_PART, "DOCX");
767
+ const ctx = await buildImportContext(pkg, { ...options, extractImages: true }, mainPart);
768
+ const documentXml = await getPartXml(pkg, mainPart);
769
+ if (!documentXml) {
770
+ throw new Error(`Invalid DOCX package: main document part "${mainPart}" could not be parsed.`);
771
+ }
752
772
  const body = getFirstElement(documentXml, "body");
753
773
  if (!body) return buildContainer("", []);
754
774
  const blocks = await convertDocumentStories(body, ctx);
755
775
  const markdownDoc = { type: "document", children: blocks };
756
776
  return buildContainer(stringifyMarkdown(markdownDoc), ctx.extractedImages);
757
777
  }
758
- async function buildImportContext(pkg, options) {
778
+ async function buildImportContext(pkg, options, mainPartPath = DOCX_MAIN_PART) {
759
779
  const ctx = {
760
780
  headingStyles: /* @__PURE__ */ new Map(),
761
781
  quoteStyles: /* @__PURE__ */ new Set(),
@@ -765,7 +785,8 @@ async function buildImportContext(pkg, options) {
765
785
  numbering: /* @__PURE__ */ new Map(),
766
786
  footnotes: /* @__PURE__ */ new Map(),
767
787
  endnotes: /* @__PURE__ */ new Map(),
768
- currentPartPath: "word/document.xml",
788
+ currentPartPath: mainPartPath,
789
+ mainPartPath,
769
790
  pkg,
770
791
  options,
771
792
  extractedImages: /* @__PURE__ */ new Map(),
@@ -784,7 +805,7 @@ async function buildImportContext(pkg, options) {
784
805
  ctx.inlineCodeStyles.add(id);
785
806
  }
786
807
  await parseStyles(pkg, ctx);
787
- const rels = await getPartRelationships(pkg, "word/document.xml");
808
+ const rels = await getPartRelationships(pkg, mainPartPath);
788
809
  for (const rel of rels) {
789
810
  ctx.documentRels.set(rel.id, rel);
790
811
  }
@@ -902,7 +923,7 @@ async function convertRelatedStories(body, ctx, kind) {
902
923
  const results = [];
903
924
  for (const relationship of documentRelationships.values()) {
904
925
  if (!relationship.type.endsWith(relationshipTypeSuffix)) continue;
905
- const partPath = resolveTarget(baseDirOf("word/document.xml"), relationship.target);
926
+ const partPath = resolveTarget(baseDirOf(ctx.mainPartPath), relationship.target);
906
927
  const part = await getPartXml(ctx.pkg, partPath);
907
928
  if (!part?.documentElement) continue;
908
929
  const partRelationships = await getPartRelationships(ctx.pkg, partPath);
@@ -1431,4 +1452,3 @@ export {
1431
1452
  docxToDoc,
1432
1453
  docxToContainer
1433
1454
  };
1434
- //# sourceMappingURL=chunk-NNHKUXKA.js.map
@@ -103,4 +103,3 @@ export {
103
103
  compileExtractedTheme,
104
104
  colorHintsFromExtraction
105
105
  };
106
- //# sourceMappingURL=chunk-NKAJPJ4G.js.map