@bendyline/squisq-formats 2.0.0 → 2.0.1

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 (70) hide show
  1. package/dist/{chunk-CX3LH47J.js → chunk-2KPARF2P.js} +3 -3
  2. package/dist/{chunk-CVNVD7VH.js → chunk-ABVI556T.js} +5 -5
  3. package/dist/{chunk-2CSZJEAL.js → chunk-CRAVSMPZ.js} +3 -3
  4. package/dist/{chunk-H7T5DXUU.js → chunk-FE6OJV6O.js} +95 -14
  5. package/dist/chunk-FE6OJV6O.js.map +1 -0
  6. package/dist/{chunk-2EFDWKC6.js → chunk-HTW2M27H.js} +86 -23
  7. package/dist/chunk-HTW2M27H.js.map +1 -0
  8. package/dist/{chunk-ZZ7D4DN6.js → chunk-QRVN6A6E.js} +39 -9
  9. package/dist/chunk-QRVN6A6E.js.map +1 -0
  10. package/dist/{chunk-XTLQXR4U.js → chunk-U32AG3G3.js} +3 -3
  11. package/dist/{chunk-HBSCRS5P.js → chunk-VJJM2SSH.js} +3 -3
  12. package/dist/{chunk-2PRVLAU3.js → chunk-VSYHZECT.js} +55 -17
  13. package/dist/chunk-VSYHZECT.js.map +1 -0
  14. package/dist/{chunk-4HJ6AK2Q.js → chunk-WC7WULGV.js} +44 -13
  15. package/dist/chunk-WC7WULGV.js.map +1 -0
  16. package/dist/{chunk-X4USWOQ2.js → chunk-XKUMNGBW.js} +2 -2
  17. package/dist/container/index.d.ts +10 -4
  18. package/dist/container/index.js +9 -4
  19. package/dist/container/index.js.map +1 -1
  20. package/dist/docx/index.d.ts +2 -2
  21. package/dist/docx/index.js +4 -4
  22. package/dist/{export-Djev9BLU.d.ts → export-D2NkylDT.d.ts} +1 -1
  23. package/dist/{extract-LNOA7DBK.js → extract-H6RXJMHP.js} +5 -5
  24. package/dist/{import-Yivc3kZM.d.ts → import-K8mfc0fz.d.ts} +1 -1
  25. package/dist/index.d.ts +8 -7
  26. package/dist/index.js +14 -12
  27. package/dist/infer/index.d.ts +4 -4
  28. package/dist/infer/index.js +5 -5
  29. package/dist/{layouts-CZ0bdsNL.d.ts → layouts-BHrgZ5FS.d.ts} +1 -1
  30. package/dist/{layouts-7OUUVAGU.js → layouts-QVPK3ZCU.js} +4 -4
  31. package/dist/ooxml/index.d.ts +4 -4
  32. package/dist/ooxml/index.js +4 -4
  33. package/dist/pptx/index.d.ts +5 -5
  34. package/dist/pptx/index.js +5 -5
  35. package/dist/{reader-Gof6OrJX.d.ts → reader-B9L8Ucbj.d.ts} +3 -3
  36. package/dist/registry/index.d.ts +20 -6
  37. package/dist/registry/index.js +6 -4
  38. package/dist/{themeReader-DPw4J5Ss.d.ts → themeReader-DJKErl_j.d.ts} +1 -1
  39. package/dist/xlsx/index.d.ts +4 -4
  40. package/dist/xlsx/index.js +4 -4
  41. package/dist/{zipLimits-bGYMS9cI.d.ts → zipLimits-BOKCB7qk.d.ts} +2 -0
  42. package/package.json +2 -2
  43. package/src/__tests__/convert.test.ts +143 -1
  44. package/src/__tests__/ooxml.test.ts +17 -0
  45. package/src/__tests__/ooxmlCancellation.test.ts +113 -0
  46. package/src/container/index.ts +17 -3
  47. package/src/index.ts +3 -0
  48. package/src/infer/index.ts +35 -4
  49. package/src/ooxml/reader.ts +55 -14
  50. package/src/pptx/layouts.ts +68 -14
  51. package/src/registry/convert.ts +115 -31
  52. package/src/registry/defaultFormats.ts +5 -2
  53. package/src/registry/index.ts +3 -1
  54. package/src/registry/types.ts +18 -1
  55. package/src/shared/boundedZipArchive.ts +49 -8
  56. package/src/shared/zipEntryCount.ts +59 -5
  57. package/src/shared/zipLimits.ts +10 -0
  58. package/dist/chunk-2EFDWKC6.js.map +0 -1
  59. package/dist/chunk-2PRVLAU3.js.map +0 -1
  60. package/dist/chunk-4HJ6AK2Q.js.map +0 -1
  61. package/dist/chunk-H7T5DXUU.js.map +0 -1
  62. package/dist/chunk-ZZ7D4DN6.js.map +0 -1
  63. /package/dist/{chunk-CX3LH47J.js.map → chunk-2KPARF2P.js.map} +0 -0
  64. /package/dist/{chunk-CVNVD7VH.js.map → chunk-ABVI556T.js.map} +0 -0
  65. /package/dist/{chunk-2CSZJEAL.js.map → chunk-CRAVSMPZ.js.map} +0 -0
  66. /package/dist/{chunk-XTLQXR4U.js.map → chunk-U32AG3G3.js.map} +0 -0
  67. /package/dist/{chunk-HBSCRS5P.js.map → chunk-VJJM2SSH.js.map} +0 -0
  68. /package/dist/{chunk-X4USWOQ2.js.map → chunk-XKUMNGBW.js.map} +0 -0
  69. /package/dist/{extract-LNOA7DBK.js.map → extract-H6RXJMHP.js.map} +0 -0
  70. /package/dist/{layouts-7OUUVAGU.js.map → layouts-QVPK3ZCU.js.map} +0 -0
