@bendyline/squisq-formats 1.4.2 → 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.
- package/README.md +48 -2
- package/dist/chunk-2KPARF2P.js +99 -0
- package/dist/chunk-2KPARF2P.js.map +1 -0
- package/dist/{chunk-5LSSWZPU.js → chunk-4VUWTSGM.js} +72 -25
- package/dist/chunk-4VUWTSGM.js.map +1 -0
- package/dist/{chunk-YESS7VY3.js → chunk-ABVI556T.js} +154 -39
- package/dist/chunk-ABVI556T.js.map +1 -0
- package/dist/{chunk-WWBIKRNP.js → chunk-CRAVSMPZ.js} +13 -11
- package/dist/chunk-CRAVSMPZ.js.map +1 -0
- package/dist/chunk-FE6OJV6O.js +560 -0
- package/dist/chunk-FE6OJV6O.js.map +1 -0
- package/dist/{chunk-D7IFPWNZ.js → chunk-GVS2XXV6.js} +27 -26
- package/dist/chunk-GVS2XXV6.js.map +1 -0
- package/dist/{chunk-RTS5XBZ7.js → chunk-HTW2M27H.js} +341 -100
- package/dist/chunk-HTW2M27H.js.map +1 -0
- package/dist/{chunk-46FMDOWZ.js → chunk-LXYLOOST.js} +49 -17
- package/dist/chunk-LXYLOOST.js.map +1 -0
- package/dist/{chunk-MJGRI6XR.js → chunk-MLX2BOJC.js} +12 -7
- package/dist/chunk-MLX2BOJC.js.map +1 -0
- package/dist/chunk-NKAJPJ4G.js +106 -0
- package/dist/chunk-NKAJPJ4G.js.map +1 -0
- package/dist/{chunk-DQAZR57U.js → chunk-O3GVVND4.js} +1 -1
- package/dist/chunk-ODL3SSPT.js +18 -0
- package/dist/chunk-ODL3SSPT.js.map +1 -0
- package/dist/chunk-QRVN6A6E.js +127 -0
- package/dist/chunk-QRVN6A6E.js.map +1 -0
- package/dist/chunk-U32AG3G3.js +195 -0
- package/dist/chunk-U32AG3G3.js.map +1 -0
- package/dist/{chunk-EHLGMSTE.js → chunk-VJJM2SSH.js} +10 -8
- package/dist/chunk-VJJM2SSH.js.map +1 -0
- package/dist/chunk-VSYHZECT.js +778 -0
- package/dist/chunk-VSYHZECT.js.map +1 -0
- package/dist/{chunk-SHLPSADL.js → chunk-WC7WULGV.js} +81 -189
- package/dist/chunk-WC7WULGV.js.map +1 -0
- package/dist/chunk-XKUMNGBW.js +131 -0
- package/dist/chunk-XKUMNGBW.js.map +1 -0
- package/dist/chunk-YRT7GQ5Y.js +28 -0
- package/dist/chunk-YRT7GQ5Y.js.map +1 -0
- package/dist/container/index.d.ts +13 -3
- package/dist/container/index.js +23 -20
- package/dist/container/index.js.map +1 -1
- package/dist/docx/index.d.ts +6 -2
- package/dist/docx/index.js +5 -3
- package/dist/epub/index.d.ts +3 -1
- package/dist/epub/index.js +3 -3
- package/dist/export-D2NkylDT.d.ts +69 -0
- package/dist/extract-H6RXJMHP.js +15 -0
- package/dist/extract-H6RXJMHP.js.map +1 -0
- package/dist/html/index.d.ts +15 -85
- package/dist/html/index.js +3 -3
- package/dist/images-7FBWPKE3.js +7 -0
- package/dist/images-7FBWPKE3.js.map +1 -0
- package/dist/import-DTkDxHmZ.d.ts +84 -0
- package/dist/import-K8mfc0fz.d.ts +136 -0
- package/dist/index.d.ts +14 -4
- package/dist/index.js +33 -12
- package/dist/infer/index.d.ts +138 -0
- package/dist/infer/index.js +28 -0
- package/dist/infer/index.js.map +1 -0
- package/dist/layouts-BHrgZ5FS.d.ts +150 -0
- package/dist/layouts-QVPK3ZCU.js +12 -0
- package/dist/layouts-QVPK3ZCU.js.map +1 -0
- package/dist/mapTheme-IR27S6IV.js +11 -0
- package/dist/mapTheme-IR27S6IV.js.map +1 -0
- package/dist/ooxml/index.d.ts +21 -127
- package/dist/ooxml/index.js +31 -9
- package/dist/pdf/index.d.ts +3 -1
- package/dist/pdf/index.js +1 -1
- package/dist/pptx/index.d.ts +8 -108
- package/dist/pptx/index.js +13 -4
- package/dist/reader-B9L8Ucbj.d.ts +140 -0
- package/dist/registry/index.d.ts +60 -8
- package/dist/registry/index.js +9 -4
- package/dist/themeReader-DJKErl_j.d.ts +56 -0
- package/dist/xlsx/index.d.ts +6 -66
- package/dist/xlsx/index.js +4 -2
- package/dist/zipLimits-BOKCB7qk.d.ts +31 -0
- package/package.json +8 -2
- package/src/__tests__/container.test.ts +41 -0
- package/src/__tests__/convert.test.ts +310 -1
- package/src/__tests__/epub.test.ts +102 -1
- package/src/__tests__/html.test.ts +62 -0
- package/src/__tests__/inferTheme.test.ts +135 -0
- package/src/__tests__/lossyWarnings.test.ts +41 -0
- package/src/__tests__/ooxml.test.ts +76 -2
- package/src/__tests__/ooxmlCancellation.test.ts +113 -0
- package/src/__tests__/ooxmlThemeReader.test.ts +92 -0
- package/src/__tests__/plainHtml.test.ts +15 -1
- package/src/__tests__/plainHtmlBundle.test.ts +18 -0
- package/src/__tests__/pptxImport.test.ts +30 -0
- package/src/__tests__/pptxInferFixtures.ts +314 -0
- package/src/__tests__/pptxLayoutInfer.test.ts +395 -0
- package/src/__tests__/zipSafety.test.ts +317 -0
- package/src/container/index.ts +37 -32
- package/src/docx/export.ts +4 -2
- package/src/docx/import.ts +4 -3
- package/src/epub/export.ts +94 -25
- package/src/html/docsHtmlBundle.ts +6 -2
- package/src/html/htmlTemplate.ts +31 -6
- package/src/html/imageUtils.ts +14 -5
- package/src/html/index.ts +12 -1
- package/src/html/plainHtml.ts +7 -3
- package/src/html/plainHtmlBundle.ts +11 -9
- package/src/index.ts +23 -0
- package/src/infer/extract.ts +127 -0
- package/src/infer/index.ts +199 -0
- package/src/infer/mapTheme.ts +176 -0
- package/src/infer/types.ts +27 -0
- package/src/ooxml/index.ts +14 -0
- package/src/ooxml/readUtils.ts +44 -0
- package/src/ooxml/reader.ts +129 -29
- package/src/ooxml/themeReader.ts +197 -0
- package/src/ooxml/types.ts +8 -9
- package/src/ooxml/writer.ts +28 -10
- package/src/pdf/export.ts +4 -2
- package/src/pdf/import.ts +40 -34
- package/src/pptx/export.ts +4 -2
- package/src/pptx/import.ts +214 -32
- package/src/pptx/index.ts +14 -0
- package/src/pptx/layouts.ts +1222 -0
- package/src/registry/convert.ts +168 -53
- package/src/registry/defaultFormats.ts +135 -45
- package/src/registry/index.ts +6 -1
- package/src/registry/types.ts +69 -6
- package/src/shared/boundedZipArchive.ts +383 -0
- package/src/shared/fidelity.ts +130 -0
- package/src/shared/zipEntryCount.ts +151 -0
- package/src/shared/zipLimits.ts +296 -0
- package/src/shared/zipSafety.ts +19 -0
- package/src/xlsx/import.ts +3 -2
- package/dist/chunk-46FMDOWZ.js.map +0 -1
- package/dist/chunk-5LSSWZPU.js.map +0 -1
- package/dist/chunk-D7IFPWNZ.js.map +0 -1
- package/dist/chunk-EHLGMSTE.js.map +0 -1
- package/dist/chunk-MJGRI6XR.js.map +0 -1
- package/dist/chunk-RTS5XBZ7.js.map +0 -1
- package/dist/chunk-SHLPSADL.js.map +0 -1
- package/dist/chunk-WWBIKRNP.js.map +0 -1
- package/dist/chunk-YESS7VY3.js.map +0 -1
- /package/dist/{chunk-DQAZR57U.js.map → chunk-O3GVVND4.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
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 {\n getPartRelationships,\n getPartXml,\n openPackage,\n throwIfOoxmlAborted,\n} 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;\nconst CANCELLATION_CHECKPOINT_INTERVAL = 128;\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\nasync function cancellationCheckpoint(index: number, signal?: AbortSignal): Promise<void> {\n throwIfOoxmlAborted(signal);\n if (index > 0 && index % CANCELLATION_CHECKPOINT_INTERVAL === 0) {\n await new Promise<void>((resolve) => setTimeout(resolve, 0));\n throwIfOoxmlAborted(signal);\n }\n}\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(\n pkg: OoxmlPackage,\n masterPath: string,\n signal?: AbortSignal,\n): Promise<MasterIndex> {\n throwIfOoxmlAborted(signal);\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 await cancellationCheckpoint(i, signal);\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 signal?: AbortSignal,\n): Promise<ExtractedSlideLayout | null> {\n throwIfOoxmlAborted(signal);\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, signal);\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 await cancellationCheckpoint(i, signal);\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(\n pkg: OoxmlPackage,\n signal?: AbortSignal,\n): Promise<{ cx: number; cy: number }> {\n throwIfOoxmlAborted(signal);\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(\n pkg: OoxmlPackage,\n signal?: AbortSignal,\n): Promise<string[]> {\n throwIfOoxmlAborted(signal);\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 await cancellationCheckpoint(i, signal);\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 throwIfOoxmlAborted(options.signal);\n const warnings: string[] = [];\n const hints = options.colors ?? {};\n const maxTemplates = options.maxTemplates ?? MAX_INFERRED_TEMPLATES;\n\n const sldSz = await readSlideSize(pkg, options.signal);\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, options.signal);\n const layoutPathBySlide = new Map<string, string>();\n const usage = new Map<string, number>();\n const orderedLayoutPaths: string[] = [];\n for (let slideIndex = 0; slideIndex < slidePaths.length; slideIndex++) {\n await cancellationCheckpoint(slideIndex, options.signal);\n const slidePath = slidePaths[slideIndex]!;\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 let partIndex = 0;\n for (const [partPath, contentType] of pkg.contentTypes.overrides) {\n await cancellationCheckpoint(partIndex++, options.signal);\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 await cancellationCheckpoint(i, options.signal);\n const layoutPath = orderedLayoutPaths[i]!;\n const extracted = await extractLayout(\n pkg,\n layoutPath,\n sldSz,\n pxPerPt,\n hints,\n masterCache,\n options.signal,\n );\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 const excess = ranked.slice(maxTemplates);\n for (let index = 0; index < excess.length; index++) {\n await cancellationCheckpoint(index, options.signal);\n const layout = excess[index]!;\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 throwIfOoxmlAborted(options.signal);\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 throwIfOoxmlAborted(options.signal);\n const pkg = await openPackage(data, options);\n const analysis = await analyzePptxLayouts(pkg, options);\n const layouts: PptxLayoutSummary[] = [];\n for (let i = 0; i < analysis.layouts.length; i++) {\n await cancellationCheckpoint(i, options.signal);\n const l = analysis.layouts[i]!;\n const { extracted, verdict, notes } = l;\n layouts.push({\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,7 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
} from "./chunk-U4MRIFKL.js";
|
|
2
|
+
openBoundedZipArchive
|
|
3
|
+
} from "./chunk-FE6OJV6O.js";
|
|
5
4
|
|
|
6
5
|
// src/ooxml/namespaces.ts
|
|
7
6
|
var NS_RELATIONSHIPS = "http://schemas.openxmlformats.org/package/2006/relationships";
|
|
@@ -51,184 +50,60 @@ var CONTENT_TYPE_XLSX_WORKSHEET = "application/vnd.openxmlformats-officedocument
|
|
|
51
50
|
var CONTENT_TYPE_XLSX_STYLES = "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml";
|
|
52
51
|
var REL_WORKSHEET = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet";
|
|
53
52
|
|
|
54
|
-
// src/ooxml/
|
|
55
|
-
import
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
addBinaryPart(path, data, contentType) {
|
|
65
|
-
parts.push({ path, binaryContent: data, contentType });
|
|
66
|
-
},
|
|
67
|
-
addRelationship(sourcePart, rel) {
|
|
68
|
-
relationships.push({ sourcePart, relationship: rel });
|
|
69
|
-
},
|
|
70
|
-
setCoreProperties(props) {
|
|
71
|
-
coreProps = props;
|
|
72
|
-
},
|
|
73
|
-
async toBlob() {
|
|
74
|
-
const zip = assemble(parts, relationships, coreProps);
|
|
75
|
-
return zip.generateAsync({ type: "blob" });
|
|
76
|
-
},
|
|
77
|
-
async toArrayBuffer() {
|
|
78
|
-
const zip = assemble(parts, relationships, coreProps);
|
|
79
|
-
return zip.generateAsync({ type: "arraybuffer" });
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
function assemble(parts, relationships, coreProps) {
|
|
84
|
-
const zip = new JSZip();
|
|
85
|
-
for (const part of parts) {
|
|
86
|
-
if (part.content !== void 0) {
|
|
87
|
-
zip.file(part.path, part.content);
|
|
88
|
-
} else if (part.binaryContent !== void 0) {
|
|
89
|
-
zip.file(part.path, part.binaryContent);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
if (coreProps) {
|
|
93
|
-
const coreXml = buildCorePropertiesXml(coreProps);
|
|
94
|
-
zip.file("docProps/core.xml", coreXml);
|
|
95
|
-
relationships.push({
|
|
96
|
-
sourcePart: "",
|
|
97
|
-
relationship: {
|
|
98
|
-
id: `rId${relationships.length + 100}`,
|
|
99
|
-
type: REL_CORE_PROPERTIES,
|
|
100
|
-
target: "docProps/core.xml"
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
zip.file("[Content_Types].xml", buildContentTypesXml(parts, coreProps));
|
|
105
|
-
const relsBySource = groupRelationshipsBySource(relationships);
|
|
106
|
-
for (const [sourcePart, rels] of relsBySource) {
|
|
107
|
-
const relsPath = sourcePart === "" ? "_rels/.rels" : buildRelsPath(sourcePart);
|
|
108
|
-
zip.file(relsPath, buildRelationshipsXml(rels));
|
|
109
|
-
}
|
|
110
|
-
return zip;
|
|
111
|
-
}
|
|
112
|
-
function buildContentTypesXml(parts, coreProps) {
|
|
113
|
-
const lines = [xmlDeclaration()];
|
|
114
|
-
lines.push(`<Types xmlns="${NS_CONTENT_TYPES}">`);
|
|
115
|
-
const extensionTypes = /* @__PURE__ */ new Map();
|
|
116
|
-
extensionTypes.set("rels", CONTENT_TYPE_RELATIONSHIPS);
|
|
117
|
-
extensionTypes.set("xml", "application/xml");
|
|
118
|
-
for (const part of parts) {
|
|
119
|
-
if (part.binaryContent !== void 0) {
|
|
120
|
-
const ext = getExtension(part.path);
|
|
121
|
-
if (ext && !extensionTypes.has(ext)) {
|
|
122
|
-
extensionTypes.set(ext, part.contentType);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
for (const [ext, ct] of extensionTypes) {
|
|
127
|
-
lines.push(` <Default Extension="${escapeXml(ext)}" ContentType="${escapeXml(ct)}"/>`);
|
|
128
|
-
}
|
|
129
|
-
for (const part of parts) {
|
|
130
|
-
if (part.content !== void 0) {
|
|
131
|
-
lines.push(
|
|
132
|
-
` <Override PartName="/${escapeXml(part.path)}" ContentType="${escapeXml(part.contentType)}"/>`
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
if (coreProps) {
|
|
137
|
-
lines.push(
|
|
138
|
-
` <Override PartName="/docProps/core.xml" ContentType="${CONTENT_TYPE_CORE_PROPERTIES}"/>`
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
|
-
lines.push("</Types>");
|
|
142
|
-
return lines.join("\n");
|
|
143
|
-
}
|
|
144
|
-
function buildRelationshipsXml(rels) {
|
|
145
|
-
const lines = [xmlDeclaration()];
|
|
146
|
-
lines.push(`<Relationships xmlns="${NS_RELATIONSHIPS}">`);
|
|
147
|
-
for (const rel of rels) {
|
|
148
|
-
const attrs = [
|
|
149
|
-
`Id="${escapeXml(rel.id)}"`,
|
|
150
|
-
`Type="${escapeXml(rel.type)}"`,
|
|
151
|
-
`Target="${escapeXml(rel.target)}"`
|
|
152
|
-
];
|
|
153
|
-
if (rel.targetMode) {
|
|
154
|
-
attrs.push(`TargetMode="${escapeXml(rel.targetMode)}"`);
|
|
155
|
-
}
|
|
156
|
-
lines.push(` <Relationship ${attrs.join(" ")}/>`);
|
|
157
|
-
}
|
|
158
|
-
lines.push("</Relationships>");
|
|
159
|
-
return lines.join("\n");
|
|
160
|
-
}
|
|
161
|
-
function buildCorePropertiesXml(props) {
|
|
162
|
-
const lines = [xmlDeclaration()];
|
|
163
|
-
lines.push(
|
|
164
|
-
`<cp:coreProperties xmlns:cp="${NS_CORE_PROPERTIES}" xmlns:dc="${NS_DC}" xmlns:dcterms="${NS_DCTERMS}" xmlns:xsi="${NS_XSI}">`
|
|
165
|
-
);
|
|
166
|
-
if (props.title) lines.push(` <dc:title>${escapeXml(props.title)}</dc:title>`);
|
|
167
|
-
if (props.subject) lines.push(` <dc:subject>${escapeXml(props.subject)}</dc:subject>`);
|
|
168
|
-
if (props.creator) lines.push(` <dc:creator>${escapeXml(props.creator)}</dc:creator>`);
|
|
169
|
-
if (props.description)
|
|
170
|
-
lines.push(` <dc:description>${escapeXml(props.description)}</dc:description>`);
|
|
171
|
-
if (props.keywords) lines.push(` <cp:keywords>${escapeXml(props.keywords)}</cp:keywords>`);
|
|
172
|
-
if (props.lastModifiedBy)
|
|
173
|
-
lines.push(` <cp:lastModifiedBy>${escapeXml(props.lastModifiedBy)}</cp:lastModifiedBy>`);
|
|
174
|
-
if (props.revision) lines.push(` <cp:revision>${escapeXml(props.revision)}</cp:revision>`);
|
|
175
|
-
if (props.created) {
|
|
176
|
-
lines.push(
|
|
177
|
-
` <dcterms:created xsi:type="dcterms:W3CDTF">${escapeXml(props.created)}</dcterms:created>`
|
|
178
|
-
);
|
|
179
|
-
}
|
|
180
|
-
if (props.modified) {
|
|
181
|
-
lines.push(
|
|
182
|
-
` <dcterms:modified xsi:type="dcterms:W3CDTF">${escapeXml(props.modified)}</dcterms:modified>`
|
|
183
|
-
);
|
|
184
|
-
}
|
|
185
|
-
lines.push("</cp:coreProperties>");
|
|
186
|
-
return lines.join("\n");
|
|
187
|
-
}
|
|
188
|
-
function getExtension(path) {
|
|
189
|
-
const dot = path.lastIndexOf(".");
|
|
190
|
-
if (dot === -1) return void 0;
|
|
191
|
-
return path.substring(dot + 1).toLowerCase();
|
|
53
|
+
// src/ooxml/reader.ts
|
|
54
|
+
import { DOMParser as XmldomDOMParser } from "@xmldom/xmldom";
|
|
55
|
+
var packageArchives = /* @__PURE__ */ new WeakMap();
|
|
56
|
+
var packageSignals = /* @__PURE__ */ new WeakMap();
|
|
57
|
+
var MAX_CONTENT_TYPES_BYTES = 1024 * 1024;
|
|
58
|
+
var MAX_RELATIONSHIPS_BYTES = 4 * 1024 * 1024;
|
|
59
|
+
var CANCELLATION_CHECKPOINT_INTERVAL = 256;
|
|
60
|
+
function throwIfOoxmlAborted(signal) {
|
|
61
|
+
if (!signal?.aborted) return;
|
|
62
|
+
throw signal.reason ?? new Error("OOXML operation was cancelled");
|
|
192
63
|
}
|
|
193
|
-
function
|
|
194
|
-
|
|
195
|
-
if (
|
|
196
|
-
|
|
64
|
+
async function cancellationCheckpoint(index, signal) {
|
|
65
|
+
throwIfOoxmlAborted(signal);
|
|
66
|
+
if (index > 0 && index % CANCELLATION_CHECKPOINT_INTERVAL === 0) {
|
|
67
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
68
|
+
throwIfOoxmlAborted(signal);
|
|
197
69
|
}
|
|
198
|
-
const dir = partPath.substring(0, lastSlash);
|
|
199
|
-
const file = partPath.substring(lastSlash + 1);
|
|
200
|
-
return `${dir}/_rels/${file}.rels`;
|
|
201
70
|
}
|
|
202
|
-
function
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
71
|
+
function parseXml(source, signal) {
|
|
72
|
+
throwIfOoxmlAborted(signal);
|
|
73
|
+
const runtime = globalThis;
|
|
74
|
+
const nativeParser = runtime.process?.versions?.node ? void 0 : runtime.DOMParser;
|
|
75
|
+
const Parser = nativeParser ?? XmldomDOMParser;
|
|
76
|
+
const doc = new Parser().parseFromString(source, "application/xml");
|
|
77
|
+
const parserErrors = doc.getElementsByTagName("parsererror");
|
|
78
|
+
if (parserErrors.length > 0) {
|
|
79
|
+
throw new Error(`Invalid OOXML XML part: ${parserErrors[0]?.textContent ?? "parse error"}`);
|
|
211
80
|
}
|
|
212
|
-
|
|
81
|
+
throwIfOoxmlAborted(signal);
|
|
82
|
+
return doc;
|
|
213
83
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
const
|
|
221
|
-
|
|
84
|
+
async function openPackage(data, limits = {}) {
|
|
85
|
+
throwIfOoxmlAborted(limits.signal);
|
|
86
|
+
const archive = await openBoundedZipArchive(data, limits);
|
|
87
|
+
const contentTypes = await parseContentTypes(archive, limits.signal);
|
|
88
|
+
const rootRelationships = await parseRelationships(archive, "", limits.signal);
|
|
89
|
+
throwIfOoxmlAborted(limits.signal);
|
|
90
|
+
const pkg = {
|
|
91
|
+
contentTypes,
|
|
92
|
+
rootRelationships
|
|
93
|
+
};
|
|
94
|
+
packageArchives.set(pkg, archive);
|
|
95
|
+
if (limits.signal) packageSignals.set(pkg, limits.signal);
|
|
96
|
+
return pkg;
|
|
222
97
|
}
|
|
223
|
-
async function parseContentTypes(
|
|
98
|
+
async function parseContentTypes(archive, signal) {
|
|
224
99
|
const overrides = /* @__PURE__ */ new Map();
|
|
225
100
|
const defaults = /* @__PURE__ */ new Map();
|
|
226
|
-
const
|
|
227
|
-
if (
|
|
228
|
-
const
|
|
229
|
-
const doc = new DOMParser().parseFromString(text, "application/xml");
|
|
101
|
+
const text = await archive.readText("[Content_Types].xml", MAX_CONTENT_TYPES_BYTES);
|
|
102
|
+
if (text === null) return { overrides, defaults };
|
|
103
|
+
const doc = parseXml(text, signal);
|
|
230
104
|
const defaultEls = doc.getElementsByTagName("Default");
|
|
231
105
|
for (let i = 0; i < defaultEls.length; i++) {
|
|
106
|
+
await cancellationCheckpoint(i, signal);
|
|
232
107
|
const el = defaultEls[i];
|
|
233
108
|
const ext = el.getAttribute("Extension");
|
|
234
109
|
const ct = el.getAttribute("ContentType");
|
|
@@ -236,6 +111,7 @@ async function parseContentTypes(zip) {
|
|
|
236
111
|
}
|
|
237
112
|
const overrideEls = doc.getElementsByTagName("Override");
|
|
238
113
|
for (let i = 0; i < overrideEls.length; i++) {
|
|
114
|
+
await cancellationCheckpoint(i, signal);
|
|
239
115
|
const el = overrideEls[i];
|
|
240
116
|
const partName = el.getAttribute("PartName");
|
|
241
117
|
const ct = el.getAttribute("ContentType");
|
|
@@ -246,18 +122,19 @@ async function parseContentTypes(zip) {
|
|
|
246
122
|
return { overrides, defaults };
|
|
247
123
|
}
|
|
248
124
|
async function getPartRelationships(pkg, partPath) {
|
|
249
|
-
return parseRelationships(pkg
|
|
125
|
+
return parseRelationships(pkg, partPath, packageSignals.get(pkg));
|
|
250
126
|
}
|
|
251
|
-
async function parseRelationships(
|
|
252
|
-
const relsPath = partPath === "" ? "_rels/.rels" :
|
|
253
|
-
const
|
|
254
|
-
if (!
|
|
255
|
-
const text =
|
|
256
|
-
const doc =
|
|
127
|
+
async function parseRelationships(source, partPath, signal) {
|
|
128
|
+
const relsPath = partPath === "" ? "_rels/.rels" : buildRelsPath(partPath);
|
|
129
|
+
const bytes = await readArchivePart(source, relsPath, MAX_RELATIONSHIPS_BYTES);
|
|
130
|
+
if (!bytes) return [];
|
|
131
|
+
const text = new TextDecoder().decode(bytes);
|
|
132
|
+
const doc = parseXml(text, signal);
|
|
257
133
|
const result = [];
|
|
258
134
|
const els = doc.getElementsByTagNameNS(NS_RELATIONSHIPS, "Relationship");
|
|
259
135
|
const fallbackEls = els.length > 0 ? els : doc.getElementsByTagName("Relationship");
|
|
260
136
|
for (let i = 0; i < fallbackEls.length; i++) {
|
|
137
|
+
await cancellationCheckpoint(i, signal);
|
|
261
138
|
const el = fallbackEls[i];
|
|
262
139
|
const id = el.getAttribute("Id");
|
|
263
140
|
const type = el.getAttribute("Type");
|
|
@@ -274,7 +151,7 @@ async function parseRelationships(zip, partPath) {
|
|
|
274
151
|
}
|
|
275
152
|
return result;
|
|
276
153
|
}
|
|
277
|
-
function
|
|
154
|
+
function buildRelsPath(partPath) {
|
|
278
155
|
const lastSlash = partPath.lastIndexOf("/");
|
|
279
156
|
if (lastSlash === -1) {
|
|
280
157
|
return `_rels/${partPath}.rels`;
|
|
@@ -284,17 +161,30 @@ function buildRelsPath2(partPath) {
|
|
|
284
161
|
return `${dir}/_rels/${file}.rels`;
|
|
285
162
|
}
|
|
286
163
|
async function getPartXml(pkg, partPath) {
|
|
287
|
-
const
|
|
288
|
-
|
|
289
|
-
const
|
|
290
|
-
return new
|
|
164
|
+
const signal = packageSignals.get(pkg);
|
|
165
|
+
throwIfOoxmlAborted(signal);
|
|
166
|
+
const bytes = await readPackagePart(pkg, partPath);
|
|
167
|
+
return bytes ? parseXml(new TextDecoder().decode(bytes), signal) : null;
|
|
291
168
|
}
|
|
292
169
|
async function getPartBinary(pkg, partPath) {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
return
|
|
170
|
+
throwIfOoxmlAborted(packageSignals.get(pkg));
|
|
171
|
+
const bytes = await readPackagePart(pkg, partPath);
|
|
172
|
+
return bytes ? bytes.slice().buffer : null;
|
|
173
|
+
}
|
|
174
|
+
function readArchivePart(source, path, maxBytes) {
|
|
175
|
+
return "entries" in source ? source.read(path, maxBytes) : readPackagePart(source, path, maxBytes);
|
|
176
|
+
}
|
|
177
|
+
async function readPackagePart(pkg, path, maxBytes) {
|
|
178
|
+
throwIfOoxmlAborted(packageSignals.get(pkg));
|
|
179
|
+
const archive = packageArchives.get(pkg);
|
|
180
|
+
if (!archive) {
|
|
181
|
+
throw new TypeError("Invalid OoxmlPackage: create packages with openPackage().");
|
|
182
|
+
}
|
|
183
|
+
return archive.read(path, maxBytes);
|
|
296
184
|
}
|
|
297
185
|
async function getCoreProperties(pkg) {
|
|
186
|
+
const signal = packageSignals.get(pkg);
|
|
187
|
+
throwIfOoxmlAborted(signal);
|
|
298
188
|
const doc = await getPartXml(pkg, "docProps/core.xml");
|
|
299
189
|
if (!doc) return {};
|
|
300
190
|
function getText(ns, localName) {
|
|
@@ -304,7 +194,7 @@ async function getCoreProperties(pkg) {
|
|
|
304
194
|
}
|
|
305
195
|
return void 0;
|
|
306
196
|
}
|
|
307
|
-
|
|
197
|
+
const properties = {
|
|
308
198
|
title: getText(NS_DC, "title"),
|
|
309
199
|
subject: getText(NS_DC, "subject"),
|
|
310
200
|
creator: getText(NS_DC, "creator"),
|
|
@@ -315,6 +205,8 @@ async function getCoreProperties(pkg) {
|
|
|
315
205
|
created: getText(NS_DCTERMS, "created"),
|
|
316
206
|
modified: getText(NS_DCTERMS, "modified")
|
|
317
207
|
};
|
|
208
|
+
throwIfOoxmlAborted(signal);
|
|
209
|
+
return properties;
|
|
318
210
|
}
|
|
319
211
|
|
|
320
212
|
export {
|
|
@@ -364,11 +256,11 @@ export {
|
|
|
364
256
|
CONTENT_TYPE_XLSX_WORKSHEET,
|
|
365
257
|
CONTENT_TYPE_XLSX_STYLES,
|
|
366
258
|
REL_WORKSHEET,
|
|
367
|
-
|
|
259
|
+
throwIfOoxmlAborted,
|
|
368
260
|
openPackage,
|
|
369
261
|
getPartRelationships,
|
|
370
262
|
getPartXml,
|
|
371
263
|
getPartBinary,
|
|
372
264
|
getCoreProperties
|
|
373
265
|
};
|
|
374
|
-
//# sourceMappingURL=chunk-
|
|
266
|
+
//# sourceMappingURL=chunk-WC7WULGV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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 the\n * package-owned xmldom parser in 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 packageSignals = new WeakMap<OoxmlPackage, AbortSignal>();\nconst MAX_CONTENT_TYPES_BYTES = 1024 * 1024;\nconst MAX_RELATIONSHIPS_BYTES = 4 * 1024 * 1024;\nconst CANCELLATION_CHECKPOINT_INTERVAL = 256;\n\n/** Preserve the caller's exact cancellation reason across OOXML traversal. */\nexport function throwIfOoxmlAborted(signal?: AbortSignal): void {\n if (!signal?.aborted) return;\n throw signal.reason ?? new Error('OOXML operation was cancelled');\n}\n\nasync function cancellationCheckpoint(index: number, signal?: AbortSignal): Promise<void> {\n throwIfOoxmlAborted(signal);\n if (index > 0 && index % CANCELLATION_CHECKPOINT_INTERVAL === 0) {\n await new Promise<void>((resolve) => setTimeout(resolve, 0));\n throwIfOoxmlAborted(signal);\n }\n}\n\n/**\n * Parse XML in browsers and Node. Test runners and SSR hosts can install a\n * partial browser DOMParser whose namespace behavior differs from browsers,\n * so Node always uses the package-owned, namespace-aware xmldom parser.\n */\nfunction parseXml(source: string, signal?: AbortSignal): Document {\n throwIfOoxmlAborted(signal);\n const runtime = globalThis as {\n DOMParser?: DomParserLike;\n process?: { versions?: { node?: string } };\n };\n const nativeParser = runtime.process?.versions?.node ? undefined : runtime.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 throwIfOoxmlAborted(signal);\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 throwIfOoxmlAborted(limits.signal);\n const archive = await openBoundedZipArchive(data, limits);\n const contentTypes = await parseContentTypes(archive, limits.signal);\n const rootRelationships = await parseRelationships(archive, '', limits.signal);\n throwIfOoxmlAborted(limits.signal);\n\n const pkg = {\n contentTypes,\n rootRelationships,\n } as unknown as OoxmlPackage;\n packageArchives.set(pkg, archive);\n if (limits.signal) packageSignals.set(pkg, limits.signal);\n return pkg;\n}\n\n// ============================================\n// Content Types\n// ============================================\n\n/**\n * Parse [Content_Types].xml from the archive.\n */\nasync function parseContentTypes(\n archive: BoundedZipArchive,\n signal?: AbortSignal,\n): 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, signal);\n\n // Parse <Default Extension=\"rels\" ContentType=\"...\" />\n const defaultEls = doc.getElementsByTagName('Default');\n for (let i = 0; i < defaultEls.length; i++) {\n await cancellationCheckpoint(i, signal);\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 await cancellationCheckpoint(i, signal);\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, packageSignals.get(pkg));\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 signal?: AbortSignal,\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, signal);\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 await cancellationCheckpoint(i, signal);\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 signal = packageSignals.get(pkg);\n throwIfOoxmlAborted(signal);\n const bytes = await readPackagePart(pkg, partPath);\n return bytes ? parseXml(new TextDecoder().decode(bytes), signal) : 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 throwIfOoxmlAborted(packageSignals.get(pkg));\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 throwIfOoxmlAborted(packageSignals.get(pkg));\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 signal = packageSignals.get(pkg);\n throwIfOoxmlAborted(signal);\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 const properties = {\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 throwIfOoxmlAborted(signal);\n return properties;\n}\n"],"mappings":"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","names":[]}
|