@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
@@ -1,5 +1,7 @@
1
1
  /** Narrow EOCD preflight for rejecting record-count bombs before JSZip allocation. */
2
2
 
3
+ import { throwIfZipAborted } from './zipLimits.js';
4
+
3
5
  const END_OF_CENTRAL_DIRECTORY = 0x06054b50;
4
6
  const ZIP64_END_OF_CENTRAL_DIRECTORY = 0x06064b50;
5
7
  const ZIP64_END_LOCATOR = 0x07064b50;
@@ -12,7 +14,9 @@ export type ZipInput = ArrayBuffer | Uint8Array | Blob;
12
14
  /** Materialize Blob input once when possible so preflight bytes feed JSZip too. */
13
15
  export async function prepareZipInput(
14
16
  data: ZipInput,
17
+ signal?: AbortSignal,
15
18
  ): Promise<{ input: ZipInput; bytes?: Uint8Array }> {
19
+ throwIfZipAborted(signal);
16
20
  if (ArrayBuffer.isView(data)) {
17
21
  const bytes = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
18
22
  return { input: bytes, bytes };
@@ -22,7 +26,8 @@ export async function prepareZipInput(
22
26
  return { input: bytes, bytes };
23
27
  }
24
28
 
25
- const bytes = await readBlobBytes(data);
29
+ const bytes = await readBlobBytes(data, signal);
30
+ throwIfZipAborted(signal);
26
31
  return bytes ? { input: bytes, bytes } : { input: data };
27
32
  }
28
33
 
@@ -82,16 +87,65 @@ function isBlobLike(data: ZipInput): data is Blob {
82
87
  return typeof candidate.size === 'number' && typeof candidate.slice === 'function';
83
88
  }
84
89
 
85
- async function readBlobBytes(blob: Blob): Promise<Uint8Array | undefined> {
90
+ async function readBlobBytes(blob: Blob, signal?: AbortSignal): Promise<Uint8Array | undefined> {
86
91
  const arrayBuffer = (blob as Blob & { arrayBuffer?: () => Promise<ArrayBuffer> }).arrayBuffer;
87
92
  if (typeof arrayBuffer === 'function') {
88
- return new Uint8Array(await arrayBuffer.call(blob));
93
+ return new Uint8Array(await raceWithAbort(arrayBuffer.call(blob), signal));
89
94
  }
90
95
  if (typeof FileReader === 'undefined') return undefined;
91
96
  return new Promise((resolve, reject) => {
92
97
  const reader = new FileReader();
93
- reader.onload = () => resolve(new Uint8Array(reader.result as ArrayBuffer));
94
- reader.onerror = () => reject(reader.error ?? new Error('Could not read ZIP blob.'));
98
+ let settled = false;
99
+ const cleanup = (): void => signal?.removeEventListener('abort', handleAbort);
100
+ const finish = (work: () => void): void => {
101
+ if (settled) return;
102
+ settled = true;
103
+ cleanup();
104
+ work();
105
+ };
106
+ const handleAbort = (): void => {
107
+ if (settled) return;
108
+ const reason = signal?.reason ?? new Error('ZIP operation was cancelled');
109
+ // Mark the promise settled before FileReader.abort(): browsers are
110
+ // allowed to dispatch `abort` synchronously and re-enter this handler.
111
+ finish(() => reject(reason));
112
+ try {
113
+ reader.abort();
114
+ } catch {
115
+ // Preserve the caller's reason if a platform reader is already done.
116
+ }
117
+ };
118
+ reader.onload = () => finish(() => resolve(new Uint8Array(reader.result as ArrayBuffer)));
119
+ reader.onerror = () =>
120
+ finish(() => reject(reader.error ?? new Error('Could not read ZIP blob.')));
121
+ reader.onabort = handleAbort;
122
+ signal?.addEventListener('abort', handleAbort, { once: true });
123
+ if (signal?.aborted) {
124
+ handleAbort();
125
+ return;
126
+ }
95
127
  reader.readAsArrayBuffer(blob);
96
128
  });
97
129
  }
130
+
131
+ function raceWithAbort<T>(work: Promise<T>, signal?: AbortSignal): Promise<T> {
132
+ throwIfZipAborted(signal);
133
+ if (!signal) return work;
134
+ return new Promise<T>((resolve, reject) => {
135
+ let settled = false;
136
+ const finish = (complete: () => void): void => {
137
+ if (settled) return;
138
+ settled = true;
139
+ signal.removeEventListener('abort', handleAbort);
140
+ complete();
141
+ };
142
+ const handleAbort = (): void =>
143
+ finish(() => reject(signal.reason ?? new Error('ZIP operation was cancelled')));
144
+ signal.addEventListener('abort', handleAbort, { once: true });
145
+ if (signal.aborted) handleAbort();
146
+ work.then(
147
+ (value) => finish(() => resolve(value)),
148
+ (error: unknown) => finish(() => reject(error)),
149
+ );
150
+ });
151
+ }
@@ -3,6 +3,8 @@
3
3
  import type JSZip from 'jszip';
4
4
 
5
5
  export interface ZipSafetyLimits {
6
+ /** Cooperatively cancel archive opening, validation, and member traversal. */
7
+ signal?: AbortSignal;
6
8
  /** Maximum number of archive records, including directories. Default: 10,000. */
7
9
  maxEntries?: number;
8
10
  /** Maximum uncompressed bytes for one member. Defaults to maxUncompressedBytes. */
@@ -77,6 +79,7 @@ export const DEFAULT_MAX_ZIP_COMPRESSION_RATIO = 1_000;
77
79
  * JSZip normalizes traversal names, so inspect `unsafeOriginalName` too.
78
80
  */
79
81
  export function validateZipArchive(zip: JSZip, limits: ZipSafetyLimits = {}): ValidatedZipEntry[] {
82
+ throwIfZipAborted(limits.signal);
80
83
  const resolved = resolveZipSafetyLimits(limits);
81
84
  const files: ValidatedZipEntry[] = [];
82
85
  let memberCount = 0;
@@ -84,6 +87,7 @@ export function validateZipArchive(zip: JSZip, limits: ZipSafetyLimits = {}): Va
84
87
  let oversizedEntry: { path: string; actual: number; limit: number } | undefined;
85
88
 
86
89
  zip.forEach((relativePath, entry) => {
90
+ throwIfZipAborted(limits.signal);
87
91
  memberCount++;
88
92
  if (entry.dir) return;
89
93
  const originalPath = originalEntryPath(entry, relativePath);
@@ -140,6 +144,12 @@ export function validateZipArchive(zip: JSZip, limits: ZipSafetyLimits = {}): Va
140
144
  return files;
141
145
  }
142
146
 
147
+ /** Preserve the caller's exact cancellation reason across ZIP/OOXML layers. */
148
+ export function throwIfZipAborted(signal?: AbortSignal): void {
149
+ if (!signal?.aborted) return;
150
+ throw signal.reason ?? new Error('ZIP operation was cancelled');
151
+ }
152
+
143
153
  /** Reject a path that could be interpreted outside an archive's logical root. */
144
154
  export function assertSafeZipPath(path: string): void {
145
155
  if (!isSafeArchivePath(path)) {
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/registry/types.ts","../src/shared/fidelity.ts","../src/registry/defaultFormats.ts","../src/registry/registry.ts","../src/registry/convert.ts"],"sourcesContent":["/**\n * Format registry — shared types.\n *\n * The registry is the programmatic heart of `convert()`: it maps a small set of\n * format ids (`md`, `docx`, `pdf`, …) to `FormatDefinition`s, each of which\n * knows how to import to / export from squisq's markdown + Doc model. Every\n * converter module is loaded lazily via `import()` inside the definition\n * methods, so pulling in the registry never eagerly bundles heavy converters.\n */\n\nimport type { Doc, ThemeRegistry } from '@bendyline/squisq/schemas';\nimport type { TransformStyleInput, TransformStyleRegistry } from '@bendyline/squisq/transform';\nimport type { MarkdownDocument } from '@bendyline/squisq/markdown';\nimport type { ContentContainer } from '@bendyline/squisq/storage';\nimport type { ParseOptions, StringifyOptions } from '@bendyline/squisq/markdown';\nimport type { DocxExportOptions } from '../docx/export.js';\nimport type { DocxImportOptions } from '../docx/import.js';\nimport type { PptxExportOptions } from '../pptx/export.js';\nimport type { PptxImportOptions } from '../pptx/import.js';\nimport type { XlsxExportOptions } from '../xlsx/export.js';\nimport type { XlsxImportOptions } from '../xlsx/import.js';\nimport type { CsvExportOptions, CsvImportOptions } from '../csv/index.js';\nimport type { PdfExportOptions } from '../pdf/export.js';\nimport type { PdfImportOptions } from '../pdf/import.js';\nimport type { HtmlExportOptions } from '../html/htmlTemplate.js';\nimport type { HtmlImportOptions } from '../html/import.js';\nimport type { EpubExportOptions } from '../epub/export.js';\nimport type { ZipSafetyLimits } from '../shared/zipSafety.js';\n\n/** A format identifier (e.g. `'docx'`). Strings so hosts can register their own. */\nexport type FormatId = string;\n\n/** The built-in formats the default registry ships with. */\nexport const BUILTIN_FORMAT_IDS = [\n 'md',\n 'docx',\n 'pdf',\n 'pptx',\n 'xlsx',\n 'csv',\n 'html',\n 'htmlzip',\n 'epub',\n 'dbk',\n] as const;\n\n/** The bytes + metadata produced by a successful export. */\nexport interface ConversionResult {\n /** Encoded output bytes. */\n bytes: Uint8Array;\n /** MIME type of the output. */\n mimeType: string;\n /** A sensible download filename (`<baseName>.<ext>`). */\n suggestedFilename: string;\n /** Non-fatal notes accumulated during conversion (may be empty). */\n warnings: string[];\n}\n\nexport interface MarkdownFormatOptions {\n parse?: ParseOptions;\n stringify?: StringifyOptions;\n}\n\n/** Resource limits applied when importing a DBK/ZIP container. */\nexport type DbkFormatOptions = ZipSafetyLimits;\n\n/**\n * Strongly typed option bags for built-in formats. Import and export options\n * share a bag because a single conversion may use the format on either side.\n * Custom registries may add arbitrary keys through the intersection used by\n * {@link ConvertOptions.formatOptions}.\n */\nexport interface BuiltinFormatOptions {\n md: MarkdownFormatOptions;\n docx: DocxImportOptions & DocxExportOptions;\n pptx: PptxImportOptions & PptxExportOptions;\n xlsx: XlsxImportOptions & XlsxExportOptions;\n csv: CsvImportOptions & CsvExportOptions;\n pdf: PdfImportOptions & PdfExportOptions;\n html: HtmlImportOptions & Partial<Omit<HtmlExportOptions, 'playerScript'>>;\n htmlzip: Partial<Omit<HtmlExportOptions, 'playerScript'>>;\n epub: EpubExportOptions;\n dbk: DbkFormatOptions;\n}\n\n/**\n * A source normalized into every shape an exporter might need. `doc` is always\n * present; `markdownDoc` is present when the source was markdown-shaped (an\n * exporter that wants markdown but finds none derives it from `doc`).\n */\nexport interface NormalizedInput {\n doc: Doc;\n markdownDoc?: MarkdownDocument;\n container: ContentContainer;\n baseName: string;\n}\n\n/** Options threaded through `convert()` and into every format method. */\nexport interface ConvertOptions {\n /** Registry to resolve formats against. Defaults to `defaultRegistry()`. */\n registry?: FormatRegistry;\n /** Explicit source format id (skips extension/byte sniffing). */\n from?: FormatId;\n /** Theme id to apply to the exported document. */\n themeId?: string;\n /** Explicit caller-owned registry for non-document custom themes. */\n themeRegistry?: ThemeRegistry;\n /** Built-in/registry id or call-scoped style to apply before export. */\n transformStyle?: TransformStyleInput;\n /** Explicit caller-owned registry used to resolve transform style ids. */\n transformRegistry?: TransformStyleRegistry;\n /** Content-aware auto-templating when deriving a Doc from markdown. */\n autoTemplates?: boolean;\n /** Title hint for exporters that expose document metadata. */\n title?: string;\n /** Lazily resolve the standalone player IIFE bundle (required for HTML export). */\n resolvePlayerScript?: () => Promise<string>;\n /** Typed per-format options for built-ins; custom format ids remain extensible. */\n formatOptions?: Partial<BuiltinFormatOptions> & Record<FormatId, unknown>;\n}\n\n/** Describes how a single format imports to / exports from the squisq model. */\nexport interface FormatDefinition {\n id: FormatId;\n label: string;\n mimeType: string;\n extensions: readonly string[];\n /** Import raw bytes to a MarkdownDocument. */\n importDoc?(data: ArrayBuffer, options: ConvertOptions): Promise<MarkdownDocument>;\n /** Import raw bytes to a ContentContainer (markdown + extracted media). */\n importContainer?(data: ArrayBuffer, options: ConvertOptions): Promise<ContentContainer>;\n /** Export a normalized input to bytes. */\n exportDoc?(input: NormalizedInput, options: ConvertOptions): Promise<ConversionResult>;\n}\n\n/** A mutable collection of format definitions keyed by id. */\nexport interface FormatRegistry {\n register(def: FormatDefinition): void;\n get(id: FormatId): FormatDefinition | undefined;\n byExtension(ext: string): FormatDefinition | undefined;\n list(): FormatDefinition[];\n}\n\n/** The three shapes `convert()` accepts as a source. */\nexport type ConvertSource =\n | { kind: 'bytes'; data: ArrayBuffer | Uint8Array; filename?: string }\n | {\n kind: 'markdown';\n markdown: string | MarkdownDocument;\n container?: ContentContainer;\n baseName?: string;\n }\n | { kind: 'doc'; doc: Doc; container?: ContentContainer; baseName?: string };\n","/**\n * Shared Markdown fidelity reporting for exporters that intentionally support\n * only a subset of the core Markdown AST. Keeping the capability profiles in\n * one exhaustive table prevents each exporter from silently drifting as the\n * core AST grows.\n */\n\nimport type {\n MarkdownBlockNode,\n MarkdownDocument,\n MarkdownInlineNode,\n} from '@bendyline/squisq/markdown';\n\ntype ContentNodeType = MarkdownBlockNode['type'] | MarkdownInlineNode['type'];\nexport type MarkdownExportProfile = 'docx' | 'pdf' | 'pptx' | 'epub';\n\n/**\n * Exhaustive by construction: adding a Markdown node type in core makes this\n * package fail typechecking until its export fidelity is considered here.\n */\nconst CONTENT_NODE_TYPES: Record<ContentNodeType, true> = {\n heading: true,\n paragraph: true,\n blockquote: true,\n list: true,\n code: true,\n thematicBreak: true,\n table: true,\n htmlBlock: true,\n math: true,\n definition: true,\n footnoteDefinition: true,\n containerDirective: true,\n leafDirective: true,\n definitionList: true,\n text: true,\n emphasis: true,\n strong: true,\n delete: true,\n inlineCode: true,\n link: true,\n image: true,\n break: true,\n htmlInline: true,\n inlineMath: true,\n footnoteReference: true,\n linkReference: true,\n imageReference: true,\n textDirective: true,\n mention: true,\n inlineIcon: true,\n};\n\nconst COMMON_SUPPORTED: readonly ContentNodeType[] = [\n 'heading',\n 'paragraph',\n 'blockquote',\n 'list',\n 'code',\n 'thematicBreak',\n 'table',\n 'htmlBlock',\n 'math',\n 'text',\n 'emphasis',\n 'strong',\n 'delete',\n 'inlineCode',\n 'link',\n 'image',\n 'break',\n 'htmlInline',\n 'inlineMath',\n];\n\nconst PROFILE_SUPPORT: Record<MarkdownExportProfile, ReadonlySet<ContentNodeType>> = {\n docx: new Set([...COMMON_SUPPORTED, 'footnoteDefinition', 'footnoteReference']),\n pdf: new Set([...COMMON_SUPPORTED, 'footnoteDefinition', 'footnoteReference']),\n pptx: new Set(COMMON_SUPPORTED),\n epub: new Set(COMMON_SUPPORTED),\n};\n\nconst PROFILE_LABELS: Record<MarkdownExportProfile, string> = {\n docx: 'DOCX',\n pdf: 'PDF',\n pptx: 'PPTX',\n epub: 'EPUB',\n};\n\ninterface AstLikeNode {\n type?: string;\n children?: unknown;\n}\n\n/** Return a user-facing warning when an exporter will omit Markdown nodes. */\nexport function markdownFidelityWarnings(\n document: MarkdownDocument,\n profile: MarkdownExportProfile,\n): string[] {\n const supported = PROFILE_SUPPORT[profile];\n const omitted = new Map<ContentNodeType, number>();\n\n const visit = (candidate: unknown): void => {\n if (!candidate || typeof candidate !== 'object') return;\n const node = candidate as AstLikeNode;\n const type = node.type as ContentNodeType | undefined;\n\n if (type && Object.prototype.hasOwnProperty.call(CONTENT_NODE_TYPES, type)) {\n if (!supported.has(type)) {\n // The exporter drops this whole subtree, so report the highest-fidelity\n // boundary once instead of inflating the count with its descendants.\n omitted.set(type, (omitted.get(type) ?? 0) + 1);\n return;\n }\n }\n\n if (Array.isArray(node.children)) {\n for (const child of node.children) visit(child);\n }\n };\n\n for (const child of document.children) visit(child);\n if (omitted.size === 0) return [];\n\n const total = [...omitted.values()].reduce((sum, count) => sum + count, 0);\n const details = [...omitted].map(([type, count]) => `${type} (${count})`).join(', ');\n return [\n `${PROFILE_LABELS[profile]} export omitted ${total} unsupported Markdown node(s): ${details}.`,\n ];\n}\n","/**\n * Built-in format definitions.\n *\n * Each definition loads its converter module lazily via `import()` inside the\n * method body, so importing the registry never eagerly bundles a heavy\n * converter (pdf-lib, jszip, the OOXML writers, …). The capability of each\n * format — which of import/export it supports — is expressed purely by which\n * methods are present.\n */\n\nimport type { ContentContainer } from '@bendyline/squisq/storage';\nimport type { MarkdownDocument } from '@bendyline/squisq/markdown';\nimport { ConversionError } from './errors.js';\nimport { markdownFidelityWarnings } from '../shared/fidelity.js';\nimport type {\n ConversionResult,\n BuiltinFormatOptions,\n ConvertOptions,\n FormatDefinition,\n NormalizedInput,\n} from './types.js';\n\n// ── MIME constants ──────────────────────────────────────────────────\n\nconst MIME = {\n md: 'text/markdown',\n docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n pdf: 'application/pdf',\n pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n csv: 'text/csv',\n html: 'text/html',\n zip: 'application/zip',\n epub: 'application/epub+zip',\n} as const;\n\n// ── Small shared helpers ────────────────────────────────────────────\n\n/** Normalize any binary export return shape to Uint8Array. */\nasync function toBytes(data: ArrayBuffer | Uint8Array | Blob): Promise<Uint8Array> {\n if (data instanceof Uint8Array) return data;\n if (data instanceof ArrayBuffer) return new Uint8Array(data);\n // Blob. Prefer the modern arrayBuffer() method; fall back to FileReader for\n // environments (e.g. some jsdom builds) whose Blob lacks it.\n if (typeof data.arrayBuffer === 'function') {\n return new Uint8Array(await data.arrayBuffer());\n }\n const buffer = await new Promise<ArrayBuffer>((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(reader.result as ArrayBuffer);\n reader.onerror = () => reject(reader.error);\n reader.readAsArrayBuffer(data);\n });\n return new Uint8Array(buffer);\n}\n\n/** The theme to apply: explicit option wins, then the doc's own theme. */\nfunction resolveThemeId(input: NormalizedInput, options: ConvertOptions): string | undefined {\n return options.themeId ?? input.doc.themeId;\n}\n\nfunction optionsFor<K extends keyof BuiltinFormatOptions>(\n options: ConvertOptions,\n id: K,\n): BuiltinFormatOptions[K] {\n return (options.formatOptions?.[id] ?? {}) as BuiltinFormatOptions[K];\n}\n\n/** The markdown shape an exporter needs — reuse the source's, else derive it. */\nasync function markdownOf(input: NormalizedInput): Promise<MarkdownDocument> {\n if (input.markdownDoc) return input.markdownDoc;\n const { docToMarkdown } = await import('@bendyline/squisq/doc');\n return docToMarkdown(input.doc);\n}\n\n/**\n * Collect image files from a container, keyed by both their container path and\n * their bare filename. Exporters that resolve by url (PPTX) and the standalone\n * player (HTML) both match against one of those two keys.\n */\nasync function collectContainerImages(\n container: ContentContainer,\n): Promise<Map<string, ArrayBuffer>> {\n const images = new Map<string, ArrayBuffer>();\n const files = await container.listFiles();\n for (const file of files) {\n if (!/\\.(jpg|jpeg|png|gif|webp|svg|bmp|avif)$/i.test(file.path)) continue;\n const data = await container.readFile(file.path);\n if (!data) continue;\n images.set(file.path, data);\n const slash = file.path.lastIndexOf('/');\n if (slash !== -1) images.set(file.path.slice(slash + 1), data);\n }\n return images;\n}\n\nasync function collectContainerDocxImages(\n container: ContentContainer,\n): Promise<Map<string, { data: ArrayBuffer; contentType: string }>> {\n const images = await collectContainerImages(container);\n const { extToMime } = await import('../shared/images.js');\n return new Map(\n [...images].map(([path, data]) => [\n path,\n { data, contentType: extToMime(path.split('.').pop() ?? '') },\n ]),\n );\n}\n\n/** Copy a container and make its primary document match the normalized source. */\nasync function snapshotContainerWithDocument(input: NormalizedInput): Promise<ContentContainer> {\n const { MemoryContentContainer } = await import('@bendyline/squisq/storage');\n const snapshot = new MemoryContentContainer();\n const entries = await input.container.listFiles();\n for (const entry of entries) {\n const data = await input.container.readFile(entry.path);\n if (data) await snapshot.writeFile(entry.path, new Uint8Array(data), entry.mimeType);\n }\n const { stringifyMarkdown } = await import('@bendyline/squisq/markdown');\n const documentPath = (await input.container.getDocumentPath()) ?? 'index.md';\n await snapshot.writeDocument(stringifyMarkdown(await markdownOf(input)), documentPath);\n return snapshot;\n}\n\n/** Resolve the player IIFE bundle or throw a helpful missing-dependency error. */\nasync function requirePlayerScript(options: ConvertOptions, format: string): Promise<string> {\n const script = await options.resolvePlayerScript?.();\n if (!script) {\n throw new ConversionError('missing-dependency', 'HTML export needs a player script.', {\n format,\n hint: \"pass resolvePlayerScript, e.g. () => import('@bendyline/squisq-react/standalone-source').then(m => m.PLAYER_BUNDLE)\",\n });\n }\n return script;\n}\n\nfunction ok(bytes: Uint8Array, mimeType: string, warnings: string[] = []): ConversionResult {\n // suggestedFilename is filled in by convert() once the baseName is known.\n return { bytes, mimeType, suggestedFilename: '', warnings };\n}\n\n/**\n * Narrow the untyped per-format escape hatch (`options.formatOptions.pptx`)\n * into the PPTX importer's options. Theme + layout inference default ON;\n * only an explicit `false` disables them.\n */\nfunction pptxImportOptionsFrom(options: ConvertOptions): BuiltinFormatOptions['pptx'] {\n const raw = optionsFor(options, 'pptx');\n return {\n ...raw,\n inferTheme: raw?.inferTheme !== false,\n inferLayouts: raw?.inferLayouts !== false,\n };\n}\n\n// ── Definitions ─────────────────────────────────────────────────────\n\nexport function defaultFormats(): FormatDefinition[] {\n const md: FormatDefinition = {\n id: 'md',\n label: 'Markdown',\n mimeType: MIME.md,\n extensions: ['.md', '.markdown'],\n async importDoc(data, options): Promise<MarkdownDocument> {\n const { parseMarkdown } = await import('@bendyline/squisq/markdown');\n return parseMarkdown(new TextDecoder().decode(data), optionsFor(options, 'md').parse);\n },\n async exportDoc(input, options): Promise<ConversionResult> {\n const { stringifyMarkdown } = await import('@bendyline/squisq/markdown');\n const text = stringifyMarkdown(await markdownOf(input), optionsFor(options, 'md').stringify);\n return ok(new TextEncoder().encode(text), MIME.md);\n },\n };\n\n const docx: FormatDefinition = {\n id: 'docx',\n label: 'Word (DOCX)',\n mimeType: MIME.docx,\n extensions: ['.docx'],\n async importContainer(data, options): Promise<ContentContainer> {\n const { docxToContainer } = await import('../docx/index.js');\n return docxToContainer(data, optionsFor(options, 'docx'));\n },\n async importDoc(data, options): Promise<MarkdownDocument> {\n const { docxToMarkdownDoc } = await import('../docx/index.js');\n return docxToMarkdownDoc(data, optionsFor(options, 'docx'));\n },\n async exportDoc(input, options): Promise<ConversionResult> {\n const { markdownDocToDocx } = await import('../docx/index.js');\n const raw = optionsFor(options, 'docx');\n const markdownDoc = await markdownOf(input);\n const containerImages = await collectContainerDocxImages(input.container);\n const images = new Map([...containerImages, ...(raw.images ?? new Map())]);\n const buf = await markdownDocToDocx(markdownDoc, {\n ...raw,\n ...(options.title !== undefined ? { title: options.title } : {}),\n themeId: resolveThemeId(input, options),\n themeRegistry: options.themeRegistry ?? raw.themeRegistry,\n images,\n });\n return ok(await toBytes(buf), MIME.docx, markdownFidelityWarnings(markdownDoc, 'docx'));\n },\n };\n\n const pdf: FormatDefinition = {\n id: 'pdf',\n label: 'PDF',\n mimeType: MIME.pdf,\n extensions: ['.pdf'],\n async importContainer(data, options): Promise<ContentContainer> {\n const { pdfToContainer } = await import('../pdf/index.js');\n return pdfToContainer(data, optionsFor(options, 'pdf'));\n },\n async importDoc(data, options): Promise<MarkdownDocument> {\n const { pdfToMarkdownDoc } = await import('../pdf/index.js');\n return pdfToMarkdownDoc(data, optionsFor(options, 'pdf'));\n },\n async exportDoc(input, options): Promise<ConversionResult> {\n const { markdownDocToPdf } = await import('../pdf/index.js');\n const raw = optionsFor(options, 'pdf');\n const markdownDoc = await markdownOf(input);\n const buf = await markdownDocToPdf(markdownDoc, {\n ...raw,\n ...(options.title !== undefined ? { title: options.title } : {}),\n themeId: resolveThemeId(input, options),\n themeRegistry: options.themeRegistry ?? raw.themeRegistry,\n });\n return ok(await toBytes(buf), MIME.pdf, markdownFidelityWarnings(markdownDoc, 'pdf'));\n },\n };\n\n const pptx: FormatDefinition = {\n id: 'pptx',\n label: 'PowerPoint (PPTX)',\n mimeType: MIME.pptx,\n extensions: ['.pptx'],\n async importContainer(data, options): Promise<ContentContainer> {\n const { pptxToContainer } = await import('../pptx/index.js');\n return pptxToContainer(data, pptxImportOptionsFrom(options));\n },\n async importDoc(data, options): Promise<MarkdownDocument> {\n const { pptxToMarkdownDoc } = await import('../pptx/index.js');\n return pptxToMarkdownDoc(data, pptxImportOptionsFrom(options));\n },\n async exportDoc(input, options): Promise<ConversionResult> {\n const { markdownDocToPptx } = await import('../pptx/index.js');\n const raw = optionsFor(options, 'pptx');\n const markdownDoc = await markdownOf(input);\n const containerImages = await collectContainerImages(input.container);\n const images = new Map([...containerImages, ...(raw.images ?? new Map())]);\n const buf = await markdownDocToPptx(markdownDoc, {\n ...raw,\n ...(options.title !== undefined ? { title: options.title } : {}),\n themeId: resolveThemeId(input, options),\n themeRegistry: options.themeRegistry ?? raw.themeRegistry,\n images,\n });\n return ok(await toBytes(buf), MIME.pptx, markdownFidelityWarnings(markdownDoc, 'pptx'));\n },\n };\n\n const xlsx: FormatDefinition = {\n id: 'xlsx',\n label: 'Excel (XLSX)',\n mimeType: MIME.xlsx,\n extensions: ['.xlsx'],\n async importDoc(data, options): Promise<MarkdownDocument> {\n const { xlsxToMarkdownDoc } = await import('../xlsx/index.js');\n return xlsxToMarkdownDoc(data, optionsFor(options, 'xlsx'));\n },\n async exportDoc(input, options): Promise<ConversionResult> {\n const { markdownDocToXlsx } = await import('../xlsx/index.js');\n const markdownDoc = await markdownOf(input);\n // XLSX fidelity is tables-only: `table` nodes become worksheets and\n // headings name them, but every other top-level block (prose, lists,\n // images, code, …) is dropped. Count those and warn honestly.\n const omitted = markdownDoc.children.filter(\n (n) => n.type !== 'table' && n.type !== 'heading',\n ).length;\n const warnings =\n omitted > 0\n ? [`XLSX export is tables-only; ${omitted} non-table block(s) were omitted.`]\n : [];\n const blob = await markdownDocToXlsx(markdownDoc, {\n ...optionsFor(options, 'xlsx'),\n ...(options.title !== undefined ? { title: options.title } : {}),\n });\n return ok(await toBytes(blob), MIME.xlsx, warnings);\n },\n };\n\n const csv: FormatDefinition = {\n id: 'csv',\n label: 'CSV',\n mimeType: MIME.csv,\n extensions: ['.csv'],\n async importDoc(data, options): Promise<MarkdownDocument> {\n const { csvToMarkdownDoc } = await import('../csv/index.js');\n return csvToMarkdownDoc(data, optionsFor(options, 'csv'));\n },\n async exportDoc(input, options): Promise<ConversionResult> {\n const { markdownDocToCsv } = await import('../csv/index.js');\n const markdownDoc = await markdownOf(input);\n const raw = optionsFor(options, 'csv');\n const tableCount = markdownDoc.children.filter((n) => n.type === 'table').length;\n const warnings: string[] = [];\n if (tableCount > 1 && raw.tableIndex === undefined) {\n warnings.push(\n `Document has ${tableCount} tables; CSV export emitted only the first. Use the csv converter's tableIndex option to select another.`,\n );\n }\n const text = markdownDocToCsv(markdownDoc, raw);\n return ok(new TextEncoder().encode(text), MIME.csv, warnings);\n },\n };\n\n const html: FormatDefinition = {\n id: 'html',\n label: 'HTML (single file)',\n mimeType: MIME.html,\n extensions: ['.html', '.htm'],\n async importDoc(data, options): Promise<MarkdownDocument> {\n const { htmlToMarkdownDoc } = await import('../html/index.js');\n return htmlToMarkdownDoc(data, optionsFor(options, 'html'));\n },\n // importContainer omitted: HTML import already inlines images as data URIs,\n // so there is nothing to extract into a container this wave.\n async exportDoc(input, options): Promise<ConversionResult> {\n const playerScript = await requirePlayerScript(options, 'html');\n const { docToHtml } = await import('../html/index.js');\n const raw = optionsFor(options, 'html');\n const containerImages = await collectContainerImages(input.container);\n const images = new Map([...containerImages, ...(raw.images ?? new Map())]);\n const htmlText = docToHtml(input.doc, {\n ...raw,\n playerScript,\n images,\n title: options.title ?? input.baseName,\n mode: raw.mode ?? 'static',\n themeId: resolveThemeId(input, options),\n themeRegistry: options.themeRegistry ?? raw.themeRegistry,\n });\n return ok(new TextEncoder().encode(htmlText), MIME.html);\n },\n };\n\n const htmlzip: FormatDefinition = {\n id: 'htmlzip',\n label: 'HTML (ZIP archive)',\n mimeType: MIME.zip,\n extensions: ['.html.zip'],\n async exportDoc(input, options): Promise<ConversionResult> {\n const playerScript = await requirePlayerScript(options, 'htmlzip');\n const { docToHtmlZip } = await import('../html/index.js');\n const raw = optionsFor(options, 'htmlzip');\n const containerImages = await collectContainerImages(input.container);\n const images = new Map([...containerImages, ...(raw.images ?? new Map())]);\n const blob = await docToHtmlZip(input.doc, {\n ...raw,\n playerScript,\n images,\n title: options.title ?? input.baseName,\n mode: raw.mode ?? 'static',\n themeId: resolveThemeId(input, options),\n themeRegistry: options.themeRegistry ?? raw.themeRegistry,\n });\n return ok(await toBytes(blob), MIME.zip);\n },\n };\n\n const epub: FormatDefinition = {\n id: 'epub',\n label: 'EPUB',\n mimeType: MIME.epub,\n extensions: ['.epub'],\n async exportDoc(input, options): Promise<ConversionResult> {\n const { markdownDocToEpub } = await import('../epub/index.js');\n const raw = optionsFor(options, 'epub');\n const markdownDoc = await markdownOf(input);\n const containerImages = await collectContainerImages(input.container);\n const images = new Map([...containerImages, ...(raw.images ?? new Map())]);\n const buf = await markdownDocToEpub(markdownDoc, {\n ...raw,\n title: options.title ?? input.baseName,\n themeId: resolveThemeId(input, options),\n themeRegistry: options.themeRegistry ?? raw.themeRegistry,\n images,\n });\n return ok(await toBytes(buf), MIME.epub, markdownFidelityWarnings(markdownDoc, 'epub'));\n },\n };\n\n const dbk: FormatDefinition = {\n id: 'dbk',\n label: 'Squisq container (DBK)',\n mimeType: MIME.zip,\n extensions: ['.dbk', '.zip'],\n async importContainer(data, options): Promise<ContentContainer> {\n const { zipToContainer } = await import('../container/index.js');\n return zipToContainer(data, optionsFor(options, 'dbk'));\n },\n async exportDoc(input): Promise<ConversionResult> {\n const { containerToZip } = await import('../container/index.js');\n const blob = await containerToZip(await snapshotContainerWithDocument(input));\n return ok(await toBytes(blob), MIME.zip);\n },\n };\n\n return [md, docx, pdf, pptx, xlsx, csv, html, htmlzip, epub, dbk];\n}\n","/**\n * Format registry implementation.\n *\n * `createRegistry()` returns an empty, mutable registry (last-write-wins by id);\n * `defaultRegistry()` returns one preloaded with every built-in format.\n */\n\nimport type { FormatDefinition, FormatId, FormatRegistry } from './types.js';\nimport { defaultFormats } from './defaultFormats.js';\n\n/** Normalize an extension to lowercase, without a leading dot. */\nfunction normalizeExt(ext: string): string {\n return ext.replace(/^\\.+/, '').toLowerCase();\n}\n\n/** Create an empty registry. Registering an existing id overwrites it. */\nexport function createRegistry(): FormatRegistry {\n const byId = new Map<FormatId, FormatDefinition>();\n\n return {\n register(def: FormatDefinition): void {\n byId.set(def.id, def);\n },\n get(id: FormatId): FormatDefinition | undefined {\n return byId.get(id);\n },\n byExtension(ext: string): FormatDefinition | undefined {\n const target = normalizeExt(ext);\n if (!target) return undefined;\n for (const def of byId.values()) {\n if (def.extensions.some((e) => normalizeExt(e) === target)) return def;\n }\n return undefined;\n },\n list(): FormatDefinition[] {\n return [...byId.values()];\n },\n };\n}\n\n/** Create a registry preloaded with all built-in formats. */\nexport function defaultRegistry(): FormatRegistry {\n const registry = createRegistry();\n for (const def of defaultFormats()) {\n registry.register(def);\n }\n return registry;\n}\n","/**\n * Programmatic `convert()` — the format-registry front door.\n *\n * Normalizes any {@link ConvertSource} into a {@link NormalizedInput} (always\n * yielding a `Doc`, keeping the `MarkdownDocument` when the source was\n * markdown-shaped, and always carrying a `ContentContainer` for media), applies\n * an optional transform, then hands off to the target format's exporter.\n */\n\nimport type { MarkdownDocument } from '@bendyline/squisq/markdown';\nimport type { ContentContainer } from '@bendyline/squisq/storage';\nimport type { TransformStyleInput, TransformStyleRegistry } from '@bendyline/squisq/transform';\nimport { ConversionError } from './errors.js';\nimport { defaultRegistry } from './registry.js';\nimport { openBoundedZipArchive, ZipSafetyError } from '../shared/zipSafety.js';\nimport type {\n BuiltinFormatOptions,\n ConversionResult,\n ConvertOptions,\n ConvertSource,\n FormatDefinition,\n FormatId,\n FormatRegistry,\n NormalizedInput,\n} from './types.js';\n\nfunction markdownFormatOptions(options: ConvertOptions): BuiltinFormatOptions['md'] {\n return (options.formatOptions?.md ?? {}) as BuiltinFormatOptions['md'];\n}\n\n// ── Byte sniffing ───────────────────────────────────────────────────\n\nfunction hasPrefix(bytes: Uint8Array, prefix: number[]): boolean {\n if (bytes.length < prefix.length) return false;\n for (let i = 0; i < prefix.length; i++) {\n if (bytes[i] !== prefix[i]) return false;\n }\n return true;\n}\n\nconst ZIP_MAGIC = [0x50, 0x4b, 0x03, 0x04]; // \"PK\\x03\\x04\"\nconst PDF_MAGIC = [0x25, 0x50, 0x44, 0x46]; // \"%PDF\"\n\n/**\n * Disambiguate a ZIP-based file. OOXML formats (docx/pptx/xlsx) all carry a\n * `[Content_Types].xml` whose content-type strings name the flavor; a squisq\n * container (.dbk) is a plain ZIP with no such part, so absence of the OOXML\n * marker means `dbk`.\n */\nasync function sniffZip(bytes: Uint8Array): Promise<FormatId> {\n const archive = await openBoundedZipArchive(bytes).catch((cause: unknown) => {\n if (cause instanceof ZipSafetyError && cause.code !== 'invalid-archive') throw cause;\n throw new ConversionError('invalid-input', 'Input is not a readable ZIP archive.', { cause });\n });\n const contentTypes = archive.entries.find((entry) => entry.path === '[Content_Types].xml');\n if (!contentTypes) return 'dbk';\n const maxContentTypesBytes = 1024 * 1024;\n if ((contentTypes.declaredSize ?? 0) > maxContentTypesBytes) {\n throw new ConversionError('invalid-input', 'OOXML content-types metadata is too large.');\n }\n const xmlBytes = await archive.read(contentTypes.path, maxContentTypesBytes);\n if (!xmlBytes) return 'dbk';\n const xml = new TextDecoder().decode(xmlBytes);\n if (xml.includes('wordprocessingml')) return 'docx';\n if (xml.includes('presentationml')) return 'pptx';\n if (xml.includes('spreadsheetml')) return 'xlsx';\n return 'dbk';\n}\n\n/** Determine the source format for raw bytes. */\nasync function detectByteFormat(\n bytes: Uint8Array,\n filename: string | undefined,\n options: ConvertOptions,\n registry: FormatRegistry,\n): Promise<FormatId> {\n if (options.from) return options.from;\n\n const ext = filename ? extractExt(filename) : undefined;\n if (ext) {\n const byExt = registry.byExtension(ext);\n if (byExt) return byExt.id;\n }\n\n if (hasPrefix(bytes, PDF_MAGIC)) return 'pdf';\n if (hasPrefix(bytes, ZIP_MAGIC)) return sniffZip(bytes);\n\n // No magic and no recognized extension → assume UTF-8 markdown.\n return 'md';\n}\n\n// ── Filename helpers ────────────────────────────────────────────────\n\n/** Lowercased extension without the leading dot (`report.DocX` → `docx`). */\nfunction extractExt(filename: string): string {\n const normalized = filename.replace(/\\\\/g, '/');\n const base = normalized.split('/').pop() ?? normalized;\n const dot = base.lastIndexOf('.');\n if (dot <= 0) return '';\n return base.slice(dot + 1).toLowerCase();\n}\n\n/** Basename without its final extension (`a/b/report.docx` → `report`). */\nfunction baseNameOf(filename: string): string {\n const normalized = filename.replace(/\\\\/g, '/');\n const base = normalized.split('/').pop() ?? normalized;\n const dot = base.lastIndexOf('.');\n return dot > 0 ? base.slice(0, dot) : base;\n}\n\n// ── Normalization ───────────────────────────────────────────────────\n\ninterface Normalized {\n input: NormalizedInput;\n warnings: string[];\n}\n\nasync function normalizeBytes(\n source: Extract<ConvertSource, { kind: 'bytes' }>,\n options: ConvertOptions,\n registry: FormatRegistry,\n): Promise<Normalized> {\n const bytes = source.data instanceof Uint8Array ? source.data : new Uint8Array(source.data);\n const buffer = bytes.buffer.slice(\n bytes.byteOffset,\n bytes.byteOffset + bytes.byteLength,\n ) as ArrayBuffer;\n\n const fromId = await detectByteFormat(bytes, source.filename, options, registry);\n const fromDef = registry.get(fromId);\n if (!fromDef) {\n throw new ConversionError('unknown-format', `Unknown source format \"${fromId}\".`, {\n format: fromId,\n });\n }\n if (!fromDef.importContainer && !fromDef.importDoc) {\n throw new ConversionError(\n 'unsupported-input',\n `Format \"${fromDef.label}\" cannot be used as a conversion source.`,\n {\n format: fromId,\n hint: 'This format is export-only.',\n },\n );\n }\n\n const { markdownToDoc } = await import('@bendyline/squisq/doc');\n const { parseMarkdown, stringifyMarkdown } = await import('@bendyline/squisq/markdown');\n\n const warnings: string[] = [];\n let markdownDoc: MarkdownDocument;\n let container: ContentContainer;\n\n if (fromDef.importContainer) {\n container = await fromDef.importContainer(buffer, options);\n // PDF embedded-image extraction needs a browser canvas; under Node it's\n // skipped inside pdfToContainer. importContainer has no warnings channel of\n // its own, so surface that degraded path here where warnings are collected.\n if (fromDef.id === 'pdf' && typeof document === 'undefined') {\n warnings.push(\n 'PDF embedded images were skipped — image decoding requires a browser canvas (running under Node).',\n );\n }\n const text = await container.readDocument();\n markdownDoc = text\n ? parseMarkdown(text, markdownFormatOptions(options).parse)\n : { type: 'document', children: [] };\n } else {\n // importDoc is guaranteed present by the guard above.\n markdownDoc = await fromDef.importDoc!(buffer, options);\n const { MemoryContentContainer } = await import('@bendyline/squisq/storage');\n const mem = new MemoryContentContainer();\n await mem.writeDocument(stringifyMarkdown(markdownDoc));\n container = mem;\n }\n\n const doc = markdownToDoc(markdownDoc, { autoTemplates: options.autoTemplates });\n const baseName = source.filename ? baseNameOf(source.filename) : 'document';\n\n return {\n input: { doc, markdownDoc, container, baseName },\n warnings,\n };\n}\n\nasync function normalizeMarkdown(\n source: Extract<ConvertSource, { kind: 'markdown' }>,\n options: ConvertOptions,\n): Promise<Normalized> {\n const { markdownToDoc } = await import('@bendyline/squisq/doc');\n const { parseMarkdown } = await import('@bendyline/squisq/markdown');\n\n const { stringifyMarkdown } = await import('@bendyline/squisq/markdown');\n\n const markdownDoc =\n typeof source.markdown === 'string'\n ? parseMarkdown(source.markdown, markdownFormatOptions(options).parse)\n : source.markdown;\n\n let container = source.container;\n if (!container) {\n // Seed a fresh container with the document so container-backed exports\n // (dbk) and media resolution have the markdown to serialize.\n const { MemoryContentContainer } = await import('@bendyline/squisq/storage');\n const mem = new MemoryContentContainer();\n await mem.writeDocument(stringifyMarkdown(markdownDoc));\n container = mem;\n }\n\n const doc = markdownToDoc(markdownDoc, { autoTemplates: options.autoTemplates });\n const baseName = source.baseName ?? 'document';\n\n return { input: { doc, markdownDoc, container, baseName }, warnings: [] };\n}\n\nasync function normalizeDoc(source: Extract<ConvertSource, { kind: 'doc' }>): Promise<Normalized> {\n let container = source.container;\n if (!container) {\n const { MemoryContentContainer } = await import('@bendyline/squisq/storage');\n const { docToMarkdown } = await import('@bendyline/squisq/doc');\n const { stringifyMarkdown } = await import('@bendyline/squisq/markdown');\n const mem = new MemoryContentContainer();\n await mem.writeDocument(stringifyMarkdown(docToMarkdown(source.doc)));\n container = mem;\n }\n const baseName = source.baseName ?? 'document';\n // markdownDoc is intentionally omitted — exporters derive it lazily via docToMarkdown.\n return { input: { doc: source.doc, container, baseName }, warnings: [] };\n}\n\nasync function normalize(\n source: ConvertSource,\n options: ConvertOptions,\n registry: FormatRegistry,\n): Promise<Normalized> {\n switch (source.kind) {\n case 'bytes':\n return normalizeBytes(source, options, registry);\n case 'markdown':\n return normalizeMarkdown(source, options);\n case 'doc':\n return normalizeDoc(source);\n }\n}\n\n// ── Transform ───────────────────────────────────────────────────────\n\nasync function applyTransformStyle(\n input: NormalizedInput,\n transformStyle: TransformStyleInput,\n themeId?: string,\n registry?: TransformStyleRegistry,\n): Promise<string[]> {\n const { applyTransform, extractDocImages } = await import('@bendyline/squisq/transform');\n const { docToMarkdown, markdownToDoc } = await import('@bendyline/squisq/doc');\n const images = extractDocImages(input.doc.blocks);\n const result = applyTransform(input.doc, transformStyle, { themeId, images, registry });\n input.doc = result.doc;\n const markdownDoc = docToMarkdown(result.doc);\n input.markdownDoc = markdownDoc;\n\n // Lossy-path detection: transforms can emit template blocks whose data lives\n // in template inputs rather than in round-trippable markdown `contents`, so\n // `docToMarkdown` silently drops them. Re-parse with auto-templating off (so\n // the comparison stays ~1:1 and isn't confused by content-aware promotion)\n // and compare block counts. Best-effort — most blocks carry `contents` and\n // round-trip fine, so this only fires on a genuine collapse.\n const roundTripped = markdownToDoc(markdownDoc, { autoTemplates: false });\n if (roundTripped.blocks.length < result.doc.blocks.length) {\n return [\n 'Transform produced blocks that don’t round-trip to markdown; export may be incomplete.',\n ];\n }\n return [];\n}\n\n// ── convert() ───────────────────────────────────────────────────────\n\n/**\n * Convert a source document to a target format.\n *\n * @param source - A bytes / markdown / doc source.\n * @param to - The target format id (must be registered and support export).\n * @param options - Conversion options (registry, theme, transform, …).\n * @throws {@link ConversionError} on any failure, with a stable `code`.\n */\nexport async function convert(\n source: ConvertSource,\n to: FormatId,\n options: ConvertOptions = {},\n): Promise<ConversionResult> {\n const registry = options.registry ?? defaultRegistry();\n\n const target: FormatDefinition | undefined = registry.get(to);\n if (!target) {\n throw new ConversionError('unknown-format', `Unknown target format \"${to}\".`, { format: to });\n }\n if (!target.exportDoc) {\n throw new ConversionError(\n 'unsupported-output',\n `Format \"${target.label}\" does not support export.`,\n { format: to, hint: 'This format is import-only.' },\n );\n }\n\n let normalized: Normalized;\n try {\n normalized = await normalize(source, options, registry);\n } catch (err: unknown) {\n if (err instanceof ConversionError) throw err;\n const message = err instanceof Error ? err.message : String(err);\n throw new ConversionError('invalid-input', message, {\n format: options.from,\n cause: err,\n });\n }\n const { input, warnings } = normalized;\n\n // Respect an existing doc theme; only fill it in from options when absent.\n if (options.themeId && !input.doc.themeId) {\n input.doc = { ...input.doc, themeId: options.themeId };\n }\n\n let result: ConversionResult;\n try {\n if (options.transformStyle) {\n warnings.push(\n ...(await applyTransformStyle(\n input,\n options.transformStyle,\n options.themeId ?? input.doc.themeId,\n options.transformRegistry,\n )),\n );\n }\n result = await target.exportDoc(input, options);\n } catch (err: unknown) {\n if (err instanceof ConversionError) throw err;\n const message = err instanceof Error ? err.message : String(err);\n throw new ConversionError('conversion-failed', message, { format: to, cause: err });\n }\n\n const ext = target.extensions[0]?.replace(/^\\.+/, '') ?? to;\n return {\n ...result,\n suggestedFilename: `${input.baseName}.${ext}`,\n warnings: [...warnings, ...result.warnings],\n };\n}\n"],"mappings":"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","names":["document"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/pptx/layouts.ts"],"sourcesContent":["/**\n * PPTX slide-layout inference — reads the layouts/masters a deck actually\n * uses and, per layout, either matches it to a close built-in Squisq\n * template (title, sectionHeader, twoColumn, leftFeature, …) or generates a\n * reusable `CustomTemplateDefinition` from its placeholder geometry.\n *\n * The classifier is a deterministic three-stage waterfall — the layout's\n * `type` attribute, then well-known layout names, then placeholder-set\n * geometry — biased toward *not* templating: a title over a single body\n * flows better as plain markdown, and only genuinely distinctive geometry\n * (side-by-side content, positioned picture placeholders) becomes a custom\n * template.\n *\n * Shared by the PPTX importer (`inferLayouts`) and the theme dialog's\n * `inspectPptxLayouts` — one implementation, two consumers.\n */\n\nimport type {\n CustomTemplateDefinition,\n CustomTemplateLayer,\n ImageLayer,\n Position,\n ShapeLayer,\n TextLayer,\n TextStyle,\n} from '@bendyline/squisq/schemas';\nimport { getPartRelationships, getPartXml, openPackage } from '../ooxml/reader.js';\nimport type { OoxmlOpenOptions } from '../ooxml/reader.js';\nimport type { OoxmlPackage } from '../ooxml/types.js';\nimport {\n CONTENT_TYPE_PPTX_SLIDE_LAYOUT,\n NS_DRAWINGML,\n NS_PML,\n NS_R,\n REL_SLIDE_LAYOUT,\n REL_SLIDE_MASTER,\n} from '../ooxml/namespaces.js';\nimport { attrNS, baseDirOf, findRelByType, resolveTarget } from '../ooxml/readUtils.js';\n\n// ── Public types ─────────────────────────────────────────────────────\n\nexport interface EmuRect {\n x: number;\n y: number;\n cx: number;\n cy: number;\n}\n\n/** Percent-of-slide rect, 0–100 per axis (2-decimal precision). */\nexport interface PctRect {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\nexport type PlaceholderKind =\n | 'title'\n | 'subtitle'\n | 'text'\n | 'picture'\n | 'table'\n | 'chart'\n | 'other';\n\nexport interface PlaceholderTextStyle {\n fontSizePt?: number;\n bold?: boolean;\n align?: 'left' | 'center' | 'right';\n anchor?: 'top' | 'middle' | 'bottom';\n}\n\nexport interface ExtractedPlaceholder {\n kind: PlaceholderKind;\n /** `p:ph@type` verbatim ('' when absent — spec default is body). */\n rawType: string;\n /** `p:ph@idx`, default 0. */\n idx: number;\n /** Geometry resolved through the layout→master inheritance chain. */\n rect: PctRect;\n inheritedFromMaster: boolean;\n vertical: boolean;\n textStyle?: PlaceholderTextStyle;\n}\n\nexport interface ExtractedDecoration {\n shape: 'rect' | 'line';\n rect: PctRect;\n fill?: string;\n stroke?: string;\n strokeWidthPx?: number;\n borderRadius?: number;\n}\n\nexport interface ExtractedSlideLayout {\n partPath: string;\n /** `p:cSld@name` ('' when absent). */\n name: string;\n /** `p:sldLayout@type` (ST_SlideLayoutType) when present. */\n typeAttr?: string;\n masterPath?: string;\n masterName?: string;\n /** Content placeholders — dt/ftr/sldNum/hdr chrome already excluded. */\n placeholders: ExtractedPlaceholder[];\n decorations: ExtractedDecoration[];\n /** Number of slides in this deck using this layout (0 = defined but unused). */\n slideCount: number;\n}\n\n/** Scheme-color hints for decoration fills, supplied by theme extraction. */\nexport interface PptxColorHints {\n text?: string;\n background?: string;\n /** `a:schemeClr@val` (accent1…, bg1, tx1, dk1, …) → resolved hex. */\n schemeColors?: Record<string, string>;\n}\n\nexport type BuiltinParamSpec =\n | 'titleSubtitle'\n | 'comparisonPairs'\n | 'featureImage'\n | 'photoGridGate';\n\nexport type LayoutVerdict =\n | { kind: 'plain' }\n | { kind: 'skip' }\n | {\n kind: 'builtin';\n template: string;\n paramSpec?: BuiltinParamSpec;\n /** For `comparisonPairs`: placeholder idx lists per column, top-to-bottom. */\n columns?: { left: number[]; right: number[] };\n }\n | { kind: 'custom'; def: CustomTemplateDefinition };\n\nexport interface AnalyzedLayout {\n extracted: ExtractedSlideLayout;\n verdict: LayoutVerdict;\n /** Human-readable caveats: dropped regions, unsupported placeholders, … */\n notes: string[];\n}\n\nexport interface PptxLayoutInference {\n slideSize: { cx: number; cy: number };\n layouts: AnalyzedLayout[];\n byLayoutPath: Map<string, AnalyzedLayout>;\n layoutPathBySlide: Map<string, string>;\n warnings: string[];\n}\n\nexport interface AnalyzePptxLayoutsOptions extends OoxmlOpenOptions {\n /** Also analyze layouts no slide references (default false). */\n includeUnused?: boolean;\n colors?: PptxColorHints;\n /** Cap on generated custom templates (default 12); excess downgrades to plain. */\n maxTemplates?: number;\n}\n\n// ── Constants ────────────────────────────────────────────────────────\n\nconst DEFAULT_SLIDE_SIZE = { cx: 12192000, cy: 6858000 };\nconst CHROME_PH_TYPES = new Set(['dt', 'ftr', 'sldNum', 'hdr']);\nconst MAX_INFERRED_TEMPLATES = 12;\nconst MAX_DECORATIONS = 4;\n/** Decorative rects smaller than this share of the slide are clutter. */\nconst MIN_DECORATION_AREA_PCT = 2;\n\n/** Default rects mirroring the exporter's slide proportions (percent). */\nconst DEFAULT_TITLE_RECT: PctRect = { x: 5, y: 4, w: 90, h: 16.7 };\nconst DEFAULT_BODY_RECT: PctRect = { x: 5, y: 23.3, w: 90, h: 66 };\n\nconst DEFAULT_TITLE_PT = 44;\nconst DEFAULT_SUBTITLE_PT = 24;\nconst DEFAULT_BODY_PT = 22;\n\n// ── Small helpers ────────────────────────────────────────────────────\n\nfunction firstPml(parent: Element | Document, local: string): Element | null {\n const els = parent.getElementsByTagNameNS(NS_PML, local);\n return els.length > 0 ? els[0]! : null;\n}\n\nfunction firstDml(parent: Element | Document, local: string): Element | null {\n const els = parent.getElementsByTagNameNS(NS_DRAWINGML, local);\n return els.length > 0 ? els[0]! : null;\n}\n\nfunction intAttr(el: Element | null, name: string): number | undefined {\n const raw = el?.getAttribute(name);\n if (!raw) return undefined;\n const n = parseInt(raw, 10);\n return Number.isFinite(n) ? n : undefined;\n}\n\nfunction pct(value: number, total: number): number {\n const raw = (value / total) * 100;\n const clamped = Math.max(-10, Math.min(110, raw));\n return Math.round(clamped * 100) / 100;\n}\n\nfunction emuToPct(rect: EmuRect, sldSz: { cx: number; cy: number }): PctRect {\n return {\n x: pct(rect.x, sldSz.cx),\n y: pct(rect.y, sldSz.cy),\n w: pct(rect.cx, sldSz.cx),\n h: pct(rect.cy, sldSz.cy),\n };\n}\n\n/** Read `a:xfrm` (off + ext) under a shape's `p:spPr`. Degenerate extents count as missing. */\nfunction readXfrm(sp: Element): EmuRect | null {\n const spPr = firstPml(sp, 'spPr');\n if (!spPr) return null;\n const xfrm = firstDml(spPr, 'xfrm');\n if (!xfrm) return null;\n const off = firstDml(xfrm, 'off');\n const ext = firstDml(xfrm, 'ext');\n const x = intAttr(off, 'x');\n const y = intAttr(off, 'y');\n const cx = intAttr(ext, 'cx');\n const cy = intAttr(ext, 'cy');\n if (x === undefined || y === undefined || cx === undefined || cy === undefined) return null;\n if (cx <= 0 || cy <= 0) return null;\n return { x, y, cx, cy };\n}\n\nfunction placeholderKind(rawType: string): PlaceholderKind {\n switch (rawType) {\n case 'title':\n case 'ctrTitle':\n return 'title';\n case 'subTitle':\n return 'subtitle';\n case '':\n case 'body':\n case 'obj':\n return 'text';\n case 'pic':\n case 'clipArt':\n case 'media':\n return 'picture';\n case 'tbl':\n return 'table';\n case 'chart':\n case 'dgm':\n return 'chart';\n default:\n return 'other';\n }\n}\n\n/** Collapse a ph type onto the master-matching base type (ECMA-376 inheritance). */\nfunction basePhType(rawType: string): string {\n switch (rawType) {\n case 'ctrTitle':\n return 'title';\n case '':\n case 'subTitle':\n case 'obj':\n case 'pic':\n case 'clipArt':\n case 'media':\n case 'tbl':\n case 'chart':\n case 'dgm':\n return 'body';\n default:\n return rawType;\n }\n}\n\nfunction parseLvl1Style(container: Element): PlaceholderTextStyle | undefined {\n const lvl1 = firstDml(container, 'lvl1pPr');\n if (!lvl1) return undefined;\n const style: PlaceholderTextStyle = {};\n const algn = lvl1.getAttribute('algn');\n if (algn === 'ctr') style.align = 'center';\n else if (algn === 'r') style.align = 'right';\n else if (algn === 'l') style.align = 'left';\n const defRPr = firstDml(lvl1, 'defRPr');\n const sz = intAttr(defRPr, 'sz');\n if (sz !== undefined && sz > 0) style.fontSizePt = sz / 100;\n const b = defRPr?.getAttribute('b');\n if (b === '1' || b === 'true') style.bold = true;\n else if (b === '0' || b === 'false') style.bold = false;\n return Object.keys(style).length > 0 ? style : undefined;\n}\n\nfunction mergeTextStyle(\n primary: PlaceholderTextStyle | undefined,\n fallback: PlaceholderTextStyle | undefined,\n): PlaceholderTextStyle | undefined {\n if (!primary) return fallback;\n if (!fallback) return primary;\n return {\n fontSizePt: primary.fontSizePt ?? fallback.fontSizePt,\n bold: primary.bold ?? fallback.bold,\n align: primary.align ?? fallback.align,\n anchor: primary.anchor ?? fallback.anchor,\n };\n}\n\n// ── Master placeholder index ─────────────────────────────────────────\n\ninterface MasterEntry {\n rect: EmuRect | null;\n style?: PlaceholderTextStyle;\n}\n\ninterface MasterIndex {\n name: string;\n exact: Map<string, MasterEntry>;\n baseIdx: Map<string, MasterEntry>;\n base: Map<string, MasterEntry>;\n titleStyle?: PlaceholderTextStyle;\n bodyStyle?: PlaceholderTextStyle;\n}\n\nasync function readMasterIndex(pkg: OoxmlPackage, masterPath: string): Promise<MasterIndex> {\n const index: MasterIndex = { name: '', exact: new Map(), baseIdx: new Map(), base: new Map() };\n const doc = await getPartXml(pkg, masterPath);\n if (!doc) return index;\n\n index.name = firstPml(doc, 'cSld')?.getAttribute('name')?.trim() ?? '';\n\n const txStyles = firstPml(doc, 'txStyles');\n if (txStyles) {\n const titleStyle = firstPml(txStyles, 'titleStyle');\n const bodyStyle = firstPml(txStyles, 'bodyStyle');\n if (titleStyle) index.titleStyle = parseLvl1Style(titleStyle);\n if (bodyStyle) index.bodyStyle = parseLvl1Style(bodyStyle);\n }\n\n const shapes = doc.getElementsByTagNameNS(NS_PML, 'sp');\n for (let i = 0; i < shapes.length; i++) {\n const sp = shapes[i]!;\n const ph = firstPml(sp, 'ph');\n if (!ph) continue;\n const rawType = ph.getAttribute('type') ?? '';\n const idx = intAttr(ph, 'idx') ?? 0;\n const entry: MasterEntry = { rect: readXfrm(sp) };\n const txBody = firstPml(sp, 'txBody');\n const lstStyle = txBody ? firstDml(txBody, 'lstStyle') : null;\n if (lstStyle) entry.style = parseLvl1Style(lstStyle);\n\n const typeKey = `${rawType || 'body'}:${idx}`;\n if (!index.exact.has(typeKey)) index.exact.set(typeKey, entry);\n const base = basePhType(rawType);\n const baseIdxKey = `${base}:${idx}`;\n if (!index.baseIdx.has(baseIdxKey)) index.baseIdx.set(baseIdxKey, entry);\n if (!index.base.has(base)) index.base.set(base, entry);\n }\n return index;\n}\n\n// ── Layout extraction ────────────────────────────────────────────────\n\nfunction resolveFillColor(solidFill: Element, hints: PptxColorHints): string | undefined {\n const srgb = firstDml(solidFill, 'srgbClr');\n const srgbVal = srgb?.getAttribute('val');\n if (srgbVal && /^[0-9a-fA-F]{6}$/.test(srgbVal)) return `#${srgbVal.toLowerCase()}`;\n const scheme = firstDml(solidFill, 'schemeClr');\n const schemeVal = scheme?.getAttribute('val');\n if (schemeVal && hints.schemeColors?.[schemeVal]) return hints.schemeColors[schemeVal];\n return undefined;\n}\n\n/** Direct child element of `parent` with the given DrawingML local name. */\nfunction directDmlChild(parent: Element, local: string): Element | null {\n for (let i = 0; i < parent.childNodes.length; i++) {\n const child = parent.childNodes[i];\n if (child && child.nodeType === 1 && (child as Element).localName === local) {\n const el = child as Element;\n if (el.namespaceURI === NS_DRAWINGML) return el;\n }\n }\n return null;\n}\n\nfunction extractDecoration(\n sp: Element,\n sldSz: { cx: number; cy: number },\n pxPerPt: number,\n hints: PptxColorHints,\n): ExtractedDecoration | null {\n const rectEmu = readXfrm(sp);\n if (!rectEmu) return null;\n const spPr = firstPml(sp, 'spPr');\n if (!spPr) return null;\n const prst = firstDml(spPr, 'prstGeom')?.getAttribute('prst');\n\n if (prst === 'line' || prst === 'straightConnector1') {\n const ln = directDmlChild(spPr, 'ln');\n const lnFill = ln ? directDmlChild(ln, 'solidFill') : null;\n const stroke = lnFill ? resolveFillColor(lnFill, hints) : undefined;\n if (!stroke) return null;\n const wEmu = intAttr(ln, 'w');\n const strokeWidthPx = wEmu\n ? Math.max(1, Math.min(40, Math.round((wEmu / 12700) * pxPerPt)))\n : 2;\n return { shape: 'line', rect: emuToPct(rectEmu, sldSz), stroke, strokeWidthPx };\n }\n\n if (prst === 'rect' || prst === 'roundRect') {\n const solidFill = directDmlChild(spPr, 'solidFill');\n const fill = solidFill ? resolveFillColor(solidFill, hints) : undefined;\n if (!fill) return null;\n const areaPct = ((rectEmu.cx * rectEmu.cy) / (sldSz.cx * sldSz.cy)) * 100;\n if (areaPct < MIN_DECORATION_AREA_PCT) return null;\n return {\n shape: 'rect',\n rect: emuToPct(rectEmu, sldSz),\n fill,\n ...(prst === 'roundRect' ? { borderRadius: 8 } : {}),\n };\n }\n\n return null;\n}\n\nasync function extractLayout(\n pkg: OoxmlPackage,\n layoutPath: string,\n sldSz: { cx: number; cy: number },\n pxPerPt: number,\n hints: PptxColorHints,\n masterCache: Map<string, Promise<MasterIndex>>,\n): Promise<ExtractedSlideLayout | null> {\n const doc = await getPartXml(pkg, layoutPath);\n if (!doc) return null;\n\n const name = firstPml(doc, 'cSld')?.getAttribute('name')?.trim() ?? '';\n const typeAttr = doc.documentElement?.getAttribute('type') ?? undefined;\n\n let masterPath: string | undefined;\n let master: MasterIndex | undefined;\n const layoutRels = await getPartRelationships(pkg, layoutPath);\n const masterRel = findRelByType(layoutRels, REL_SLIDE_MASTER);\n if (masterRel) {\n masterPath = resolveTarget(baseDirOf(layoutPath), masterRel.target);\n let cached = masterCache.get(masterPath);\n if (!cached) {\n cached = readMasterIndex(pkg, masterPath);\n masterCache.set(masterPath, cached);\n }\n master = await cached;\n }\n\n const placeholders: ExtractedPlaceholder[] = [];\n const decorations: ExtractedDecoration[] = [];\n\n const shapes = doc.getElementsByTagNameNS(NS_PML, 'sp');\n for (let i = 0; i < shapes.length; i++) {\n const sp = shapes[i]!;\n const ph = firstPml(sp, 'ph');\n\n if (!ph) {\n if (decorations.length < MAX_DECORATIONS) {\n const decoration = extractDecoration(sp, sldSz, pxPerPt, hints);\n if (decoration) decorations.push(decoration);\n }\n continue;\n }\n\n const rawType = ph.getAttribute('type') ?? '';\n if (CHROME_PH_TYPES.has(rawType)) continue;\n const idx = intAttr(ph, 'idx') ?? 0;\n const kind = placeholderKind(rawType);\n\n // Geometry: own xfrm → master by (type, idx) → by (base, idx) → by base → defaults.\n const own = readXfrm(sp);\n let rectEmu = own;\n let inheritedFromMaster = false;\n if (!rectEmu && master) {\n const base = basePhType(rawType);\n const entry =\n master.exact.get(`${rawType || 'body'}:${idx}`) ??\n master.baseIdx.get(`${base}:${idx}`) ??\n master.base.get(base);\n if (entry?.rect) {\n rectEmu = entry.rect;\n inheritedFromMaster = true;\n }\n }\n const rect = rectEmu\n ? emuToPct(rectEmu, sldSz)\n : kind === 'title'\n ? { ...DEFAULT_TITLE_RECT }\n : { ...DEFAULT_BODY_RECT };\n\n // Text style: layout lstStyle → master ph style → master txStyles.\n const txBody = firstPml(sp, 'txBody');\n const lstStyle = txBody ? firstDml(txBody, 'lstStyle') : null;\n let textStyle = lstStyle ? parseLvl1Style(lstStyle) : undefined;\n if (master) {\n const base = basePhType(rawType);\n const masterEntry =\n master.exact.get(`${rawType || 'body'}:${idx}`) ?? master.baseIdx.get(`${base}:${idx}`);\n textStyle = mergeTextStyle(textStyle, masterEntry?.style);\n textStyle = mergeTextStyle(\n textStyle,\n kind === 'title' || kind === 'subtitle' ? master.titleStyle : master.bodyStyle,\n );\n }\n\n const bodyPr = txBody ? firstDml(txBody, 'bodyPr') : null;\n const anchor = bodyPr?.getAttribute('anchor');\n if (anchor === 't' || anchor === 'ctr' || anchor === 'b') {\n textStyle = {\n ...(textStyle ?? {}),\n anchor: anchor === 't' ? 'top' : anchor === 'ctr' ? 'middle' : 'bottom',\n };\n }\n\n const orient = ph.getAttribute('orient');\n const vert = bodyPr?.getAttribute('vert');\n const vertical = orient === 'vert' || (!!vert && vert !== 'horz');\n\n placeholders.push({\n kind,\n rawType,\n idx,\n rect,\n inheritedFromMaster,\n vertical,\n ...(textStyle ? { textStyle } : {}),\n });\n }\n\n return {\n partPath: layoutPath,\n name,\n ...(typeAttr ? { typeAttr } : {}),\n ...(masterPath ? { masterPath } : {}),\n ...(master?.name ? { masterName: master.name } : {}),\n placeholders,\n decorations,\n slideCount: 0,\n };\n}\n\n// ── Geometry predicates ──────────────────────────────────────────────\n\nfunction overlap1D(aStart: number, aLen: number, bStart: number, bLen: number): number {\n return Math.max(0, Math.min(aStart + aLen, bStart + bLen) - Math.max(aStart, bStart));\n}\n\nfunction sideBySide(a: PctRect, b: PctRect): boolean {\n const xOverlap = overlap1D(a.x, a.w, b.x, b.w);\n const yOverlap = overlap1D(a.y, a.h, b.y, b.h);\n return (\n xOverlap <= 0.15 * Math.min(a.w, b.w) &&\n yOverlap >= 0.5 * Math.min(a.h, b.h) &&\n a.w >= 25 &&\n b.w >= 25\n );\n}\n\nfunction stackedAbove(a: PctRect, b: PctRect): boolean {\n const xOverlap = overlap1D(a.x, a.w, b.x, b.w);\n const yOverlap = overlap1D(a.y, a.h, b.y, b.h);\n return yOverlap <= 0.15 * Math.min(a.h, b.h) && xOverlap >= 0.5 * Math.min(a.w, b.w) && a.y < b.y;\n}\n\nfunction fullBleed(p: PctRect): boolean {\n return p.w >= 85 && p.h >= 80;\n}\n\nfunction nearEqualWidth(a: PctRect, b: PctRect): boolean {\n return Math.abs(a.w - b.w) <= 0.15 * Math.max(a.w, b.w);\n}\n\nfunction rectsOverlap(a: PctRect, b: PctRect): boolean {\n return overlap1D(a.x, a.w, b.x, b.w) > 2 && overlap1D(a.y, a.h, b.y, b.h) > 2;\n}\n\nfunction centerX(r: PctRect): number {\n return r.x + r.w / 2;\n}\n\n// ── Classifier ───────────────────────────────────────────────────────\n\ntype Directive =\n | { kind: 'plain' }\n | { kind: 'skip' }\n | { kind: 'builtin'; template: string; paramSpec?: BuiltinParamSpec }\n | { kind: 'feature-by-geometry' }\n | { kind: 'comparison' }\n | { kind: 'custom-two-column' }\n | { kind: 'custom-caption' }\n | { kind: 'custom-generic' }\n | { kind: 'by-geometry' };\n\nconst PLAIN_LAYOUT_TYPES = new Set([\n 'titleOnly',\n 'tx',\n 'obj',\n 'objOnly',\n 'objTx',\n 'txOverObj',\n 'objOverTx',\n 'tbl',\n 'chart',\n 'dgm',\n 'txAndChart',\n 'chartAndTx',\n 'vertTitleAndTxOverChart',\n 'txAndTwoObj',\n 'twoObjAndTx',\n 'twoObjOverTx',\n 'objAndTwoObj',\n 'twoObjAndObj',\n 'fourObj',\n 'vertTx',\n 'vertTitleAndTx',\n 'clipArtAndVertTx',\n]);\n\nfunction stage1(typeAttr: string | undefined): Directive | null {\n if (!typeAttr || typeAttr === 'cust') return null;\n if (typeAttr === 'title')\n return { kind: 'builtin', template: 'title', paramSpec: 'titleSubtitle' };\n if (typeAttr === 'secHead') return { kind: 'builtin', template: 'sectionHeader' };\n if (typeAttr === 'blank') return { kind: 'skip' };\n if (PLAIN_LAYOUT_TYPES.has(typeAttr)) return { kind: 'plain' };\n if (typeAttr === 'picTx') return { kind: 'feature-by-geometry' };\n if (typeAttr === 'clipArtAndTx' || typeAttr === 'mediaAndTx') {\n return { kind: 'builtin', template: 'leftFeature', paramSpec: 'featureImage' };\n }\n if (typeAttr === 'txAndClipArt' || typeAttr === 'txAndMedia') {\n return { kind: 'builtin', template: 'rightFeature', paramSpec: 'featureImage' };\n }\n if (\n typeAttr === 'twoColTx' ||\n typeAttr === 'twoObj' ||\n typeAttr === 'txAndObj' ||\n typeAttr === 'objAndTx'\n ) {\n return { kind: 'custom-two-column' };\n }\n if (typeAttr === 'twoTxTwoObj') return { kind: 'comparison' };\n // Unknown/future type values fall through to name + geometry stages.\n return null;\n}\n\nconst WELL_KNOWN_NAMES: Record<string, Directive> = {\n 'title slide': { kind: 'builtin', template: 'title', paramSpec: 'titleSubtitle' },\n 'section header': { kind: 'builtin', template: 'sectionHeader' },\n 'two content': { kind: 'custom-two-column' },\n comparison: { kind: 'comparison' },\n 'content with caption': { kind: 'custom-caption' },\n 'picture with caption': { kind: 'feature-by-geometry' },\n 'title and content': { kind: 'plain' },\n 'title only': { kind: 'plain' },\n blank: { kind: 'skip' },\n 'vertical title and text': { kind: 'plain' },\n 'title and vertical text': { kind: 'plain' },\n};\n\nfunction stage2(name: string): Directive | null {\n return WELL_KNOWN_NAMES[name.trim().toLowerCase()] ?? null;\n}\n\nfunction contentPlaceholders(layout: ExtractedSlideLayout): ExtractedPlaceholder[] {\n return layout.placeholders.filter((p) => p.kind !== 'title' && p.kind !== 'subtitle');\n}\n\nfunction stage3(layout: ExtractedSlideLayout): Directive {\n if (layout.placeholders.some((p) => p.vertical)) return { kind: 'plain' };\n const hasTitle = layout.placeholders.some((p) => p.kind === 'title');\n const content = contentPlaceholders(layout);\n if (content.length === 0) return hasTitle ? { kind: 'plain' } : { kind: 'skip' };\n\n const texts = content.filter((p) => p.kind === 'text');\n const pictures = content.filter((p) => p.kind === 'picture');\n const others = content.filter((p) => p.kind !== 'text' && p.kind !== 'picture');\n\n if (pictures.length === 0 && others.length === 0) {\n if (texts.length === 1) return { kind: 'plain' };\n if (texts.length === 2 && sideBySide(texts[0]!.rect, texts[1]!.rect)) {\n return nearEqualWidth(texts[0]!.rect, texts[1]!.rect)\n ? { kind: 'custom-two-column' }\n : { kind: 'custom-caption' };\n }\n if (texts.length === 4 && findComparisonColumns(texts)) return { kind: 'comparison' };\n return { kind: 'plain' };\n }\n\n if (pictures.length === 1 && others.length === 0) {\n if (texts.length === 0) {\n return fullBleed(pictures[0]!.rect)\n ? { kind: 'builtin', template: 'imageWithCaption', paramSpec: 'featureImage' }\n : { kind: 'custom-generic' };\n }\n return { kind: 'feature-by-geometry' };\n }\n\n if (\n pictures.length >= 2 &&\n pictures.length <= 4 &&\n texts.length === 0 &&\n others.length === 0 &&\n pictures.every((a, i) => pictures.every((b, j) => i === j || !rectsOverlap(a.rect, b.rect)))\n ) {\n return { kind: 'builtin', template: 'photoGrid', paramSpec: 'photoGridGate' };\n }\n\n return { kind: 'plain' };\n}\n\n/**\n * Detect the Comparison shape: 4 texts forming two side-by-side columns of a\n * short header over a taller body. Returns placeholder idx lists per column,\n * or null when the rects don't form that shape.\n */\nfunction findComparisonColumns(\n texts: ExtractedPlaceholder[],\n): { left: number[]; right: number[] } | null {\n if (texts.length !== 4) return null;\n const sorted = [...texts].sort((a, b) => centerX(a.rect) - centerX(b.rect));\n const leftPair = [sorted[0]!, sorted[1]!];\n const rightPair = [sorted[2]!, sorted[3]!];\n const columnWidth = (pair: ExtractedPlaceholder[]) =>\n Math.abs(centerX(pair[0]!.rect) - centerX(pair[1]!.rect));\n if (columnWidth(leftPair) > 10 || columnWidth(rightPair) > 10) return null;\n if (centerX(rightPair[0]!.rect) - centerX(leftPair[1]!.rect) <= 10) return null;\n\n const orderColumn = (pair: ExtractedPlaceholder[]): number[] | null => {\n const byY = [...pair].sort((a, b) => a.rect.y - b.rect.y);\n const header = byY[0]!;\n const body = byY[1]!;\n if (header.rect.h > 20 || header.rect.y + header.rect.h > body.rect.y + 2) return null;\n return [header.idx, body.idx];\n };\n const left = orderColumn(leftPair);\n const right = orderColumn(rightPair);\n return left && right ? { left, right } : null;\n}\n\n// ── Custom template generation ───────────────────────────────────────\n\nfunction slugify(name: string): string {\n const slug = name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n return slug;\n}\n\nfunction pctPosition(rect: PctRect): Position {\n return { x: `${rect.x}%`, y: `${rect.y}%`, width: `${rect.w}%`, height: `${rect.h}%` };\n}\n\ninterface GeneratorContext {\n hints: PptxColorHints;\n pxPerPt: number;\n viewport: { width: number; height: number };\n notes: string[];\n}\n\nfunction fontPx(pt: number | undefined, defaultPt: number, pxPerPt: number): number {\n const sizePt = pt && pt > 0 ? pt : defaultPt;\n return Math.max(16, Math.min(140, Math.round(sizePt * pxPerPt)));\n}\n\nfunction textLayerFor(\n id: string,\n ph: ExtractedPlaceholder,\n text: string,\n role: 'title' | 'subtitle' | 'body',\n gen: GeneratorContext,\n): TextLayer {\n const defaultPt =\n role === 'title'\n ? DEFAULT_TITLE_PT\n : role === 'subtitle'\n ? DEFAULT_SUBTITLE_PT\n : DEFAULT_BODY_PT;\n const style: TextStyle = {\n fontSize: fontPx(ph.textStyle?.fontSizePt, defaultPt, gen.pxPerPt),\n color: gen.hints.text ?? '#1a1a1a',\n lineHeight: role === 'title' ? 1.15 : 1.4,\n ...(role === 'title'\n ? { fontWeight: ph.textStyle?.bold === false ? 'normal' : 'bold' }\n : ph.textStyle?.bold\n ? { fontWeight: 'bold' }\n : {}),\n ...(ph.textStyle?.align ? { textAlign: ph.textStyle.align } : {}),\n ...(ph.textStyle?.anchor ? { verticalAlign: ph.textStyle.anchor } : {}),\n };\n return { id, type: 'text', position: pctPosition(ph.rect), content: { text, style } };\n}\n\nfunction imageLayerFor(id: string, ph: ExtractedPlaceholder, imageIndex: number): ImageLayer {\n // {image:N} is 0-based; a layer whose token resolves to no image is\n // dropped whole at render time, so picture placeholders degrade cleanly\n // on slides without pictures.\n return {\n id,\n type: 'image',\n position: pctPosition(ph.rect),\n content: { src: `{image:${imageIndex}}`, alt: `{image:${imageIndex}}`, fit: 'cover' },\n };\n}\n\nfunction decorationLayers(layout: ExtractedSlideLayout): ShapeLayer[] {\n return layout.decorations.map((d, i) => ({\n id: `decor-${i + 1}`,\n type: 'shape' as const,\n position: pctPosition(d.rect),\n content:\n d.shape === 'line'\n ? { shape: 'line' as const, stroke: d.stroke, strokeWidth: d.strokeWidthPx ?? 2 }\n : {\n shape: 'rect' as const,\n fill: d.fill,\n ...(d.borderRadius ? { borderRadius: d.borderRadius } : {}),\n },\n }));\n}\n\nfunction titlePlaceholder(layout: ExtractedSlideLayout): ExtractedPlaceholder | undefined {\n return layout.placeholders.find((p) => p.kind === 'title');\n}\n\n/** Synthetic title placeholder used when a layout omits one but a template needs it. */\nfunction defaultTitlePlaceholder(): ExtractedPlaceholder {\n return {\n kind: 'title',\n rawType: 'title',\n idx: 0,\n rect: { ...DEFAULT_TITLE_RECT },\n inheritedFromMaster: false,\n vertical: false,\n };\n}\n\nfunction buildTwoColumnDef(\n layout: ExtractedSlideLayout,\n gen: GeneratorContext,\n): CustomTemplateLayer[] {\n const texts = contentPlaceholders(layout).filter((p) => p.kind === 'text');\n let left: ExtractedPlaceholder;\n let right: ExtractedPlaceholder;\n const sorted = [...texts].sort((a, b) => a.rect.x - b.rect.x);\n if (sorted.length >= 2 && sideBySide(sorted[0]!.rect, sorted[sorted.length - 1]!.rect)) {\n left = sorted[0]!;\n right = sorted[sorted.length - 1]!;\n } else {\n // Geometry unavailable (defaulted rects) — synthesize equal columns\n // inside the standard body area with a 4% gutter.\n left = {\n ...defaultTitlePlaceholder(),\n kind: 'text',\n rawType: 'body',\n rect: { x: 5, y: 23.3, w: 43, h: 66 },\n };\n right = { ...left, rect: { x: 52, y: 23.3, w: 43, h: 66 } };\n }\n\n const gap = Math.max(0, Math.round((right.rect.x - (left.rect.x + left.rect.w)) * 100) / 100);\n const layers: CustomTemplateLayer[] = [...decorationLayers(layout)];\n const title = titlePlaceholder(layout) ?? defaultTitlePlaceholder();\n layers.push(textLayerFor('title', title, '{title}', 'title', gen));\n const itemLayer: CustomTemplateLayer = {\n ...textLayerFor('column', left, '{item}', 'body', gen),\n // gap is in percentage points because the layer's width is a %-string;\n // the repeat resolver offsets clones by width + gap in the same unit.\n repeat: { source: 'listItems', direction: 'row', gap, max: 2 },\n };\n layers.push(itemLayer);\n return layers;\n}\n\nfunction buildCaptionDef(\n layout: ExtractedSlideLayout,\n gen: GeneratorContext,\n): CustomTemplateLayer[] {\n const texts = contentPlaceholders(layout).filter((p) => p.kind === 'text');\n const byWidth = [...texts].sort((a, b) => b.rect.w - a.rect.w);\n const wide = byWidth[0];\n const narrow = byWidth[1];\n const layers: CustomTemplateLayer[] = [...decorationLayers(layout)];\n const title = titlePlaceholder(layout) ?? defaultTitlePlaceholder();\n layers.push(textLayerFor('title', title, '{title}', 'title', gen));\n if (wide) layers.push(textLayerFor('body', wide, '{content}', 'body', gen));\n if (narrow) {\n // Empty pipe-default: the caption region stays invisible until the\n // author fills it via `{[name caption=\"…\"]}`.\n layers.push(textLayerFor('caption', narrow, '{attr:caption|}', 'body', gen));\n }\n return layers;\n}\n\nfunction buildGenericDef(\n layout: ExtractedSlideLayout,\n gen: GeneratorContext,\n): CustomTemplateLayer[] {\n const layers: CustomTemplateLayer[] = [...decorationLayers(layout)];\n const title = titlePlaceholder(layout);\n if (title) layers.push(textLayerFor('title', title, '{title}', 'title', gen));\n\n const content = contentPlaceholders(layout);\n const pictures = content\n .filter((p) => p.kind === 'picture')\n .sort((a, b) => a.idx - b.idx || a.rect.y - b.rect.y);\n pictures.forEach((ph, k) => layers.push(imageLayerFor(`image-${k}`, ph, k)));\n\n const texts = content.filter((p) => p.kind === 'text');\n if (texts.length > 0) layers.push(textLayerFor('body', texts[0]!, '{content}', 'body', gen));\n if (texts.length > 1) {\n gen.notes.push(\n `${texts.length - 1} additional text region(s) could not be bound — the token grammar has no per-region address; full text stays in the markdown body.`,\n );\n }\n const dropped = content.filter(\n (p) => p.kind === 'table' || p.kind === 'chart' || p.kind === 'other',\n );\n if (dropped.length > 0) {\n gen.notes.push(\n `${dropped.length} table/chart placeholder(s) dropped (content flows as markdown).`,\n );\n }\n return layers;\n}\n\n/**\n * Whether generated layers contain any content-bearing layer (something a\n * slide's title/body/images will bind to) beyond decorations.\n */\nfunction hasContentLayer(layers: CustomTemplateLayer[]): boolean {\n return layers.some((l) => l.type === 'text' || l.type === 'image');\n}\n\n// ── Verdict resolution ───────────────────────────────────────────────\n\nfunction resolveFeatureByGeometry(layout: ExtractedSlideLayout): LayoutVerdict {\n const content = contentPlaceholders(layout);\n const pic = content.find((p) => p.kind === 'picture');\n if (!pic) return { kind: 'plain' };\n const texts = content.filter((p) => p.kind === 'text');\n const beside = texts.find((t) => sideBySide(pic.rect, t.rect));\n if (beside) {\n const template = centerX(pic.rect) < centerX(beside.rect) ? 'leftFeature' : 'rightFeature';\n return { kind: 'builtin', template, paramSpec: 'featureImage' };\n }\n if (texts.some((t) => stackedAbove(pic.rect, t.rect)) || fullBleed(pic.rect)) {\n return { kind: 'builtin', template: 'imageWithCaption', paramSpec: 'featureImage' };\n }\n return { kind: 'builtin', template: 'leftFeature', paramSpec: 'featureImage' };\n}\n\nfunction classifyLayout(layout: ExtractedSlideLayout): Directive {\n return stage1(layout.typeAttr) ?? stage2(layout.name) ?? stage3(layout);\n}\n\nfunction resolveVerdict(\n layout: ExtractedSlideLayout,\n directive: Directive,\n gen: GeneratorContext,\n templateName: string,\n): LayoutVerdict {\n switch (directive.kind) {\n case 'plain':\n case 'skip':\n return { kind: directive.kind };\n case 'builtin':\n return directive;\n case 'feature-by-geometry':\n return resolveFeatureByGeometry(layout);\n case 'comparison': {\n const texts = contentPlaceholders(layout).filter((p) => p.kind === 'text');\n const columns = findComparisonColumns(texts);\n // Without resolvable column geometry the importer can't attribute\n // slide texts to sides — and a bare {[twoColumn]} renders empty.\n if (!columns) return { kind: 'plain' };\n return { kind: 'builtin', template: 'twoColumn', paramSpec: 'comparisonPairs', columns };\n }\n case 'custom-two-column':\n case 'custom-caption':\n case 'custom-generic':\n case 'by-geometry': {\n const layers =\n directive.kind === 'custom-two-column'\n ? buildTwoColumnDef(layout, gen)\n : directive.kind === 'custom-caption'\n ? buildCaptionDef(layout, gen)\n : buildGenericDef(layout, gen);\n if (!hasContentLayer(layers)) return { kind: 'plain' };\n const def: CustomTemplateDefinition = {\n name: templateName,\n label: layout.name || 'Imported layout',\n description: `Imported from PowerPoint layout \"${layout.name || templateName}\"${\n layout.masterName ? ` (master \"${layout.masterName}\")` : ''\n }`,\n viewport: gen.viewport,\n layers,\n };\n return { kind: 'custom', def };\n }\n }\n}\n\n// ── Deck-level analysis ──────────────────────────────────────────────\n\nasync function readSlideSize(pkg: OoxmlPackage): Promise<{ cx: number; cy: number }> {\n const pres = await getPartXml(pkg, 'ppt/presentation.xml');\n const sldSz = pres ? firstPml(pres, 'sldSz') : null;\n const cx = intAttr(sldSz, 'cx');\n const cy = intAttr(sldSz, 'cy');\n if (cx && cy && cx > 0 && cy > 0) return { cx, cy };\n return { ...DEFAULT_SLIDE_SIZE };\n}\n\nasync function orderedSlidePathsForLayouts(pkg: OoxmlPackage): Promise<string[]> {\n const pres = await getPartXml(pkg, 'ppt/presentation.xml');\n if (!pres) return [];\n const rels = await getPartRelationships(pkg, 'ppt/presentation.xml');\n const relById = new Map(rels.map((r) => [r.id, r.target]));\n const out: string[] = [];\n const ids = pres.getElementsByTagNameNS(NS_PML, 'sldId');\n for (let i = 0; i < ids.length; i++) {\n const rid = attrNS(ids[i]!, NS_R, 'id', 'r:id');\n const target = rid ? relById.get(rid) : undefined;\n if (target) out.push(resolveTarget('ppt', target));\n }\n return out;\n}\n\nfunction viewportFor(sldSz: { cx: number; cy: number }): { width: number; height: number } {\n if (sldSz.cy > sldSz.cx) {\n return { width: 1080, height: Math.round((1080 * sldSz.cy) / sldSz.cx) };\n }\n return { width: Math.round((1080 * sldSz.cx) / sldSz.cy), height: 1080 };\n}\n\n/**\n * Analyze the deck's slide layouts: extract placeholder geometry (with\n * master inheritance), classify each layout against the built-in template\n * set, and generate custom template definitions for the distinctive ones.\n */\nexport async function analyzePptxLayouts(\n pkg: OoxmlPackage,\n options: AnalyzePptxLayoutsOptions = {},\n): Promise<PptxLayoutInference> {\n const warnings: string[] = [];\n const hints = options.colors ?? {};\n const maxTemplates = options.maxTemplates ?? MAX_INFERRED_TEMPLATES;\n\n const sldSz = await readSlideSize(pkg);\n const viewport = viewportFor(sldSz);\n const pxPerPt = viewport.height / (sldSz.cy / 12700);\n\n // Layouts used by slides, in first-use order, with usage counts.\n const slidePaths = await orderedSlidePathsForLayouts(pkg);\n const layoutPathBySlide = new Map<string, string>();\n const usage = new Map<string, number>();\n const orderedLayoutPaths: string[] = [];\n for (const slidePath of slidePaths) {\n const rels = await getPartRelationships(pkg, slidePath);\n const layoutRel = findRelByType(rels, REL_SLIDE_LAYOUT);\n if (!layoutRel) continue;\n const layoutPath = resolveTarget(baseDirOf(slidePath), layoutRel.target);\n layoutPathBySlide.set(slidePath, layoutPath);\n if (!usage.has(layoutPath)) orderedLayoutPaths.push(layoutPath);\n usage.set(layoutPath, (usage.get(layoutPath) ?? 0) + 1);\n }\n\n if (options.includeUnused) {\n const unused: string[] = [];\n for (const [partPath, contentType] of pkg.contentTypes.overrides) {\n if (contentType === CONTENT_TYPE_PPTX_SLIDE_LAYOUT && !usage.has(partPath)) {\n unused.push(partPath);\n }\n }\n unused.sort();\n orderedLayoutPaths.push(...unused);\n }\n\n // Extract + classify each layout.\n const masterCache = new Map<string, Promise<MasterIndex>>();\n const layouts: AnalyzedLayout[] = [];\n const usedNames = new Set<string>();\n for (let i = 0; i < orderedLayoutPaths.length; i++) {\n const layoutPath = orderedLayoutPaths[i]!;\n const extracted = await extractLayout(pkg, layoutPath, sldSz, pxPerPt, hints, masterCache);\n if (!extracted) {\n warnings.push(`layout ${layoutPath} could not be read; its slides import plain`);\n continue;\n }\n extracted.slideCount = usage.get(layoutPath) ?? 0;\n\n // Unique slug for the (potential) custom template. Reserved up front so\n // two masters sharing a layout name get -2/-3 suffixes deterministically.\n const baseSlug = slugify(extracted.name) || `layout-${i + 1}`;\n let templateName = `pptx-${baseSlug}`;\n for (let n = 2; usedNames.has(templateName); n++) templateName = `pptx-${baseSlug}-${n}`;\n\n const notes: string[] = [];\n const gen: GeneratorContext = { hints, pxPerPt, viewport, notes };\n const directive = classifyLayout(extracted);\n const verdict = resolveVerdict(extracted, directive, gen, templateName);\n if (verdict.kind === 'custom') usedNames.add(templateName);\n layouts.push({ extracted, verdict, notes });\n }\n\n // Cap generated templates, keeping the most-used layouts.\n const customs = layouts.filter((l) => l.verdict.kind === 'custom');\n if (customs.length > maxTemplates) {\n const ranked = [...customs].sort((a, b) => b.extracted.slideCount - a.extracted.slideCount);\n for (const layout of ranked.slice(maxTemplates)) {\n layout.verdict = { kind: 'plain' };\n layout.notes.push('dropped: more inferred layouts than the template cap');\n }\n warnings.push(\n `deck defines ${customs.length} distinctive layouts; kept the ${maxTemplates} most used as custom templates`,\n );\n }\n\n const byLayoutPath = new Map(layouts.map((l) => [l.extracted.partPath, l]));\n return { slideSize: sldSz, layouts, byLayoutPath, layoutPathBySlide, warnings };\n}\n\n// ── Dialog-path inspection API ───────────────────────────────────────\n\nexport interface PptxLayoutSummary {\n layoutPath: string;\n name: string;\n masterName?: string;\n typeAttr?: string;\n slideCount: number;\n verdict: 'builtin' | 'custom' | 'plain' | 'skip';\n /** Set when verdict is 'builtin' — the close built-in alternative. */\n builtinTemplate?: string;\n /** Set when verdict is 'custom' — ready to save as a doc/library template. */\n customTemplate?: CustomTemplateDefinition;\n notes?: string[];\n}\n\nexport type InspectPptxLayoutsOptions = AnalyzePptxLayoutsOptions;\n\n/**\n * Inspect a deck's layouts without importing it — used by the theme dialog\n * to list what a PPTX would contribute (built-in matches shown as\n * informational rows; custom templates offered for confirmation).\n */\nexport async function inspectPptxLayouts(\n data: ArrayBuffer | Blob,\n options: InspectPptxLayoutsOptions = {},\n): Promise<{ layouts: PptxLayoutSummary[]; slideSize: { cx: number; cy: number } }> {\n const pkg = await openPackage(data, options);\n const analysis = await analyzePptxLayouts(pkg, options);\n const layouts = analysis.layouts.map((l, i): PptxLayoutSummary => {\n const { extracted, verdict, notes } = l;\n return {\n layoutPath: extracted.partPath,\n name: extracted.name || `Layout ${i + 1}`,\n ...(extracted.masterName ? { masterName: extracted.masterName } : {}),\n ...(extracted.typeAttr ? { typeAttr: extracted.typeAttr } : {}),\n slideCount: extracted.slideCount,\n verdict: verdict.kind,\n ...(verdict.kind === 'builtin' ? { builtinTemplate: verdict.template } : {}),\n ...(verdict.kind === 'custom' ? { customTemplate: verdict.def } : {}),\n ...(notes.length > 0 ? { notes } : {}),\n };\n });\n return { layouts, slideSize: analysis.slideSize };\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/ooxml/namespaces.ts","../src/ooxml/reader.ts"],"sourcesContent":["/**\n * OOXML Namespace Constants\n *\n * All Office Open XML namespace URIs used across DOCX, PPTX, and XLSX.\n * Organized by category for easy reference.\n */\n\n// ============================================\n// Package-level namespaces (shared by all formats)\n// ============================================\n\n/** Relationships namespace (used in _rels/*.rels files) */\nexport const NS_RELATIONSHIPS = 'http://schemas.openxmlformats.org/package/2006/relationships';\n\n/** Content Types namespace ([Content_Types].xml) */\nexport const NS_CONTENT_TYPES = 'http://schemas.openxmlformats.org/package/2006/content-types';\n\n// ============================================\n// Relationship type URIs\n// ============================================\n\n/** Relationship type: Office document (main part) */\nexport const REL_OFFICE_DOCUMENT =\n 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument';\n\n/** Relationship type: Core properties */\nexport const REL_CORE_PROPERTIES =\n 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties';\n\n/** Relationship type: Extended properties (app.xml) */\nexport const REL_EXTENDED_PROPERTIES =\n 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties';\n\n/** Relationship type: Styles */\nexport const REL_STYLES =\n 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles';\n\n/** Relationship type: Numbering */\nexport const REL_NUMBERING =\n 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering';\n\n/** Relationship type: Font table */\nexport const REL_FONT_TABLE =\n 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable';\n\n/** Relationship type: Settings */\nexport const REL_SETTINGS =\n 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings';\n\n/** Relationship type: Hyperlink */\nexport const REL_HYPERLINK =\n 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink';\n\n/** Relationship type: Image */\nexport const REL_IMAGE =\n 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image';\n\n/** Relationship type: Footnotes */\nexport const REL_FOOTNOTES =\n 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes';\n\n/** Relationship type: Theme */\nexport const REL_THEME =\n 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme';\n\n// ============================================\n// WordprocessingML (DOCX)\n// ============================================\n\n/** WordprocessingML main namespace (w:) */\nexport const NS_WML = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';\n\n// ============================================\n// PresentationML (PPTX)\n// ============================================\n\n/** PresentationML main namespace (p:) */\nexport const NS_PML = 'http://schemas.openxmlformats.org/presentationml/2006/main';\n\n/** PowerPoint 2010 extension namespace (p14:) */\nexport const NS_PML_2010 = 'http://schemas.microsoft.com/office/powerpoint/2010/main';\n\n// ============================================\n// SpreadsheetML (XLSX)\n// ============================================\n\n/** SpreadsheetML main namespace */\nexport const NS_SML = 'http://schemas.openxmlformats.org/spreadsheetml/2006/main';\n\n// ============================================\n// DrawingML (shared across formats)\n// ============================================\n\n/** DrawingML main namespace (a:) */\nexport const NS_DRAWINGML = 'http://schemas.openxmlformats.org/drawingml/2006/main';\n\n/** DrawingML WordprocessingML drawing namespace (wp:) */\nexport const NS_WP_DRAWING =\n 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing';\n\n/** DrawingML picture namespace (pic:) */\nexport const NS_PICTURE = 'http://schemas.openxmlformats.org/drawingml/2006/picture';\n\n// ============================================\n// Dublin Core / Core Properties\n// ============================================\n\n/** Dublin Core elements namespace */\nexport const NS_DC = 'http://purl.org/dc/elements/1.1/';\n\n/** Dublin Core terms namespace */\nexport const NS_DCTERMS = 'http://purl.org/dc/terms/';\n\n/** Core properties namespace */\nexport const NS_CORE_PROPERTIES =\n 'http://schemas.openxmlformats.org/package/2006/metadata/core-properties';\n\n/** XML Schema Instance namespace */\nexport const NS_XSI = 'http://www.w3.org/2001/XMLSchema-instance';\n\n// ============================================\n// Markup Compatibility\n// ============================================\n\n/** Markup Compatibility namespace (mc:) */\nexport const NS_MC = 'http://schemas.openxmlformats.org/markup-compatibility/2006';\n\n/** Office relationships namespace (r:) */\nexport const NS_R = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships';\n\n// ============================================\n// Content type strings\n// ============================================\n\nexport const CONTENT_TYPE_RELATIONSHIPS =\n 'application/vnd.openxmlformats-package.relationships+xml';\n\nexport const CONTENT_TYPE_CORE_PROPERTIES =\n 'application/vnd.openxmlformats-package.core-properties+xml';\n\nexport const CONTENT_TYPE_DOCX_DOCUMENT =\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml';\n\nexport const CONTENT_TYPE_DOCX_STYLES =\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml';\n\nexport const CONTENT_TYPE_DOCX_NUMBERING =\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml';\n\nexport const CONTENT_TYPE_DOCX_SETTINGS =\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml';\n\nexport const CONTENT_TYPE_DOCX_FONT_TABLE =\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml';\n\nexport const CONTENT_TYPE_DOCX_FOOTNOTES =\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml';\n\nexport const CONTENT_TYPE_PPTX_PRESENTATION =\n 'application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml';\n\nexport const CONTENT_TYPE_PPTX_SLIDE =\n 'application/vnd.openxmlformats-officedocument.presentationml.slide+xml';\n\nexport const CONTENT_TYPE_PPTX_SLIDE_LAYOUT =\n 'application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml';\n\nexport const CONTENT_TYPE_PPTX_SLIDE_MASTER =\n 'application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml';\n\nexport const CONTENT_TYPE_PPTX_THEME = 'application/vnd.openxmlformats-officedocument.theme+xml';\n\n/** Relationship type: Slide */\nexport const REL_SLIDE =\n 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide';\n\n/** Relationship type: Slide layout */\nexport const REL_SLIDE_LAYOUT =\n 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout';\n\n/** Relationship type: Slide master */\nexport const REL_SLIDE_MASTER =\n 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster';\n\nexport const CONTENT_TYPE_XLSX_WORKBOOK =\n 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml';\n\nexport const CONTENT_TYPE_XLSX_WORKSHEET =\n 'application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml';\n\nexport const CONTENT_TYPE_XLSX_STYLES =\n 'application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml';\n\n/** Relationship type: Worksheet */\nexport const REL_WORKSHEET =\n 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet';\n","/**\n * OOXML Package Reader\n *\n * Opens OOXML archives (.docx, .pptx, .xlsx) and parses their\n * structural metadata: [Content_Types].xml, relationships, and\n * core properties.\n *\n * Uses bounded JSZip member streams and a platform DOMParser (with an xmldom\n * fallback in bare Node/SSR) to parse XML.\n */\n\nimport { DOMParser as XmldomDOMParser } from '@xmldom/xmldom';\nimport type { OoxmlPackage, ContentTypeMap, Relationship, CoreProperties } from './types.js';\nimport { NS_RELATIONSHIPS, NS_DC, NS_DCTERMS, NS_CORE_PROPERTIES } from './namespaces.js';\nimport {\n openBoundedZipArchive,\n type BoundedZipArchive,\n type ZipSafetyLimits,\n} from '../shared/zipSafety.js';\n\nexport type OoxmlOpenOptions = ZipSafetyLimits;\n\ntype DomParserLike = new () => {\n parseFromString(source: string, mimeType: string): unknown;\n};\n\n/** Safe read sessions for opaque packages opened by this module. */\nconst packageArchives = new WeakMap<OoxmlPackage, BoundedZipArchive>();\nconst MAX_CONTENT_TYPES_BYTES = 1024 * 1024;\nconst MAX_RELATIONSHIPS_BYTES = 4 * 1024 * 1024;\n\n/**\n * Parse XML in browsers and bare Node. Browser DOMParser is preferred; the\n * pure-JS xmldom implementation is the package-owned fallback for Node/SSR.\n */\nfunction parseXml(source: string): Document {\n const nativeParser = (globalThis as { DOMParser?: DomParserLike }).DOMParser;\n const Parser = nativeParser ?? (XmldomDOMParser as unknown as DomParserLike);\n const doc = new Parser().parseFromString(source, 'application/xml') as Document;\n const parserErrors = doc.getElementsByTagName('parsererror');\n if (parserErrors.length > 0) {\n throw new Error(`Invalid OOXML XML part: ${parserErrors[0]?.textContent ?? 'parse error'}`);\n }\n return doc;\n}\n\n// ============================================\n// Package Opening\n// ============================================\n\n/**\n * Open an OOXML package from raw data.\n *\n * Parses the ZIP archive, [Content_Types].xml, and root relationships.\n *\n * @param data - The raw .docx/.pptx/.xlsx file as ArrayBuffer or Blob\n * @param limits - Optional archive count, size, and compression-ratio limits\n * @returns A parsed OoxmlPackage\n */\nexport async function openPackage(\n data: ArrayBuffer | Blob,\n limits: OoxmlOpenOptions = {},\n): Promise<OoxmlPackage> {\n const archive = await openBoundedZipArchive(data, limits);\n const contentTypes = await parseContentTypes(archive);\n const rootRelationships = await parseRelationships(archive, '');\n\n const pkg = {\n contentTypes,\n rootRelationships,\n } as unknown as OoxmlPackage;\n packageArchives.set(pkg, archive);\n return pkg;\n}\n\n// ============================================\n// Content Types\n// ============================================\n\n/**\n * Parse [Content_Types].xml from the archive.\n */\nasync function parseContentTypes(archive: BoundedZipArchive): Promise<ContentTypeMap> {\n const overrides = new Map<string, string>();\n const defaults = new Map<string, string>();\n\n const text = await archive.readText('[Content_Types].xml', MAX_CONTENT_TYPES_BYTES);\n if (text === null) return { overrides, defaults };\n const doc = parseXml(text);\n\n // Parse <Default Extension=\"rels\" ContentType=\"...\" />\n const defaultEls = doc.getElementsByTagName('Default');\n for (let i = 0; i < defaultEls.length; i++) {\n const el = defaultEls[i];\n const ext = el.getAttribute('Extension');\n const ct = el.getAttribute('ContentType');\n if (ext && ct) defaults.set(ext, ct);\n }\n\n // Parse <Override PartName=\"/word/document.xml\" ContentType=\"...\" />\n const overrideEls = doc.getElementsByTagName('Override');\n for (let i = 0; i < overrideEls.length; i++) {\n const el = overrideEls[i];\n const partName = el.getAttribute('PartName');\n const ct = el.getAttribute('ContentType');\n if (partName && ct) {\n // Normalize: strip leading slash\n overrides.set(partName.replace(/^\\//, ''), ct);\n }\n }\n\n return { overrides, defaults };\n}\n\n// ============================================\n// Relationships\n// ============================================\n\n/**\n * Parse relationships for a specific part.\n *\n * @param pkg - The OOXML package (or the zip directly)\n * @param partPath - The part path (e.g., \"word/document.xml\").\n * Use \"\" for root-level relationships (_rels/.rels).\n * @returns Array of relationship entries\n */\nexport async function getPartRelationships(\n pkg: OoxmlPackage,\n partPath: string,\n): Promise<Relationship[]> {\n return parseRelationships(pkg, partPath);\n}\n\n/**\n * Parse a _rels/*.rels file from the ZIP.\n *\n * For root relationships, relsPath = \"_rels/.rels\".\n * For part relationships, relsPath = \"<dir>/_rels/<filename>.rels\".\n */\nasync function parseRelationships(\n source: OoxmlPackage | BoundedZipArchive,\n partPath: string,\n): Promise<Relationship[]> {\n const relsPath = partPath === '' ? '_rels/.rels' : buildRelsPath(partPath);\n\n const bytes = await readArchivePart(source, relsPath, MAX_RELATIONSHIPS_BYTES);\n if (!bytes) return [];\n const text = new TextDecoder().decode(bytes);\n const doc = parseXml(text);\n const result: Relationship[] = [];\n\n const els = doc.getElementsByTagNameNS(NS_RELATIONSHIPS, 'Relationship');\n // Fallback in case namespace isn't used (some generators omit it)\n const fallbackEls = els.length > 0 ? els : doc.getElementsByTagName('Relationship');\n\n for (let i = 0; i < fallbackEls.length; i++) {\n const el = fallbackEls[i];\n const id = el.getAttribute('Id');\n const type = el.getAttribute('Type');\n const target = el.getAttribute('Target');\n if (id && type && target) {\n const targetMode = el.getAttribute('TargetMode') as 'Internal' | 'External' | null;\n result.push({\n id,\n type,\n target,\n ...(targetMode ? { targetMode } : {}),\n });\n }\n }\n\n return result;\n}\n\n/**\n * Build the _rels path for a given part path.\n *\n * \"word/document.xml\" → \"word/_rels/document.xml.rels\"\n * \"xl/workbook.xml\" → \"xl/_rels/workbook.xml.rels\"\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\n// ============================================\n// Part Access\n// ============================================\n\n/**\n * Extract an XML part from the package and parse it as a DOM Document.\n *\n * @param pkg - The OOXML package\n * @param partPath - Path within the archive (e.g., \"word/document.xml\")\n * @returns Parsed XML Document, or null if the part doesn't exist\n */\nexport async function getPartXml(pkg: OoxmlPackage, partPath: string): Promise<Document | null> {\n const bytes = await readPackagePart(pkg, partPath);\n return bytes ? parseXml(new TextDecoder().decode(bytes)) : null;\n}\n\n/**\n * Extract a binary part from the package (e.g., an image from word/media/).\n *\n * @param pkg - The OOXML package\n * @param partPath - Path within the archive\n * @returns The binary content, or null if the part doesn't exist\n */\nexport async function getPartBinary(\n pkg: OoxmlPackage,\n partPath: string,\n): Promise<ArrayBuffer | null> {\n const bytes = await readPackagePart(pkg, partPath);\n return bytes ? bytes.slice().buffer : null;\n}\n\nfunction readArchivePart(\n source: OoxmlPackage | BoundedZipArchive,\n path: string,\n maxBytes?: number,\n): Promise<Uint8Array | null> {\n return 'entries' in source\n ? source.read(path, maxBytes)\n : readPackagePart(source, path, maxBytes);\n}\n\nasync function readPackagePart(\n pkg: OoxmlPackage,\n path: string,\n maxBytes?: number,\n): Promise<Uint8Array | null> {\n const archive = packageArchives.get(pkg);\n if (!archive) {\n throw new TypeError('Invalid OoxmlPackage: create packages with openPackage().');\n }\n return archive.read(path, maxBytes);\n}\n\n// ============================================\n// Core Properties\n// ============================================\n\n/**\n * Parse core document properties from docProps/core.xml.\n *\n * @param pkg - The OOXML package\n * @returns Parsed core properties (all fields optional)\n */\nexport async function getCoreProperties(pkg: OoxmlPackage): Promise<CoreProperties> {\n const doc = await getPartXml(pkg, 'docProps/core.xml');\n if (!doc) return {};\n\n function getText(ns: string, localName: string): string | undefined {\n const els = doc!.getElementsByTagNameNS(ns, localName);\n if (els.length > 0 && els[0].textContent) {\n return els[0].textContent;\n }\n return undefined;\n }\n\n return {\n title: getText(NS_DC, 'title'),\n subject: getText(NS_DC, 'subject'),\n creator: getText(NS_DC, 'creator'),\n description: getText(NS_DC, 'description'),\n keywords: getText(NS_CORE_PROPERTIES, 'keywords'),\n lastModifiedBy: getText(NS_CORE_PROPERTIES, 'lastModifiedBy'),\n revision: getText(NS_CORE_PROPERTIES, 'revision'),\n created: getText(NS_DCTERMS, 'created'),\n modified: getText(NS_DCTERMS, 'modified'),\n };\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/shared/zipLimits.ts","../src/shared/boundedZipArchive.ts","../src/shared/zipEntryCount.ts"],"sourcesContent":["/** ZIP safety policy, structured errors, path checks, and metadata validation. */\n\nimport type JSZip from 'jszip';\n\nexport interface ZipSafetyLimits {\n /** Maximum number of archive records, including directories. Default: 10,000. */\n maxEntries?: number;\n /** Maximum uncompressed bytes for one member. Defaults to maxUncompressedBytes. */\n maxEntryUncompressedBytes?: number;\n /** Maximum total uncompressed bytes across the archive. Default: 512 MiB. */\n maxUncompressedBytes?: number;\n /** Maximum uncompressed/compressed ratio for a member. Default: 1,000. */\n maxCompressionRatio?: number;\n}\n\nexport type ZipSafetyErrorCode =\n | 'invalid-limit'\n | 'invalid-archive'\n | 'unsafe-path'\n | 'invalid-entry-metadata'\n | 'too-many-entries'\n | 'entry-too-large'\n | 'archive-too-large'\n | 'compression-ratio-exceeded'\n | 'size-mismatch'\n | 'crc-mismatch'\n | 'decompression-failed';\n\nexport interface ZipSafetyErrorOptions {\n path?: string;\n limit?: number;\n actual?: number;\n cause?: unknown;\n}\n\n/** A stable, machine-readable error raised while validating or reading a ZIP. */\nexport class ZipSafetyError extends Error {\n readonly code: ZipSafetyErrorCode;\n readonly path?: string;\n readonly limit?: number;\n readonly actual?: number;\n\n constructor(code: ZipSafetyErrorCode, message: string, options: ZipSafetyErrorOptions = {}) {\n super(message);\n this.name = 'ZipSafetyError';\n this.code = code;\n this.path = options.path;\n this.limit = options.limit;\n this.actual = options.actual;\n if (options.cause !== undefined) {\n (this as Error & { cause?: unknown }).cause = options.cause;\n }\n }\n}\n\nexport interface ValidatedZipEntry {\n path: string;\n entry: JSZip.JSZipObject;\n declaredSize?: number;\n compressedSize?: number;\n crc32?: number;\n}\n\nexport interface ResolvedZipSafetyLimits {\n maxEntries: number;\n maxEntryUncompressedBytes: number;\n maxUncompressedBytes: number;\n maxCompressionRatio: number;\n}\n\nexport const DEFAULT_MAX_ZIP_ENTRIES = 10_000;\nexport const DEFAULT_MAX_ZIP_UNCOMPRESSED_BYTES = 512 * 1024 * 1024;\nexport const DEFAULT_MAX_ZIP_COMPRESSION_RATIO = 1_000;\n\n/**\n * Validate central-directory metadata before any member is decompressed.\n * JSZip normalizes traversal names, so inspect `unsafeOriginalName` too.\n */\nexport function validateZipArchive(zip: JSZip, limits: ZipSafetyLimits = {}): ValidatedZipEntry[] {\n const resolved = resolveZipSafetyLimits(limits);\n const files: ValidatedZipEntry[] = [];\n let memberCount = 0;\n let declaredTotal = 0;\n let oversizedEntry: { path: string; actual: number; limit: number } | undefined;\n\n zip.forEach((relativePath, entry) => {\n memberCount++;\n if (entry.dir) return;\n const originalPath = originalEntryPath(entry, relativePath);\n if (!isSafeArchivePath(originalPath)) {\n throw new ZipSafetyError(\n 'unsafe-path',\n `ZIP import: archive contains an unsafe path: ${originalPath}.`,\n { path: originalPath },\n );\n }\n\n const metadata = compressedMetadata(entry, originalPath);\n if (\n metadata.uncompressedSize !== undefined &&\n metadata.uncompressedSize > resolved.maxEntryUncompressedBytes\n ) {\n oversizedEntry ??= {\n path: originalPath,\n actual: metadata.uncompressedSize,\n limit: resolved.maxEntryUncompressedBytes,\n };\n }\n\n const ratio =\n metadata.uncompressedSize === undefined || metadata.compressedSize === undefined\n ? undefined\n : compressionRatio(metadata.uncompressedSize, metadata.compressedSize);\n if (ratio !== undefined && ratio > resolved.maxCompressionRatio) {\n throw compressionRatioError(originalPath, ratio, resolved.maxCompressionRatio);\n }\n\n declaredTotal += metadata.uncompressedSize ?? 0;\n if (!Number.isSafeInteger(declaredTotal)) throw invalidMetadataError(originalPath);\n files.push({\n path: relativePath,\n entry,\n ...(metadata.uncompressedSize !== undefined\n ? { declaredSize: metadata.uncompressedSize }\n : {}),\n ...(metadata.compressedSize !== undefined ? { compressedSize: metadata.compressedSize } : {}),\n ...(metadata.crc32 !== undefined ? { crc32: metadata.crc32 } : {}),\n });\n });\n\n if (memberCount > resolved.maxEntries) {\n throw tooManyEntriesError(memberCount, resolved.maxEntries);\n }\n if (declaredTotal > resolved.maxUncompressedBytes) {\n throw archiveTooLargeError(declaredTotal, resolved.maxUncompressedBytes);\n }\n if (oversizedEntry) {\n throw entryTooLargeError(oversizedEntry.path, oversizedEntry.actual, oversizedEntry.limit);\n }\n return files;\n}\n\n/** Reject a path that could be interpreted outside an archive's logical root. */\nexport function assertSafeZipPath(path: string): void {\n if (!isSafeArchivePath(path)) {\n throw new ZipSafetyError('unsafe-path', `ZIP archive path is unsafe: ${path}.`, { path });\n }\n}\n\nexport function resolveZipSafetyLimits(limits: ZipSafetyLimits): ResolvedZipSafetyLimits {\n const maxEntries = limits.maxEntries ?? DEFAULT_MAX_ZIP_ENTRIES;\n const maxUncompressedBytes = limits.maxUncompressedBytes ?? DEFAULT_MAX_ZIP_UNCOMPRESSED_BYTES;\n const maxEntryUncompressedBytes = limits.maxEntryUncompressedBytes ?? maxUncompressedBytes;\n const maxCompressionRatio = limits.maxCompressionRatio ?? DEFAULT_MAX_ZIP_COMPRESSION_RATIO;\n\n assertNonNegativeInteger('maxEntries', maxEntries);\n assertNonNegativeFinite('maxUncompressedBytes', maxUncompressedBytes);\n assertNonNegativeFinite('maxEntryUncompressedBytes', maxEntryUncompressedBytes);\n if (!Number.isFinite(maxCompressionRatio) || maxCompressionRatio < 1) {\n throw invalidLimitError(\n 'maxCompressionRatio must be a finite number greater than or equal to 1',\n );\n }\n return {\n maxEntries,\n maxEntryUncompressedBytes,\n maxUncompressedBytes,\n maxCompressionRatio,\n };\n}\n\nexport function assertNonNegativeFinite(name: string, value: number): void {\n if (!Number.isFinite(value) || value < 0) {\n throw invalidLimitError(`${name} must be a non-negative finite number`);\n }\n}\n\nexport function entryTooLargeError(path: string, actual: number, limit: number): ZipSafetyError {\n return new ZipSafetyError(\n 'entry-too-large',\n `ZIP import: archive member ${path} exceeds ${limit} byte per-entry limit.`,\n { path, limit, actual },\n );\n}\n\nexport function tooManyEntriesError(actual: number, limit: number): ZipSafetyError {\n return new ZipSafetyError(\n 'too-many-entries',\n `ZIP import: archive has ${actual} files; limit is ${limit}.`,\n { limit, actual },\n );\n}\n\nexport function archiveTooLargeError(actual: number, limit: number): ZipSafetyError {\n return new ZipSafetyError(\n 'archive-too-large',\n `ZIP import: uncompressed content exceeds ${limit} byte limit.`,\n { limit, actual },\n );\n}\n\nexport function compressionRatioError(path: string, actual: number, limit: number): ZipSafetyError {\n return new ZipSafetyError(\n 'compression-ratio-exceeded',\n `ZIP import: archive member ${path} exceeds ${limit}:1 compression-ratio limit.`,\n { path, limit, actual },\n );\n}\n\nexport function compressionRatio(uncompressedBytes: number, compressedBytes: number): number {\n if (uncompressedBytes === 0) return 0;\n if (compressedBytes === 0) return Number.POSITIVE_INFINITY;\n return uncompressedBytes / compressedBytes;\n}\n\nfunction assertNonNegativeInteger(name: string, value: number): void {\n if (!Number.isInteger(value) || value < 0) {\n throw invalidLimitError(`${name} must be a non-negative integer`);\n }\n}\n\nfunction invalidLimitError(detail: string): ZipSafetyError {\n return new ZipSafetyError('invalid-limit', `ZIP import: ${detail}.`);\n}\n\nfunction originalEntryPath(entry: JSZip.JSZipObject, relativePath: string): string {\n return (\n (\n entry as JSZip.JSZipObject & {\n unsafeOriginalName?: string;\n }\n ).unsafeOriginalName ?? relativePath\n );\n}\n\nfunction compressedMetadata(\n entry: JSZip.JSZipObject,\n path: string,\n): { uncompressedSize?: number; compressedSize?: number; crc32?: number } {\n const data = (\n entry as unknown as {\n _data?: { uncompressedSize?: number; compressedSize?: number; crc32?: number };\n }\n )._data;\n const uncompressedSize = data?.uncompressedSize;\n const compressedSize = data?.compressedSize;\n const crc32 = data?.crc32;\n if (\n (uncompressedSize !== undefined && !isValidMetadataInteger(uncompressedSize)) ||\n (compressedSize !== undefined && !isValidMetadataInteger(compressedSize)) ||\n (crc32 !== undefined && !Number.isInteger(crc32))\n ) {\n throw invalidMetadataError(path);\n }\n return {\n ...(uncompressedSize !== undefined ? { uncompressedSize } : {}),\n ...(compressedSize !== undefined ? { compressedSize } : {}),\n ...(crc32 !== undefined ? { crc32 } : {}),\n };\n}\n\nfunction isValidMetadataInteger(value: number): boolean {\n return Number.isSafeInteger(value) && value >= 0;\n}\n\nfunction invalidMetadataError(path: string): ZipSafetyError {\n return new ZipSafetyError(\n 'invalid-entry-metadata',\n `ZIP import: archive member has invalid size or checksum metadata: ${path}.`,\n { path },\n );\n}\n\nfunction isSafeArchivePath(path: string): boolean {\n const segments = path.split('/');\n return !(\n path.startsWith('/') ||\n /^[a-zA-Z]:[\\\\/]/.test(path) ||\n path.includes('\\\\') ||\n Array.from(path).some((character) => {\n const codePoint = character.codePointAt(0) ?? 0;\n return codePoint < 0x20 || codePoint === 0x7f;\n }) ||\n segments.some((segment) => segment === '' || segment === '.' || segment === '..')\n );\n}\n","/** Incremental JSZip member reads governed by one shared archive budget. */\n\nimport JSZip from 'jszip';\nimport {\n archiveTooLargeError,\n assertNonNegativeFinite,\n compressionRatio,\n compressionRatioError,\n entryTooLargeError,\n resolveZipSafetyLimits,\n validateZipArchive,\n tooManyEntriesError,\n ZipSafetyError,\n type ResolvedZipSafetyLimits,\n type ValidatedZipEntry,\n type ZipSafetyErrorCode,\n type ZipSafetyLimits,\n} from './zipLimits.js';\nimport { declaredZipEntryCount, prepareZipInput, type ZipInput } from './zipEntryCount.js';\n\ninterface ActiveZipRead {\n stop(error: ZipSafetyError): void;\n}\n\ninterface ZipChunkStream {\n on(event: 'data', callback: (chunk: Uint8Array) => void): ZipChunkStream;\n on(event: 'error', callback: (error: unknown) => void): ZipChunkStream;\n on(event: 'end', callback: () => void): ZipChunkStream;\n pause(): ZipChunkStream;\n resume(): ZipChunkStream;\n}\n\ninterface StreamableZipObject {\n internalStream(type: 'uint8array'): ZipChunkStream;\n}\n\n/**\n * A JSZip archive whose member reads share one actual-byte budget.\n *\n * JSZip's promise API accumulates a complete inflated member before returning.\n * This wrapper instead consumes `internalStream('uint8array')`, checks every\n * emitted chunk, and pauses every active stream as soon as any limit fails.\n * Completed reads are cached so repeated OOXML part access is neither inflated\n * nor charged twice.\n */\nexport interface BoundedZipArchive {\n readonly zip: JSZip;\n readonly entries: readonly ValidatedZipEntry[];\n readonly emittedUncompressedBytes: number;\n read(path: string, maxBytes?: number): Promise<Uint8Array | null>;\n readText(path: string, maxBytes?: number): Promise<string | null>;\n release(path: string): void;\n}\n\nclass JsZipBoundedArchive implements BoundedZipArchive {\n readonly zip: JSZip;\n readonly entries: readonly ValidatedZipEntry[];\n\n private readonly limits: ResolvedZipSafetyLimits;\n private readonly entriesByPath: ReadonlyMap<string, ValidatedZipEntry>;\n private readonly reads = new Map<string, Promise<Uint8Array>>();\n private readonly activeReads = new Set<ActiveZipRead>();\n private terminalError?: ZipSafetyError;\n private emittedBytes = 0;\n\n constructor(zip: JSZip, entries: readonly ValidatedZipEntry[], limits: ResolvedZipSafetyLimits) {\n this.zip = zip;\n this.entries = entries;\n this.limits = limits;\n this.entriesByPath = new Map(entries.map((entry) => [entry.path, entry]));\n }\n\n /** Actual uncompressed bytes accepted from JSZip streams so far. */\n get emittedUncompressedBytes(): number {\n return this.emittedBytes;\n }\n\n /** Read and cache one member, returning null when it does not exist. */\n async read(path: string, maxBytes?: number): Promise<Uint8Array | null> {\n this.throwIfFailed();\n if (maxBytes !== undefined) assertNonNegativeFinite('member read limit', maxBytes);\n const entry = this.entriesByPath.get(path);\n if (!entry) return null;\n\n let pending = this.reads.get(path);\n if (!pending) {\n pending = this.streamEntry(entry, maxBytes);\n this.reads.set(path, pending);\n }\n const bytes = await pending;\n if (maxBytes !== undefined && bytes.byteLength > maxBytes) {\n const error = entryTooLargeError(path, bytes.byteLength, maxBytes);\n this.failArchive(error);\n throw error;\n }\n return bytes;\n }\n\n /** Read one UTF-8 text member, returning null when it does not exist. */\n async readText(path: string, maxBytes?: number): Promise<string | null> {\n const bytes = await this.read(path, maxBytes);\n return bytes ? new TextDecoder().decode(bytes) : null;\n }\n\n /** Release a cached member when a sequential consumer has taken ownership. */\n release(path: string): void {\n this.reads.delete(path);\n }\n\n private streamEntry(metadata: ValidatedZipEntry, readLimit?: number): Promise<Uint8Array> {\n const { path, entry, declaredSize, crc32: expectedCrc } = metadata;\n const effectiveEntryLimit = Math.min(\n this.limits.maxEntryUncompressedBytes,\n readLimit ?? Number.POSITIVE_INFINITY,\n );\n // Never trust a declaration enough to allocate it up front. A forged\n // 511 MiB size must not force 511 MiB of memory for a tiny member.\n let output: Uint8Array = new Uint8Array(0);\n let stream: ZipChunkStream;\n try {\n stream = (entry as unknown as StreamableZipObject).internalStream('uint8array');\n } catch (error: unknown) {\n const safeError = asZipSafetyError(error, path);\n this.failArchive(safeError);\n return Promise.reject(safeError);\n }\n\n return new Promise<Uint8Array>((resolve, reject) => {\n let settled = false;\n let written = 0;\n let crc = 0xffffffff;\n\n const controller: ActiveZipRead = {\n stop: (error) => {\n if (settled) return;\n settled = true;\n this.activeReads.delete(controller);\n // Public JSZip cancellation is cooperative. It prevents another\n // compressed-input tick; data already emitted synchronously by the\n // current tick is ignored because `settled` is now true.\n try {\n stream.pause();\n } catch {\n // Reject with the original safety failure even if a malformed\n // third-party stream cannot be paused cleanly.\n }\n reject(error);\n },\n };\n this.activeReads.add(controller);\n\n stream\n .on('data', (chunk: Uint8Array) => {\n if (settled) return;\n const nextWritten = written + chunk.byteLength;\n try {\n this.assertChunkAllowed(metadata, nextWritten, chunk.byteLength, effectiveEntryLimit);\n output = growOutput(output, nextWritten, declaredSize, effectiveEntryLimit);\n output.set(chunk, written);\n written = nextWritten;\n crc = updateCrc32(crc, chunk);\n } catch (error: unknown) {\n this.failArchive(asZipSafetyError(error, path));\n }\n })\n .on('error', (error: unknown) => {\n if (settled) return;\n const message = error instanceof Error ? error.message : String(error);\n const code: ZipSafetyErrorCode = message.includes('uncompressed data size mismatch')\n ? 'size-mismatch'\n : 'decompression-failed';\n this.failArchive(\n new ZipSafetyError(code, `ZIP import: could not decompress ${path}: ${message}`, {\n path,\n cause: error,\n }),\n );\n })\n .on('end', () => {\n if (settled) return;\n if (declaredSize !== undefined && written !== declaredSize) {\n this.failArchive(\n new ZipSafetyError(\n 'size-mismatch',\n `ZIP import: archive member size does not match its metadata: ${path}.`,\n { path, actual: written },\n ),\n );\n return;\n }\n const actualCrc = (crc ^ 0xffffffff) >>> 0;\n if (expectedCrc !== undefined && actualCrc !== expectedCrc >>> 0) {\n this.failArchive(\n new ZipSafetyError('crc-mismatch', `ZIP import: CRC32 mismatch for ${path}.`, {\n path,\n }),\n );\n return;\n }\n\n settled = true;\n this.activeReads.delete(controller);\n resolve(output.byteLength === written ? output : output.slice(0, written));\n })\n .resume();\n });\n }\n\n private assertChunkAllowed(\n entry: ValidatedZipEntry,\n nextEntryBytes: number,\n chunkBytes: number,\n effectiveEntryLimit: number,\n ): void {\n if (entry.declaredSize !== undefined && nextEntryBytes > entry.declaredSize) {\n throw new ZipSafetyError(\n 'size-mismatch',\n `ZIP import: archive member size does not match its metadata: ${entry.path}.`,\n { path: entry.path, actual: nextEntryBytes },\n );\n }\n if (\n effectiveEntryLimit < this.limits.maxUncompressedBytes &&\n nextEntryBytes > effectiveEntryLimit\n ) {\n throw entryTooLargeError(entry.path, nextEntryBytes, effectiveEntryLimit);\n }\n\n const nextTotal = this.emittedBytes + chunkBytes;\n if (nextTotal > this.limits.maxUncompressedBytes) {\n throw archiveTooLargeError(nextTotal, this.limits.maxUncompressedBytes);\n }\n if (nextEntryBytes > effectiveEntryLimit) {\n throw entryTooLargeError(entry.path, nextEntryBytes, effectiveEntryLimit);\n }\n\n const ratio =\n entry.compressedSize === undefined\n ? undefined\n : compressionRatio(nextEntryBytes, entry.compressedSize);\n if (ratio !== undefined && ratio > this.limits.maxCompressionRatio) {\n throw compressionRatioError(entry.path, ratio, this.limits.maxCompressionRatio);\n }\n this.emittedBytes = nextTotal;\n }\n\n private failArchive(error: ZipSafetyError): void {\n if (this.terminalError) return;\n this.terminalError = error;\n for (const active of [...this.activeReads]) active.stop(error);\n }\n\n private throwIfFailed(): void {\n if (this.terminalError) throw this.terminalError;\n }\n}\n\n/** Load with JSZip, validate metadata, and create a shared bounded read session. */\nexport async function openBoundedZipArchive(\n data: ZipInput,\n limits: ZipSafetyLimits = {},\n): Promise<BoundedZipArchive> {\n const resolved = resolveZipSafetyLimits(limits);\n let prepared: { input: ZipInput; bytes?: Uint8Array };\n try {\n prepared = await prepareZipInput(data);\n } catch (error: unknown) {\n throw invalidArchiveError(error);\n }\n if (prepared.bytes) {\n const declaredEntries = declaredZipEntryCount(prepared.bytes);\n if (declaredEntries !== undefined && declaredEntries > resolved.maxEntries) {\n throw tooManyEntriesError(declaredEntries, resolved.maxEntries);\n }\n }\n let zip: JSZip;\n try {\n zip = await JSZip.loadAsync(prepared.input);\n } catch (error: unknown) {\n throw invalidArchiveError(error);\n }\n return createBoundedZipArchive(zip, resolved);\n}\n\nfunction invalidArchiveError(cause: unknown): ZipSafetyError {\n return new ZipSafetyError('invalid-archive', 'ZIP import: archive is not readable.', { cause });\n}\n\n/** Wrap an existing JSZip instance in the same validation and shared budget. */\nexport function createBoundedZipArchive(\n zip: JSZip,\n limits: ZipSafetyLimits = {},\n): BoundedZipArchive {\n const resolved = resolveZipSafetyLimits(limits);\n const entries = validateZipArchive(zip, resolved);\n return new JsZipBoundedArchive(zip, entries, resolved);\n}\n\nfunction asZipSafetyError(error: unknown, path: string): ZipSafetyError {\n if (error instanceof ZipSafetyError) return error;\n return new ZipSafetyError(\n 'decompression-failed',\n `ZIP import: could not decompress ${path}: ${error instanceof Error ? error.message : String(error)}`,\n { path, cause: error },\n );\n}\n\nfunction growOutput(\n current: Uint8Array,\n required: number,\n declaredSize: number | undefined,\n limit: number,\n): Uint8Array {\n if (required <= current.byteLength) return current;\n const maximum = Math.min(declaredSize ?? limit, limit);\n const grownSize = current.byteLength === 0 ? required : current.byteLength * 2;\n const nextSize = Math.min(maximum, Math.max(required, grownSize));\n const next = new Uint8Array(nextSize);\n next.set(current);\n return next;\n}\n\nlet crcTable: Uint32Array | undefined;\n\nfunction updateCrc32(crc: number, bytes: Uint8Array): number {\n const table = crcTable ?? (crcTable = makeCrcTable());\n let next = crc >>> 0;\n for (const byte of bytes) next = table[(next ^ byte) & 0xff]! ^ (next >>> 8);\n return next >>> 0;\n}\n\nfunction makeCrcTable(): Uint32Array {\n const table = new Uint32Array(256);\n for (let n = 0; n < table.length; n++) {\n let value = n;\n for (let bit = 0; bit < 8; bit++) {\n value = (value & 1) !== 0 ? 0xedb88320 ^ (value >>> 1) : value >>> 1;\n }\n table[n] = value >>> 0;\n }\n return table;\n}\n","/** Narrow EOCD preflight for rejecting record-count bombs before JSZip allocation. */\n\nconst END_OF_CENTRAL_DIRECTORY = 0x06054b50;\nconst ZIP64_END_OF_CENTRAL_DIRECTORY = 0x06064b50;\nconst ZIP64_END_LOCATOR = 0x07064b50;\nconst UINT16_MAX = 0xffff;\nconst MIN_EOCD_BYTES = 22;\nconst MAX_ZIP_COMMENT_BYTES = 0xffff;\n\nexport type ZipInput = ArrayBuffer | Uint8Array | Blob;\n\n/** Materialize Blob input once when possible so preflight bytes feed JSZip too. */\nexport async function prepareZipInput(\n data: ZipInput,\n): Promise<{ input: ZipInput; bytes?: Uint8Array }> {\n if (ArrayBuffer.isView(data)) {\n const bytes = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);\n return { input: bytes, bytes };\n }\n if (!isBlobLike(data)) {\n const bytes = new Uint8Array(data);\n return { input: bytes, bytes };\n }\n\n const bytes = await readBlobBytes(data);\n return bytes ? { input: bytes, bytes } : { input: data };\n}\n\n/**\n * Read the declared total central-directory record count when unambiguous.\n * Returns undefined for absent, trailing, malformed, or unsupported metadata;\n * JSZip remains authoritative in those cases.\n */\nexport function declaredZipEntryCount(bytes: Uint8Array): number | undefined {\n const eocdOffset = findEocd(bytes);\n if (eocdOffset === undefined) return undefined;\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n const count = view.getUint16(eocdOffset + 10, true);\n if (count !== UINT16_MAX) return count;\n return readZip64EntryCount(view, eocdOffset);\n}\n\nfunction findEocd(bytes: Uint8Array): number | undefined {\n if (bytes.byteLength < MIN_EOCD_BYTES) return undefined;\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n const earliest = Math.max(0, bytes.byteLength - MIN_EOCD_BYTES - MAX_ZIP_COMMENT_BYTES);\n for (let offset = bytes.byteLength - MIN_EOCD_BYTES; offset >= earliest; offset--) {\n if (view.getUint32(offset, true) !== END_OF_CENTRAL_DIRECTORY) continue;\n const commentLength = view.getUint16(offset + 20, true);\n if (offset + MIN_EOCD_BYTES + commentLength === bytes.byteLength) return offset;\n }\n return undefined;\n}\n\nfunction readZip64EntryCount(view: DataView, eocdOffset: number): number | undefined {\n const locatorOffset = eocdOffset - 20;\n if (locatorOffset < 0 || view.getUint32(locatorOffset, true) !== ZIP64_END_LOCATOR) {\n return undefined;\n }\n const recordOffset = readSafeUint64(view, locatorOffset + 8);\n if (\n recordOffset === undefined ||\n recordOffset < 0 ||\n recordOffset + 40 > view.byteLength ||\n view.getUint32(recordOffset, true) !== ZIP64_END_OF_CENTRAL_DIRECTORY\n ) {\n return undefined;\n }\n return readSafeUint64(view, recordOffset + 32);\n}\n\nfunction readSafeUint64(view: DataView, offset: number): number | undefined {\n if (offset < 0 || offset + 8 > view.byteLength) return undefined;\n const low = view.getUint32(offset, true);\n const high = view.getUint32(offset + 4, true);\n const value = high * 0x1_0000_0000 + low;\n return Number.isSafeInteger(value) ? value : undefined;\n}\n\nfunction isBlobLike(data: ZipInput): data is Blob {\n const candidate = data as Blob;\n return typeof candidate.size === 'number' && typeof candidate.slice === 'function';\n}\n\nasync function readBlobBytes(blob: Blob): Promise<Uint8Array | undefined> {\n const arrayBuffer = (blob as Blob & { arrayBuffer?: () => Promise<ArrayBuffer> }).arrayBuffer;\n if (typeof arrayBuffer === 'function') {\n return new Uint8Array(await arrayBuffer.call(blob));\n }\n if (typeof FileReader === 'undefined') return undefined;\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(new Uint8Array(reader.result as ArrayBuffer));\n reader.onerror = () => reject(reader.error ?? new Error('Could not read ZIP blob.'));\n reader.readAsArrayBuffer(blob);\n });\n}\n"],"mappings":"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","names":["bytes"]}