package/dist/index.js CHANGED
@@ -7,15 +7,16 @@ import {
7
7
  convert,
8
8
  createRegistry,
9
9
  defaultFormats,
10
- defaultRegistry
11
- } from "./chunk-2EFDWKC6.js";
10
+ defaultRegistry,
11
+ prepareConversion
12
+ } from "./chunk-HTW2M27H.js";
12
13
  import {
13
14
  inferThemeFromFile
14
- } from "./chunk-ZZ7D4DN6.js";
15
+ } from "./chunk-QRVN6A6E.js";
15
16
  import {
16
17
  ConversionError
17
18
  } from "./chunk-ODL3SSPT.js";
18
- import "./chunk-CX3LH47J.js";
19
+ import "./chunk-2KPARF2P.js";
19
20
  import {
20
21
  compileExtractedTheme
21
22
  } from "./chunk-NKAJPJ4G.js";
@@ -24,21 +25,21 @@ import {
24
25
  docxToDoc,
25
26
  docxToMarkdownDoc,
26
27
  markdownDocToDocx
27
- } from "./chunk-2CSZJEAL.js";
28
+ } from "./chunk-CRAVSMPZ.js";
28
29
  import {
29
30
  docToPptx,
30
31
  markdownDocToPptx,
31
32
  pptxToDoc,
32
33
  pptxToMarkdownDoc
33
- } from "./chunk-CVNVD7VH.js";
34
- import "./chunk-2PRVLAU3.js";
34
+ } from "./chunk-ABVI556T.js";
35
+ import "./chunk-VSYHZECT.js";
35
36
  import "./chunk-6M7Z25LA.js";
36
37
  import {
37
38
  docToXlsx,
38
39
  markdownDocToXlsx,
39
40
  xlsxToDoc,
40
41
  xlsxToMarkdownDoc
41
- } from "./chunk-HBSCRS5P.js";
42
+ } from "./chunk-VJJM2SSH.js";
42
43
  import "./chunk-PN52A5AA.js";
43
44
  import {
44
45
  csvToDoc,
@@ -46,14 +47,14 @@ import {
46
47
  markdownDocToCsv,
47
48
  parseCsv
48
49
  } from "./chunk-RFAPOKHJ.js";
49
- import "./chunk-X4USWOQ2.js";
50
+ import "./chunk-XKUMNGBW.js";
50
51
  import "./chunk-YRT7GQ5Y.js";
51
- import "./chunk-XTLQXR4U.js";
52
+ import "./chunk-U32AG3G3.js";
52
53
  import "./chunk-U4MRIFKL.js";
53
- import "./chunk-4HJ6AK2Q.js";
54
+ import "./chunk-WC7WULGV.js";
54
55
  import {
55
56
  ZipSafetyError
56
- } from "./chunk-H7T5DXUU.js";
57
+ } from "./chunk-FE6OJV6O.js";
57
58
  import {
58
59
  configurePdfWorker,
59
60
  docToPdf,
@@ -109,6 +110,7 @@ export {
109
110
  pdfToMarkdownDoc,
110
111
  pptxToDoc,
111
112
  pptxToMarkdownDoc,
113
+ prepareConversion,
112
114
  xlsxToDoc,
113
115
  xlsxToMarkdownDoc
114
116
  };
@@ -1,8 +1,8 @@
1
1
  import { Theme, DeepPartial, CustomTemplateDefinition } from '@bendyline/squisq/schemas';
2
- import { a as OoxmlPackage, O as OoxmlOpenOptions } from '../reader-Gof6OrJX.js';
3
- import { O as OoxmlColorScheme, a as OoxmlFontScheme } from '../themeReader-DPw4J5Ss.js';
4
- import { P as PptxColorHints } from '../layouts-CZ0bdsNL.js';
5
- import '../zipLimits-bGYMS9cI.js';
2
+ import { a as OoxmlPackage, O as OoxmlOpenOptions } from '../reader-B9L8Ucbj.js';
3
+ import { O as OoxmlColorScheme, a as OoxmlFontScheme } from '../themeReader-DJKErl_j.js';
4
+ import { P as PptxColorHints } from '../layouts-BHrgZ5FS.js';
5
+ import '../zipLimits-BOKCB7qk.js';
6
6
 
7
7
  /**
8
8
  * Shared types for file-import theme inference.
@@ -1,21 +1,21 @@
1
1
  import {
2
2
  inferThemeFromFile
3
- } from "../chunk-ZZ7D4DN6.js";
3
+ } from "../chunk-QRVN6A6E.js";
4
4
  import "../chunk-ODL3SSPT.js";
5
5
  import {
6
6
  extractDocxTheme,
7
7
  extractPptxTheme,
8
8
  extractXlsxTheme
9
- } from "../chunk-CX3LH47J.js";
9
+ } from "../chunk-2KPARF2P.js";
10
10
  import {
11
11
  colorHintsFromExtraction,
12
12
  compileExtractedTheme,
13
13
  extractedThemeToPartial
14
14
  } from "../chunk-NKAJPJ4G.js";
15
- import "../chunk-X4USWOQ2.js";
15
+ import "../chunk-XKUMNGBW.js";
16
16
  import "../chunk-YRT7GQ5Y.js";
17
- import "../chunk-4HJ6AK2Q.js";
18
- import "../chunk-H7T5DXUU.js";
17
+ import "../chunk-WC7WULGV.js";
18
+ import "../chunk-FE6OJV6O.js";
19
19
  export {
20
20
  colorHintsFromExtraction,
21
21
  compileExtractedTheme,
@@ -1,5 +1,5 @@
1
1
  import { CustomTemplateDefinition } from '@bendyline/squisq/schemas';
2
- import { O as OoxmlOpenOptions, a as OoxmlPackage } from './reader-Gof6OrJX.js';
2
+ import { O as OoxmlOpenOptions, a as OoxmlPackage } from './reader-B9L8Ucbj.js';
3
3
 
4
4
  /**
5
5
  * PPTX slide-layout inference — reads the layouts/masters a deck actually
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  analyzePptxLayouts,
3
3
  inspectPptxLayouts
4
- } from "./chunk-2PRVLAU3.js";
4
+ } from "./chunk-VSYHZECT.js";
5
5
  import "./chunk-YRT7GQ5Y.js";
6
- import "./chunk-4HJ6AK2Q.js";
7
- import "./chunk-H7T5DXUU.js";
6
+ import "./chunk-WC7WULGV.js";
7
+ import "./chunk-FE6OJV6O.js";
8
8
  export {
9
9
  analyzePptxLayouts,
10
10
  inspectPptxLayouts
11
11
  };
12
- //# sourceMappingURL=layouts-7OUUVAGU.js.map
12
+ //# sourceMappingURL=layouts-QVPK3ZCU.js.map
@@ -1,7 +1,7 @@
1
- import { R as Relationship, C as CoreProperties } from '../reader-Gof6OrJX.js';
2
- export { b as ContentTypeMap, O as OoxmlOpenOptions, a as OoxmlPackage, P as PackagePart, c as PendingRelationship, g as getCoreProperties, d as getPartBinary, e as getPartRelationships, f as getPartXml, o as openPackage } from '../reader-Gof6OrJX.js';
3
- export { Z as ZipSafetyError, a as ZipSafetyErrorCode, b as ZipSafetyErrorOptions, c as ZipSafetyLimits } from '../zipLimits-bGYMS9cI.js';
4
- export { O as OoxmlColorScheme, a as OoxmlFontScheme, b as OoxmlTheme, p as parseThemeXml, r as readThemePart } from '../themeReader-DPw4J5Ss.js';
1
+ import { R as Relationship, C as CoreProperties } from '../reader-B9L8Ucbj.js';
2
+ export { b as ContentTypeMap, O as OoxmlOpenOptions, a as OoxmlPackage, P as PackagePart, c as PendingRelationship, g as getCoreProperties, d as getPartBinary, e as getPartRelationships, f as getPartXml, o as openPackage } from '../reader-B9L8Ucbj.js';
3
+ export { Z as ZipSafetyError, a as ZipSafetyErrorCode, b as ZipSafetyErrorOptions, c as ZipSafetyLimits } from '../zipLimits-BOKCB7qk.js';
4
+ export { O as OoxmlColorScheme, a as OoxmlFontScheme, b as OoxmlTheme, p as parseThemeXml, r as readThemePart } from '../themeReader-DJKErl_j.js';
5
5
 
6
6
  /**
7
7
  * Shared DOM-read helpers for OOXML importers.
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  parseThemeXml,
3
3
  readThemePart
4
- } from "../chunk-X4USWOQ2.js";
4
+ } from "../chunk-XKUMNGBW.js";
5
5
  import {
6
6
  attrNS,
7
7
  baseDirOf,
@@ -10,7 +10,7 @@ import {
10
10
  } from "../chunk-YRT7GQ5Y.js";
11
11
  import {
12
12
  createPackage
13
- } from "../chunk-XTLQXR4U.js";
13
+ } from "../chunk-U32AG3G3.js";
14
14
  import {
15
15
  attrString,
16
16
  escapeXml,
@@ -70,10 +70,10 @@ import {
70
70
  getPartRelationships,
71
71
  getPartXml,
72
72
  openPackage
73
- } from "../chunk-4HJ6AK2Q.js";
73
+ } from "../chunk-WC7WULGV.js";
74
74
  import {
75
75
  ZipSafetyError
76
- } from "../chunk-H7T5DXUU.js";
76
+ } from "../chunk-FE6OJV6O.js";
77
77
  export {
78
78
  CONTENT_TYPE_CORE_PROPERTIES,
79
79
  CONTENT_TYPE_DOCX_DOCUMENT,
@@ -1,10 +1,10 @@
1
- import { a as PptxImportOptions } from '../import-Yivc3kZM.js';
2
- export { P as PptxExportOptions, d as docToPptx, m as markdownDocToPptx, b as pptxToContainer, p as pptxToMarkdownDoc } from '../import-Yivc3kZM.js';
1
+ import { a as PptxImportOptions } from '../import-K8mfc0fz.js';
2
+ export { P as PptxExportOptions, d as docToPptx, m as markdownDocToPptx, b as pptxToContainer, p as pptxToMarkdownDoc } from '../import-K8mfc0fz.js';
3
3
  import { Doc } from '@bendyline/squisq/schemas';
4
- export { A as AnalyzePptxLayoutsOptions, a as AnalyzedLayout, E as ExtractedPlaceholder, b as ExtractedSlideLayout, I as InspectPptxLayoutsOptions, L as LayoutVerdict, P as PptxColorHints, c as PptxLayoutInference, d as PptxLayoutSummary, e as analyzePptxLayouts, i as inspectPptxLayouts } from '../layouts-CZ0bdsNL.js';
4
+ export { A as AnalyzePptxLayoutsOptions, a as AnalyzedLayout, E as ExtractedPlaceholder, b as ExtractedSlideLayout, I as InspectPptxLayoutsOptions, L as LayoutVerdict, P as PptxColorHints, c as PptxLayoutInference, d as PptxLayoutSummary, e as analyzePptxLayouts, i as inspectPptxLayouts } from '../layouts-BHrgZ5FS.js';
5
5
  import '@bendyline/squisq/markdown';
6
- import '../reader-Gof6OrJX.js';
7
- import '../zipLimits-bGYMS9cI.js';
6
+ import '../reader-B9L8Ucbj.js';
7
+ import '../zipLimits-BOKCB7qk.js';
8
8
  import '@bendyline/squisq/storage';
9
9
 
10
10
  /**
@@ -4,18 +4,18 @@ import {
4
4
  pptxToContainer,
5
5
  pptxToDoc,
6
6
  pptxToMarkdownDoc
7
- } from "../chunk-CVNVD7VH.js";
7
+ } from "../chunk-ABVI556T.js";
8
8
  import {
9
9
  analyzePptxLayouts,
10
10
  inspectPptxLayouts
11
- } from "../chunk-2PRVLAU3.js";
11
+ } from "../chunk-VSYHZECT.js";
12
12
  import "../chunk-6M7Z25LA.js";
13
13
  import "../chunk-PN52A5AA.js";
14
14
  import "../chunk-YRT7GQ5Y.js";
15
- import "../chunk-XTLQXR4U.js";
15
+ import "../chunk-U32AG3G3.js";
16
16
  import "../chunk-U4MRIFKL.js";
17
- import "../chunk-4HJ6AK2Q.js";
18
- import "../chunk-H7T5DXUU.js";
17
+ import "../chunk-WC7WULGV.js";
18
+ import "../chunk-FE6OJV6O.js";
19
19
  import "../chunk-SSUPBUF5.js";
20
20
  import "../chunk-MLX2BOJC.js";
21
21
  import "../chunk-O3GVVND4.js";
@@ -1,4 +1,4 @@
1
- import { c as ZipSafetyLimits } from './zipLimits-bGYMS9cI.js';
1
+ import { c as ZipSafetyLimits } from './zipLimits-BOKCB7qk.js';
2
2
 
3
3
  /**
4
4
  * OOXML Types
@@ -89,8 +89,8 @@ interface PendingRelationship {
89
89
  * structural metadata: [Content_Types].xml, relationships, and
90
90
  * core properties.
91
91
  *
92
- * Uses bounded JSZip member streams and a platform DOMParser (with an xmldom
93
- * fallback in bare Node/SSR) to parse XML.
92
+ * Uses bounded JSZip member streams and a platform DOMParser (with the
93
+ * package-owned xmldom parser in Node/SSR) to parse XML.
94
94
  */
95
95
 
96
96
  type OoxmlOpenOptions = ZipSafetyLimits;
@@ -3,14 +3,15 @@ import { TransformStyleInput, TransformStyleRegistry } from '@bendyline/squisq/t
3
3
  import { ParseOptions, StringifyOptions, MarkdownDocument } from '@bendyline/squisq/markdown';
4
4
  import { ContentContainer } from '@bendyline/squisq/storage';
5
5
  import { DocxImportOptions, DocxExportOptions } from '../docx/index.js';
6
- import { a as PptxImportOptions, P as PptxExportOptions } from '../import-Yivc3kZM.js';
7
- import { a as XlsxImportOptions, X as XlsxExportOptions } from '../export-Djev9BLU.js';
6
+ import { a as PptxImportOptions, P as PptxExportOptions } from '../import-K8mfc0fz.js';
7
+ import { a as XlsxImportOptions, X as XlsxExportOptions } from '../export-D2NkylDT.js';
8
8
  import { CsvImportOptions, CsvExportOptions } from '../csv/index.js';
9
9
  import { PdfImportOptions, PdfExportOptions } from '../pdf/index.js';
10
10
  import { a as HtmlImportOptions, H as HtmlExportOptions } from '../import-DTkDxHmZ.js';
11
11
  import { EpubExportOptions } from '../epub/index.js';
12
- import { c as ZipSafetyLimits } from '../zipLimits-bGYMS9cI.js';
13
- import '../reader-Gof6OrJX.js';
12
+ import { ContainerToZipOptions } from '../container/index.js';
13
+ import { c as ZipSafetyLimits } from '../zipLimits-BOKCB7qk.js';
14
+ import '../reader-B9L8Ucbj.js';
14
15
 
15
16
  /**
16
17
  * Format registry — shared types.
@@ -42,7 +43,7 @@ interface MarkdownFormatOptions {
42
43
  stringify?: StringifyOptions;
43
44
  }
44
45
  /** Resource limits applied when importing a DBK/ZIP container. */
45
- type DbkFormatOptions = ZipSafetyLimits;
46
+ type DbkFormatOptions = ZipSafetyLimits & ContainerToZipOptions;
46
47
  /**
47
48
  * Strongly typed option bags for built-in formats. Import and export options
48
49
  * share a bag because a single conversion may use the format on either side.
@@ -74,6 +75,8 @@ interface NormalizedInput {
74
75
  }
75
76
  /** Options threaded through `convert()` and into every format method. */
76
77
  interface ConvertOptions {
78
+ /** Cancel normalization, transformation, or export at the next bounded work boundary. */
79
+ signal?: AbortSignal;
77
80
  /** Registry to resolve formats against. Defaults to `defaultRegistry()`. */
78
81
  registry?: FormatRegistry;
79
82
  /** Explicit source format id (skips extension/byte sniffing). */
@@ -95,6 +98,15 @@ interface ConvertOptions {
95
98
  /** Typed per-format options for built-ins; custom format ids remain extensible. */
96
99
  formatOptions?: Partial<BuiltinFormatOptions> & Record<FormatId, unknown>;
97
100
  }
101
+ /** Target-only options accepted after a source has already been normalized and transformed. */
102
+ type PreparedExportOptions = Pick<ConvertOptions, 'signal' | 'title' | 'resolvePlayerScript' | 'formatOptions'>;
103
+ /**
104
+ * An opaque normalized conversion snapshot. The source and transform pipeline
105
+ * has already completed; each call exports that same snapshot to one target.
106
+ */
107
+ interface PreparedConversion {
108
+ convert(to: FormatId, options?: PreparedExportOptions): Promise<ConversionResult>;
109
+ }
98
110
  /** Describes how a single format imports to / exports from the squisq model. */
99
111
  interface FormatDefinition {
100
112
  id: FormatId;
@@ -192,6 +204,8 @@ declare function defaultFormats(): FormatDefinition[];
192
204
  * an optional transform, then hands off to the target format's exporter.
193
205
  */
194
206
 
207
+ /** Normalize and transform a source once, then safely export that snapshot many times. */
208
+ declare function prepareConversion(source: ConvertSource, options?: ConvertOptions): Promise<PreparedConversion>;
195
209
  /**
196
210
  * Convert a source document to a target format.
197
211
  *
@@ -202,4 +216,4 @@ declare function defaultFormats(): FormatDefinition[];
202
216
  */
203
217
  declare function convert(source: ConvertSource, to: FormatId, options?: ConvertOptions): Promise<ConversionResult>;
204
218
 
205
- export { BUILTIN_FORMAT_IDS, type BuiltinFormatOptions, ConversionError, type ConversionErrorCode, type ConversionErrorOptions, type ConversionResult, type ConvertOptions, type ConvertSource, type DbkFormatOptions, type FormatDefinition, type FormatId, type FormatRegistry, type MarkdownFormatOptions, type NormalizedInput, convert, createRegistry, defaultFormats, defaultRegistry };
219
+ export { BUILTIN_FORMAT_IDS, type BuiltinFormatOptions, ConversionError, type ConversionErrorCode, type ConversionErrorOptions, type ConversionResult, type ConvertOptions, type ConvertSource, type DbkFormatOptions, type FormatDefinition, type FormatId, type FormatRegistry, type MarkdownFormatOptions, type NormalizedInput, type PreparedConversion, type PreparedExportOptions, convert, createRegistry, defaultFormats, defaultRegistry, prepareConversion };
@@ -3,18 +3,20 @@ import {
3
3
  convert,
4
4
  createRegistry,
5
5
  defaultFormats,
6
- defaultRegistry
7
- } from "../chunk-2EFDWKC6.js";
6
+ defaultRegistry,
7
+ prepareConversion
8
+ } from "../chunk-HTW2M27H.js";
8
9
  import {
9
10
  ConversionError
10
11
  } from "../chunk-ODL3SSPT.js";
11
- import "../chunk-H7T5DXUU.js";
12
+ import "../chunk-FE6OJV6O.js";
12
13
  export {
13
14
  BUILTIN_FORMAT_IDS,
14
15
  ConversionError,
15
16
  convert,
16
17
  createRegistry,
17
18
  defaultFormats,
18
- defaultRegistry
19
+ defaultRegistry,
20
+ prepareConversion
19
21
  };
20
22
  //# sourceMappingURL=index.js.map
@@ -1,4 +1,4 @@
1
- import { a as OoxmlPackage } from './reader-Gof6OrJX.js';
1
+ import { a as OoxmlPackage } from './reader-B9L8Ucbj.js';
2
2
 
3
3
  /**
4
4
  * OOXML theme reader — parses a `theme1.xml` part (DrawingML `a:theme`)
@@ -1,9 +1,9 @@
1
1
  import { Doc } from '@bendyline/squisq/schemas';
2
- import { a as XlsxImportOptions } from '../export-Djev9BLU.js';
3
- export { X as XlsxExportOptions, d as docToXlsx, m as markdownDocToXlsx, x as xlsxToMarkdownDoc } from '../export-Djev9BLU.js';
2
+ import { a as XlsxImportOptions } from '../export-D2NkylDT.js';
3
+ export { X as XlsxExportOptions, d as docToXlsx, m as markdownDocToXlsx, x as xlsxToMarkdownDoc } from '../export-D2NkylDT.js';
4
4
  import '@bendyline/squisq/markdown';
5
- import '../reader-Gof6OrJX.js';
6
- import '../zipLimits-bGYMS9cI.js';
5
+ import '../reader-B9L8Ucbj.js';
6
+ import '../zipLimits-BOKCB7qk.js';
7
7
 
8
8
  /**
9
9
  * @bendyline/squisq-formats XLSX Module
@@ -3,12 +3,12 @@ import {
3
3
  markdownDocToXlsx,
4
4
  xlsxToDoc,
5
5
  xlsxToMarkdownDoc
6
- } from "../chunk-HBSCRS5P.js";
6
+ } from "../chunk-VJJM2SSH.js";
7
7
  import "../chunk-PN52A5AA.js";
8
- import "../chunk-XTLQXR4U.js";
8
+ import "../chunk-U32AG3G3.js";
9
9
  import "../chunk-U4MRIFKL.js";
10
- import "../chunk-4HJ6AK2Q.js";
11
- import "../chunk-H7T5DXUU.js";
10
+ import "../chunk-WC7WULGV.js";
11
+ import "../chunk-FE6OJV6O.js";
12
12
  export {
13
13
  docToXlsx,
14
14
  markdownDocToXlsx,
@@ -1,6 +1,8 @@
1
1
  /** ZIP safety policy, structured errors, path checks, and metadata validation. */
2
2
 
3
3
  interface ZipSafetyLimits {
4
+ /** Cooperatively cancel archive opening, validation, and member traversal. */
5
+ signal?: AbortSignal;
4
6
  /** Maximum number of archive records, including directories. Default: 10,000. */
5
7
  maxEntries?: number;
6
8
  /** Maximum uncompressed bytes for one member. Defaults to maxUncompressedBytes. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bendyline/squisq-formats",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "Document format converters — DOCX, PDF, OOXML import/export",
5
5
  "license": "MIT",
6
6
  "author": "Bendyline",
@@ -100,7 +100,7 @@
100
100
  },
101
101
  "dependencies": {
102
102
  "@xmldom/xmldom": "0.9.10",
103
- "@bendyline/squisq": "2.0.0",
103
+ "@bendyline/squisq": "2.0.1",
104
104
  "jszip": "3.10.1",
105
105
  "pdf-lib": "1.17.1",
106
106
  "pdfjs-dist": "4.10.38"
@@ -10,7 +10,7 @@ import { parseMarkdown } from '@bendyline/squisq/markdown';
10
10
  import { markdownToDoc } from '@bendyline/squisq/doc';
11
11
  import { MemoryContentContainer } from '@bendyline/squisq/storage';
12
12
  import { createTransformStyleRegistry, resolveTransformStyle } from '@bendyline/squisq/transform';
13
- import { convert, ConversionError, defaultRegistry } from '../registry/index';
13
+ import { convert, ConversionError, defaultRegistry, prepareConversion } from '../registry/index';
14
14
  import { zipToContainer } from '../container/index';
15
15
  import { markdownDocToPptx } from '../pptx/export';
16
16
  import { buildThemedPptx } from './pptxInferFixtures';
@@ -57,6 +57,31 @@ describe('convert error paths', () => {
57
57
  format: 'docx',
58
58
  });
59
59
  });
60
+
61
+ it('threads cancellation to exporters and preserves the abort reason', async () => {
62
+ const controller = new AbortController();
63
+ const reason = new Error('caller cancelled conversion');
64
+ reason.name = 'AbortError';
65
+ const registry = defaultRegistry();
66
+ registry.register({
67
+ id: 'abortable',
68
+ label: 'Abortable',
69
+ mimeType: 'application/x-abortable',
70
+ extensions: ['.abortable'],
71
+ async exportDoc(_input, options) {
72
+ expect(options.signal).toBe(controller.signal);
73
+ controller.abort(reason);
74
+ throw new Error('must not replace the abort reason');
75
+ },
76
+ });
77
+
78
+ await expect(
79
+ convert({ kind: 'markdown', markdown: '# Cancel me' }, 'abortable', {
80
+ registry,
81
+ signal: controller.signal,
82
+ }),
83
+ ).rejects.toBe(reason);
84
+ });
60
85
  });
61
86
 
62
87
  describe('format option threading', () => {
@@ -110,6 +135,16 @@ describe('format option threading', () => {
110
135
  }),
111
136
  ).rejects.toMatchObject({ code: 'invalid-input', format: 'docx' });
112
137
  });
138
+
139
+ it('can emit DBK with STORE so strict import compression limits accept its own output', async () => {
140
+ const result = await convert(
141
+ { kind: 'markdown', markdown: `# Self-compatible DBK\n\n${'x'.repeat(16 * 1024)}` },
142
+ 'dbk',
143
+ { formatOptions: { dbk: { compression: 'STORE' } } },
144
+ );
145
+ const restored = await zipToContainer(result.bytes, { maxCompressionRatio: 1.01 });
146
+ expect(await restored.readDocument()).toContain('Self-compatible DBK');
147
+ });
113
148
  });
114
149
 
115
150
  // ── round trip: md → docx → md ──────────────────────────────────────
@@ -191,6 +226,113 @@ describe('byte sniffing', () => {
191
226
  // ── transform threading ─────────────────────────────────────────────
192
227
 
193
228
  describe('transform threading', () => {
229
+ it('normalizes and transforms once before exporting multiple targets', async () => {
230
+ let importCount = 0;
231
+ let transformLookupCount = 0;
232
+ const exportCounts = { first: 0, second: 0 };
233
+ const markers: string[] = [];
234
+ const exportSignals: Array<AbortSignal | undefined> = [];
235
+ const formats = defaultRegistry();
236
+ formats.register({
237
+ id: 'counted-input',
238
+ label: 'Counted input',
239
+ mimeType: 'application/x-counted-input',
240
+ extensions: ['.counted'],
241
+ async importDoc() {
242
+ importCount += 1;
243
+ return parseMarkdown(SAMPLE_MD);
244
+ },
245
+ });
246
+ for (const [id, key] of [
247
+ ['prepared-first', 'first'],
248
+ ['prepared-second', 'second'],
249
+ ] as const) {
250
+ formats.register({
251
+ id,
252
+ label: id,
253
+ mimeType: `application/x-${id}`,
254
+ extensions: [`.${key}`],
255
+ async exportDoc(input, options) {
256
+ exportCounts[key] += 1;
257
+ exportSignals.push(options.signal);
258
+ const targetOptions = options.formatOptions?.[id] as { marker?: string } | undefined;
259
+ markers.push(targetOptions?.marker ?? 'missing');
260
+ expect(input.doc.blocks.length).toBeGreaterThan(0);
261
+ return {
262
+ bytes: new TextEncoder().encode(key),
263
+ mimeType: `application/x-${id}`,
264
+ suggestedFilename: '',
265
+ warnings: [`${key} warning`],
266
+ };
267
+ },
268
+ });
269
+ }
270
+
271
+ const style = { ...resolveTransformStyle('magazine'), id: 'counted-transform' };
272
+ const backingTransforms = createTransformStyleRegistry([style]);
273
+ const transformRegistry = {
274
+ register: (candidate: typeof style) => backingTransforms.register(candidate),
275
+ unregister: (id: string) => backingTransforms.unregister(id),
276
+ get: (id: string) => {
277
+ transformLookupCount += 1;
278
+ return backingTransforms.get(id);
279
+ },
280
+ list: () => backingTransforms.list(),
281
+ };
282
+ const overall = new AbortController();
283
+ const prepared = await prepareConversion(
284
+ {
285
+ kind: 'bytes',
286
+ data: new TextEncoder().encode('count me once'),
287
+ filename: 'source.counted',
288
+ },
289
+ {
290
+ registry: formats,
291
+ from: 'counted-input',
292
+ transformStyle: 'counted-transform',
293
+ transformRegistry,
294
+ signal: overall.signal,
295
+ },
296
+ );
297
+ const first = await prepared.convert('prepared-first', {
298
+ formatOptions: { 'prepared-first': { marker: 'one' } },
299
+ });
300
+ const target = new AbortController();
301
+ const second = await prepared.convert('prepared-second', {
302
+ signal: target.signal,
303
+ formatOptions: { 'prepared-second': { marker: 'two' } },
304
+ });
305
+
306
+ expect(importCount).toBe(1);
307
+ expect(transformLookupCount).toBe(1);
308
+ expect(exportCounts).toEqual({ first: 1, second: 1 });
309
+ expect(markers).toEqual(['one', 'two']);
310
+ expect(exportSignals[0]).toBe(overall.signal);
311
+ expect(exportSignals[1]?.aborted).toBe(false);
312
+ expect(first.suggestedFilename).toBe('source.first');
313
+ expect(second.suggestedFilename).toBe('source.second');
314
+ expect(first.warnings).toContain('first warning');
315
+ expect(second.warnings).toContain('second warning');
316
+
317
+ await expect(prepared.convert('missing-target')).rejects.toMatchObject({
318
+ name: 'ConversionError',
319
+ code: 'unknown-format',
320
+ format: 'missing-target',
321
+ });
322
+ const targetReason = new Error('cancel target export');
323
+ target.abort(targetReason);
324
+ expect(exportSignals[1]?.reason).toBe(targetReason);
325
+ await expect(prepared.convert('prepared-first', { signal: target.signal })).rejects.toBe(
326
+ targetReason,
327
+ );
328
+ const overallReason = new Error('cancel prepared conversion');
329
+ overall.abort(overallReason);
330
+ await expect(
331
+ prepared.convert('prepared-first', { signal: new AbortController().signal }),
332
+ ).rejects.toBe(overallReason);
333
+ expect(exportCounts.first).toBe(1);
334
+ });
335
+
194
336
  it('applies a transform style before handing off to the exporter', async () => {
195
337
  // A capture format records the NormalizedInput it receives, letting us
196
338
  // observe that the transform ran without depending on any converter.
@@ -126,6 +126,23 @@ describe('createPackage / openPackage round-trip', () => {
126
126
  expect(doc?.getElementsByTagName('value')[0]?.textContent).toBe('node');
127
127
  });
128
128
 
129
+ it('ignores an incomplete ambient DOMParser when running in Node', async () => {
130
+ const pkg = createPackage();
131
+ pkg.addPart('word/document.xml', '<doc><value>node</value></doc>', 'application/xml');
132
+ const buffer = await pkg.toArrayBuffer();
133
+
134
+ class IncompleteDomParser {
135
+ parseFromString(): never {
136
+ throw new Error('ambient parser must not be used in Node');
137
+ }
138
+ }
139
+
140
+ vi.stubGlobal('DOMParser', IncompleteDomParser);
141
+ const opened = await openPackage(buffer);
142
+ const doc = await getPartXml(opened, 'word/document.xml');
143
+ expect(doc?.getElementsByTagName('value')[0]?.textContent).toBe('node');
144
+ });
145
+
129
146
  it('applies archive resource limits before parsing OOXML parts', async () => {
130
147
  const pkg = createPackage();
131
148
  pkg.addPart('word/document.xml', '<doc/>', 'application/xml');