@bendyline/squisq-formats 2.0.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (195) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE.md +20 -0
  3. package/README.md +1 -1
  4. package/dist/{chunk-CRAVSMPZ.js → chunk-26ISNJ7Y.js} +356 -114
  5. package/dist/{chunk-NKAJPJ4G.js → chunk-2JJ5RFDZ.js} +0 -1
  6. package/dist/{chunk-HTW2M27H.js → chunk-3NKXBZSR.js} +193 -42
  7. package/dist/{chunk-U32AG3G3.js → chunk-4V3KCHAP.js} +3 -4
  8. package/dist/{chunk-MLX2BOJC.js → chunk-6RQOV3B3.js} +1 -2
  9. package/dist/{chunk-QRVN6A6E.js → chunk-6S6GU3ZG.js} +5 -6
  10. package/dist/{chunk-FE6OJV6O.js → chunk-7AWFHP5U.js} +1 -1
  11. package/dist/{chunk-RFAPOKHJ.js → chunk-AD2WT564.js} +59 -9
  12. package/dist/{chunk-O3GVVND4.js → chunk-AONELFLA.js} +0 -1
  13. package/dist/{chunk-XKUMNGBW.js → chunk-EJTNGKEA.js} +5 -8
  14. package/dist/chunk-GX7RAUME.js +121 -0
  15. package/dist/{chunk-SSUPBUF5.js → chunk-IIQYS2YH.js} +0 -1
  16. package/dist/{chunk-ABVI556T.js → chunk-IPN56VLW.js} +83 -58
  17. package/dist/{chunk-LXYLOOST.js → chunk-JE6LSIHE.js} +83 -22
  18. package/dist/{chunk-U4MRIFKL.js → chunk-JU2RHXUB.js} +0 -1
  19. package/dist/{chunk-4VUWTSGM.js → chunk-K6XRMVPW.js} +64 -31
  20. package/dist/{chunk-ODL3SSPT.js → chunk-KXOZMWBS.js} +0 -1
  21. package/dist/chunk-OGS5VCGJ.js +446 -0
  22. package/dist/{chunk-GVS2XXV6.js → chunk-PJXJI2LY.js} +449 -57
  23. package/dist/{chunk-2KPARF2P.js → chunk-PU7REGWV.js} +5 -8
  24. package/dist/{chunk-PN52A5AA.js → chunk-SBUW7NHR.js} +0 -1
  25. package/dist/{chunk-VSYHZECT.js → chunk-TAAENIRB.js} +5 -8
  26. package/dist/{chunk-WC7WULGV.js → chunk-X2DEAXNK.js} +62 -2
  27. package/dist/container/index.js +1 -2
  28. package/dist/csv/index.d.ts +27 -2
  29. package/dist/csv/index.js +1 -2
  30. package/dist/docx/index.d.ts +5 -1
  31. package/dist/docx/index.js +9 -10
  32. package/dist/epub/index.d.ts +2 -0
  33. package/dist/epub/index.js +5 -6
  34. package/dist/{export-D2NkylDT.d.ts → export-D9msROJS.d.ts} +18 -6
  35. package/dist/extract-MN7LA3NL.js +13 -0
  36. package/dist/html/index.d.ts +11 -4
  37. package/dist/html/index.js +3 -4
  38. package/dist/images-ESPQKVTW.js +6 -0
  39. package/dist/{import-K8mfc0fz.d.ts → import-C3htUTss.d.ts} +5 -1
  40. package/dist/{import-DTkDxHmZ.d.ts → import-C8whCC7_.d.ts} +6 -0
  41. package/dist/index.d.ts +7 -7
  42. package/dist/index.js +28 -26
  43. package/dist/infer/index.d.ts +3 -3
  44. package/dist/infer/index.js +7 -9
  45. package/dist/{layouts-BHrgZ5FS.d.ts → layouts-CTdPlB-u.d.ts} +1 -1
  46. package/dist/layouts-DRWZGSPD.js +10 -0
  47. package/dist/{mapTheme-IR27S6IV.js → mapTheme-4TWH25FT.js} +1 -2
  48. package/dist/ooxml/index.d.ts +3 -3
  49. package/dist/ooxml/index.js +14 -13
  50. package/dist/pdf/index.d.ts +18 -0
  51. package/dist/pdf/index.js +2 -3
  52. package/dist/pptx/index.d.ts +4 -4
  53. package/dist/pptx/index.js +11 -13
  54. package/dist/{reader-B9L8Ucbj.d.ts → reader-B_m1aKZC.d.ts} +30 -1
  55. package/dist/registry/index.d.ts +21 -5
  56. package/dist/registry/index.js +9 -6
  57. package/dist/{themeReader-DJKErl_j.d.ts → themeReader-DCtwC83Q.d.ts} +1 -1
  58. package/dist/xlsx/index.d.ts +3 -3
  59. package/dist/xlsx/index.js +6 -7
  60. package/package.json +6 -3
  61. package/dist/chunk-2KPARF2P.js.map +0 -1
  62. package/dist/chunk-4VUWTSGM.js.map +0 -1
  63. package/dist/chunk-6M7Z25LA.js +0 -46
  64. package/dist/chunk-6M7Z25LA.js.map +0 -1
  65. package/dist/chunk-ABVI556T.js.map +0 -1
  66. package/dist/chunk-CRAVSMPZ.js.map +0 -1
  67. package/dist/chunk-FE6OJV6O.js.map +0 -1
  68. package/dist/chunk-GVS2XXV6.js.map +0 -1
  69. package/dist/chunk-HTW2M27H.js.map +0 -1
  70. package/dist/chunk-LXYLOOST.js.map +0 -1
  71. package/dist/chunk-MLX2BOJC.js.map +0 -1
  72. package/dist/chunk-NKAJPJ4G.js.map +0 -1
  73. package/dist/chunk-O3GVVND4.js.map +0 -1
  74. package/dist/chunk-ODL3SSPT.js.map +0 -1
  75. package/dist/chunk-PN52A5AA.js.map +0 -1
  76. package/dist/chunk-QRVN6A6E.js.map +0 -1
  77. package/dist/chunk-RFAPOKHJ.js.map +0 -1
  78. package/dist/chunk-SSUPBUF5.js.map +0 -1
  79. package/dist/chunk-U32AG3G3.js.map +0 -1
  80. package/dist/chunk-U4MRIFKL.js.map +0 -1
  81. package/dist/chunk-VJJM2SSH.js +0 -275
  82. package/dist/chunk-VJJM2SSH.js.map +0 -1
  83. package/dist/chunk-VSYHZECT.js.map +0 -1
  84. package/dist/chunk-WC7WULGV.js.map +0 -1
  85. package/dist/chunk-XKUMNGBW.js.map +0 -1
  86. package/dist/chunk-YRT7GQ5Y.js +0 -28
  87. package/dist/chunk-YRT7GQ5Y.js.map +0 -1
  88. package/dist/container/index.js.map +0 -1
  89. package/dist/csv/index.js.map +0 -1
  90. package/dist/docx/index.js.map +0 -1
  91. package/dist/epub/index.js.map +0 -1
  92. package/dist/extract-H6RXJMHP.js +0 -15
  93. package/dist/extract-H6RXJMHP.js.map +0 -1
  94. package/dist/html/index.js.map +0 -1
  95. package/dist/images-7FBWPKE3.js +0 -7
  96. package/dist/images-7FBWPKE3.js.map +0 -1
  97. package/dist/index.js.map +0 -1
  98. package/dist/infer/index.js.map +0 -1
  99. package/dist/layouts-QVPK3ZCU.js +0 -12
  100. package/dist/layouts-QVPK3ZCU.js.map +0 -1
  101. package/dist/mapTheme-IR27S6IV.js.map +0 -1
  102. package/dist/ooxml/index.js.map +0 -1
  103. package/dist/pdf/index.js.map +0 -1
  104. package/dist/pptx/index.js.map +0 -1
  105. package/dist/registry/index.js.map +0 -1
  106. package/dist/xlsx/index.js.map +0 -1
  107. package/src/__tests__/container.test.ts +0 -230
  108. package/src/__tests__/convert.test.ts +0 -495
  109. package/src/__tests__/csvImport.test.ts +0 -84
  110. package/src/__tests__/docxExport.test.ts +0 -457
  111. package/src/__tests__/docxImport.test.ts +0 -410
  112. package/src/__tests__/epub.test.ts +0 -649
  113. package/src/__tests__/exportThemeReconciliation.test.ts +0 -87
  114. package/src/__tests__/formatRegistry.test.ts +0 -174
  115. package/src/__tests__/html.test.ts +0 -435
  116. package/src/__tests__/htmlImport.test.ts +0 -57
  117. package/src/__tests__/inferTheme.test.ts +0 -135
  118. package/src/__tests__/lossyWarnings.test.ts +0 -146
  119. package/src/__tests__/ooxml.test.ts +0 -271
  120. package/src/__tests__/ooxmlCancellation.test.ts +0 -113
  121. package/src/__tests__/ooxmlThemeReader.test.ts +0 -92
  122. package/src/__tests__/pdfExport.test.ts +0 -322
  123. package/src/__tests__/pdfImport.test.ts +0 -384
  124. package/src/__tests__/plainHtml.test.ts +0 -417
  125. package/src/__tests__/plainHtmlBundle.test.ts +0 -253
  126. package/src/__tests__/pptxExport.test.ts +0 -138
  127. package/src/__tests__/pptxImport.test.ts +0 -145
  128. package/src/__tests__/pptxInferFixtures.ts +0 -314
  129. package/src/__tests__/pptxLayoutInfer.test.ts +0 -395
  130. package/src/__tests__/roundTrip.test.ts +0 -201
  131. package/src/__tests__/roundTripAssets.test.ts +0 -50
  132. package/src/__tests__/roundTripMatrix.fixtures.ts +0 -86
  133. package/src/__tests__/roundTripMatrix.helpers.ts +0 -154
  134. package/src/__tests__/roundTripMatrix.test.ts +0 -142
  135. package/src/__tests__/sharedContainer.test.ts +0 -41
  136. package/src/__tests__/sharedImages.test.ts +0 -61
  137. package/src/__tests__/xlsxExport.test.ts +0 -164
  138. package/src/__tests__/xlsxImport.test.ts +0 -80
  139. package/src/__tests__/zipSafety.test.ts +0 -317
  140. package/src/container/index.ts +0 -94
  141. package/src/csv/index.ts +0 -188
  142. package/src/docx/export.ts +0 -1267
  143. package/src/docx/import.ts +0 -995
  144. package/src/docx/index.ts +0 -26
  145. package/src/docx/styles.ts +0 -145
  146. package/src/epub/export.ts +0 -968
  147. package/src/epub/index.ts +0 -20
  148. package/src/html/docsHtmlBundle.ts +0 -373
  149. package/src/html/htmlTemplate.ts +0 -385
  150. package/src/html/imageUtils.ts +0 -61
  151. package/src/html/import.ts +0 -297
  152. package/src/html/index.ts +0 -212
  153. package/src/html/plainHtml.ts +0 -790
  154. package/src/html/plainHtmlBundle.ts +0 -421
  155. package/src/index.ts +0 -109
  156. package/src/infer/extract.ts +0 -127
  157. package/src/infer/index.ts +0 -199
  158. package/src/infer/mapTheme.ts +0 -176
  159. package/src/infer/types.ts +0 -27
  160. package/src/ooxml/index.ts +0 -111
  161. package/src/ooxml/namespaces.ts +0 -196
  162. package/src/ooxml/readUtils.ts +0 -44
  163. package/src/ooxml/reader.ts +0 -318
  164. package/src/ooxml/themeReader.ts +0 -197
  165. package/src/ooxml/types.ts +0 -103
  166. package/src/ooxml/writer.ts +0 -339
  167. package/src/ooxml/xmlUtils.ts +0 -123
  168. package/src/pdf/export.ts +0 -1084
  169. package/src/pdf/import.ts +0 -1164
  170. package/src/pdf/index.ts +0 -29
  171. package/src/pdf/styles.ts +0 -180
  172. package/src/pptx/export.ts +0 -1184
  173. package/src/pptx/import.ts +0 -455
  174. package/src/pptx/index.ts +0 -52
  175. package/src/pptx/layouts.ts +0 -1222
  176. package/src/pptx/styles.ts +0 -96
  177. package/src/pptx/templates.ts +0 -187
  178. package/src/registry/convert.ts +0 -433
  179. package/src/registry/defaultFormats.ts +0 -413
  180. package/src/registry/errors.ts +0 -46
  181. package/src/registry/index.ts +0 -43
  182. package/src/registry/registry.ts +0 -48
  183. package/src/registry/types.ts +0 -170
  184. package/src/shared/boundedZipArchive.ts +0 -383
  185. package/src/shared/container.ts +0 -28
  186. package/src/shared/fidelity.ts +0 -130
  187. package/src/shared/images.ts +0 -44
  188. package/src/shared/inlineRuns.ts +0 -99
  189. package/src/shared/text.ts +0 -41
  190. package/src/shared/zipEntryCount.ts +0 -151
  191. package/src/shared/zipLimits.ts +0 -296
  192. package/src/shared/zipSafety.ts +0 -19
  193. package/src/xlsx/export.ts +0 -253
  194. package/src/xlsx/import.ts +0 -160
  195. package/src/xlsx/index.ts +0 -35
@@ -1,275 +0,0 @@
1
- import {
2
- extractPlainText
3
- } from "./chunk-PN52A5AA.js";
4
- import {
5
- createPackage
6
- } from "./chunk-U32AG3G3.js";
7
- import {
8
- escapeXml,
9
- xmlDeclaration
10
- } from "./chunk-U4MRIFKL.js";
11
- import {
12
- CONTENT_TYPE_XLSX_STYLES,
13
- CONTENT_TYPE_XLSX_WORKBOOK,
14
- CONTENT_TYPE_XLSX_WORKSHEET,
15
- NS_R,
16
- NS_SML,
17
- REL_OFFICE_DOCUMENT,
18
- REL_STYLES,
19
- REL_WORKSHEET,
20
- getPartRelationships,
21
- getPartXml,
22
- openPackage
23
- } from "./chunk-WC7WULGV.js";
24
-
25
- // src/xlsx/index.ts
26
- import { markdownToDoc } from "@bendyline/squisq/doc";
27
-
28
- // src/xlsx/import.ts
29
- function attrNS(el, ns, local, fallback) {
30
- return el.getAttributeNS(ns, local) ?? el.getAttribute(fallback);
31
- }
32
- function resolveTarget(baseDir, target) {
33
- if (target.startsWith("/")) return target.replace(/^\//, "");
34
- const stack = baseDir ? baseDir.split("/") : [];
35
- for (const seg of target.split("/")) {
36
- if (seg === "..") stack.pop();
37
- else if (seg !== ".") stack.push(seg);
38
- }
39
- return stack.join("/");
40
- }
41
- async function readSheets(pkg) {
42
- const wb = await getPartXml(pkg, "xl/workbook.xml");
43
- if (!wb) return [];
44
- const rels = await getPartRelationships(pkg, "xl/workbook.xml");
45
- const relById = new Map(rels.map((r) => [r.id, r.target]));
46
- const out = [];
47
- const sheetEls = wb.getElementsByTagNameNS(NS_SML, "sheet");
48
- for (let i = 0; i < sheetEls.length; i++) {
49
- const el = sheetEls[i];
50
- const name = el.getAttribute("name") ?? `Sheet${i + 1}`;
51
- const rid = attrNS(el, NS_R, "id", "r:id");
52
- const target = rid ? relById.get(rid) : void 0;
53
- if (target) out.push({ name, path: resolveTarget("xl", target) });
54
- }
55
- return out;
56
- }
57
- async function readSharedStrings(pkg) {
58
- const doc = await getPartXml(pkg, "xl/sharedStrings.xml");
59
- if (!doc) return [];
60
- const siEls = doc.getElementsByTagNameNS(NS_SML, "si");
61
- const out = [];
62
- for (let i = 0; i < siEls.length; i++) out.push(siEls[i].textContent ?? "");
63
- return out;
64
- }
65
- function colIndex(ref) {
66
- const m = /^([A-Za-z]+)/.exec(ref);
67
- if (!m) return 0;
68
- let n = 0;
69
- for (const ch of m[1].toUpperCase()) n = n * 26 + (ch.charCodeAt(0) - 64);
70
- return n - 1;
71
- }
72
- function cellText(cell, shared) {
73
- const t = cell.getAttribute("t");
74
- if (t === "inlineStr") {
75
- const is = cell.getElementsByTagNameNS(NS_SML, "t");
76
- return is.length ? is[0].textContent ?? "" : "";
77
- }
78
- const vEls = cell.getElementsByTagNameNS(NS_SML, "v");
79
- const v = vEls.length ? vEls[0].textContent ?? "" : "";
80
- if (t === "s") return shared[Number.parseInt(v, 10)] ?? "";
81
- if (t === "b") return v === "1" ? "TRUE" : "FALSE";
82
- return v;
83
- }
84
- async function sheetToGrid(pkg, path, shared) {
85
- const doc = await getPartXml(pkg, path);
86
- if (!doc) return [];
87
- const rowEls = doc.getElementsByTagNameNS(NS_SML, "row");
88
- const grid = [];
89
- for (let r = 0; r < rowEls.length; r++) {
90
- const cells = rowEls[r].getElementsByTagNameNS(NS_SML, "c");
91
- const rowArr = [];
92
- for (let c = 0; c < cells.length; c++) {
93
- const cell = cells[c];
94
- const ref = cell.getAttribute("r");
95
- const idx = ref ? colIndex(ref) : rowArr.length;
96
- while (rowArr.length < idx) rowArr.push("");
97
- rowArr[idx] = cellText(cell, shared);
98
- }
99
- grid.push(rowArr);
100
- }
101
- return grid;
102
- }
103
- function gridToTable(grid) {
104
- const maxCols = grid.reduce((m, r) => Math.max(m, r.length), 1);
105
- const rows = grid.map((cells, rowIdx) => {
106
- const children = [];
107
- for (let c = 0; c < maxCols; c++) {
108
- const value = cells[c] ?? "";
109
- children.push({
110
- type: "tableCell",
111
- ...rowIdx === 0 ? { isHeader: true } : {},
112
- children: value ? [{ type: "text", value }] : []
113
- });
114
- }
115
- return { type: "tableRow", children };
116
- });
117
- return { type: "table", children: rows };
118
- }
119
- async function xlsxToMarkdownDoc(data, options = {}) {
120
- const pkg = await openPackage(data, options);
121
- const sheets = await readSheets(pkg);
122
- const shared = await readSharedStrings(pkg);
123
- let selected = sheets;
124
- if (options.sheet !== void 0) {
125
- const picked = typeof options.sheet === "number" ? sheets[options.sheet] : sheets.find((s) => s.name === options.sheet);
126
- selected = picked ? [picked] : [];
127
- }
128
- const children = [];
129
- const single = selected.length === 1 && options.sheet !== void 0;
130
- for (const sheet of selected) {
131
- const grid = await sheetToGrid(pkg, sheet.path, shared);
132
- if (!single) {
133
- children.push({ type: "heading", depth: 1, children: [{ type: "text", value: sheet.name }] });
134
- }
135
- if (grid.length > 0) children.push(gridToTable(grid));
136
- }
137
- return { type: "document", children };
138
- }
139
-
140
- // src/xlsx/export.ts
141
- import { docToMarkdown } from "@bendyline/squisq/doc";
142
- var NUMERIC_RE = /^-?\d+(\.\d+)?$/;
143
- function sanitizeSheetName(raw, used, fallback) {
144
- let name = raw.replace(/[[\]:*?/\\]/g, "").trim();
145
- if (name.length === 0) name = fallback;
146
- name = name.slice(0, 31);
147
- if (!used.has(name)) {
148
- used.add(name);
149
- return name;
150
- }
151
- for (let n = 2; ; n++) {
152
- const suffix = String(n);
153
- const base = name.slice(0, 31 - suffix.length);
154
- const candidate = `${base}${suffix}`;
155
- if (!used.has(candidate)) {
156
- used.add(candidate);
157
- return candidate;
158
- }
159
- }
160
- }
161
- function tableToGrid(table) {
162
- return table.children.map(
163
- (row) => row.children.map((cell) => extractPlainText(cell.children))
164
- );
165
- }
166
- function collectSheets(doc, prefix) {
167
- const used = /* @__PURE__ */ new Set();
168
- const sheets = [];
169
- let pendingHeading = null;
170
- const visit = (nodes) => {
171
- for (const node of nodes) {
172
- if (node.type === "heading") {
173
- pendingHeading = extractPlainText(node.children);
174
- } else if (node.type === "table") {
175
- const fallback = `${prefix}${sheets.length + 1}`;
176
- const name = sanitizeSheetName(pendingHeading ?? fallback, used, fallback);
177
- sheets.push({ name, grid: tableToGrid(node) });
178
- pendingHeading = null;
179
- }
180
- }
181
- };
182
- visit(doc.children);
183
- return sheets;
184
- }
185
- function columnLetter(index) {
186
- let n = index + 1;
187
- let letters = "";
188
- while (n > 0) {
189
- const rem = (n - 1) % 26;
190
- letters = String.fromCharCode(65 + rem) + letters;
191
- n = Math.floor((n - 1) / 26);
192
- }
193
- return letters;
194
- }
195
- function cellXml(value, ref) {
196
- if (NUMERIC_RE.test(value)) {
197
- return `<c r="${ref}"><v>${escapeXml(value)}</v></c>`;
198
- }
199
- return `<c r="${ref}" t="inlineStr"><is><t xml:space="preserve">${escapeXml(value)}</t></is></c>`;
200
- }
201
- function worksheetXml(grid) {
202
- const rows = [];
203
- for (let r = 0; r < grid.length; r++) {
204
- const cells = grid[r];
205
- const cellsXml = cells.map((value, c) => cellXml(value, `${columnLetter(c)}${r + 1}`)).join("");
206
- rows.push(`<row r="${r + 1}">${cellsXml}</row>`);
207
- }
208
- return `${xmlDeclaration()}
209
- <worksheet xmlns="${NS_SML}" xmlns:r="${NS_R}"><sheetData>${rows.join("")}</sheetData></worksheet>`;
210
- }
211
- function workbookXml(sheets) {
212
- const sheetEls = sheets.map(
213
- (sheet, i) => `<sheet name="${escapeXml(sheet.name)}" sheetId="${i + 1}" r:id="rId${i + 1}"/>`
214
- ).join("");
215
- return `${xmlDeclaration()}
216
- <workbook xmlns="${NS_SML}" xmlns:r="${NS_R}"><sheets>${sheetEls}</sheets></workbook>`;
217
- }
218
- function stylesXml() {
219
- return `${xmlDeclaration()}
220
- <styleSheet xmlns="${NS_SML}"><fonts count="1"><font><sz val="11"/><name val="Calibri"/></font></fonts><fills count="1"><fill><patternFill patternType="none"/></fill></fills><borders count="1"><border/></borders><cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs><cellXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0" xfId="0"/></cellXfs></styleSheet>`;
221
- }
222
- async function markdownDocToXlsx(doc, options = {}) {
223
- const prefix = options.sheetNamePrefix ?? "Sheet";
224
- let sheets = collectSheets(doc, prefix);
225
- if (sheets.length === 0) {
226
- sheets = [{ name: `${prefix}1`, grid: [] }];
227
- }
228
- const pkg = createPackage();
229
- sheets.forEach((sheet, i) => {
230
- const sheetPath = `xl/worksheets/sheet${i + 1}.xml`;
231
- pkg.addPart(sheetPath, worksheetXml(sheet.grid), CONTENT_TYPE_XLSX_WORKSHEET);
232
- pkg.addRelationship("xl/workbook.xml", {
233
- id: `rId${i + 1}`,
234
- type: REL_WORKSHEET,
235
- target: `worksheets/sheet${i + 1}.xml`
236
- });
237
- });
238
- pkg.addPart("xl/styles.xml", stylesXml(), CONTENT_TYPE_XLSX_STYLES);
239
- pkg.addRelationship("xl/workbook.xml", {
240
- id: `rId${sheets.length + 1}`,
241
- type: REL_STYLES,
242
- target: "styles.xml"
243
- });
244
- pkg.addPart("xl/workbook.xml", workbookXml(sheets), CONTENT_TYPE_XLSX_WORKBOOK);
245
- pkg.addRelationship("", {
246
- id: "rId1",
247
- type: REL_OFFICE_DOCUMENT,
248
- target: "xl/workbook.xml"
249
- });
250
- if (options.title || options.author) {
251
- pkg.setCoreProperties({
252
- title: options.title,
253
- creator: options.author,
254
- created: (/* @__PURE__ */ new Date()).toISOString(),
255
- modified: (/* @__PURE__ */ new Date()).toISOString()
256
- });
257
- }
258
- return pkg.toArrayBuffer();
259
- }
260
- async function docToXlsx(doc, options) {
261
- return markdownDocToXlsx(docToMarkdown(doc), options);
262
- }
263
-
264
- // src/xlsx/index.ts
265
- async function xlsxToDoc(data, options) {
266
- return markdownToDoc(await xlsxToMarkdownDoc(data, options));
267
- }
268
-
269
- export {
270
- xlsxToMarkdownDoc,
271
- markdownDocToXlsx,
272
- docToXlsx,
273
- xlsxToDoc
274
- };
275
- //# sourceMappingURL=chunk-VJJM2SSH.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/xlsx/index.ts","../src/xlsx/import.ts","../src/xlsx/export.ts"],"sourcesContent":["/**\n * @bendyline/squisq-formats XLSX Module\n *\n * Excel .xlsx support via SpreadsheetML and the shared ooxml/ infrastructure.\n * Both directions are implemented: import (`xlsxToMarkdownDoc` / `xlsxToDoc`)\n * turns each worksheet grid into a markdown table; export (`markdownDocToXlsx`\n * / `docToXlsx`) turns each markdown table into a worksheet. Export is\n * tables-only fidelity — non-table content is dropped (headings only survive\n * as sheet names). See export.ts for details.\n *\n * @example\n * ```ts\n * import { xlsxToMarkdownDoc, markdownDocToXlsx } from '@bendyline/squisq-formats/xlsx';\n * ```\n */\n\nimport { markdownToDoc } from '@bendyline/squisq/doc';\nimport type { Doc } from '@bendyline/squisq/schemas';\nimport { type XlsxImportOptions, xlsxToMarkdownDoc } from './import.js';\n\nexport type { XlsxImportOptions } from './import.js';\nexport { xlsxToMarkdownDoc } from './import.js';\n\nexport type { XlsxExportOptions } from './export.js';\nexport { markdownDocToXlsx, docToXlsx } from './export.js';\n\n/**\n * Convert a .xlsx file to a squisq Doc (via the markdown table model).\n */\nexport async function xlsxToDoc(\n data: ArrayBuffer | Blob,\n options?: XlsxImportOptions,\n): Promise<Doc> {\n return markdownToDoc(await xlsxToMarkdownDoc(data, options));\n}\n","/**\n * XLSX import — SpreadsheetML (.xlsx) → MarkdownDocument.\n *\n * Reuses the shared ooxml/ reader (zip + DOMParser). Reads the workbook's\n * sheet list, resolves each sheet part via relationships, pulls shared strings,\n * and turns each worksheet's cell grid into a markdown table (first row treated\n * as the header). By default every sheet is imported, each preceded by an H1 of\n * the sheet name; pass `options.sheet` (index or name) to import just one.\n */\n\nimport type {\n MarkdownBlockNode,\n MarkdownDocument,\n MarkdownTable,\n MarkdownTableCell,\n MarkdownTableRow,\n} from '@bendyline/squisq/markdown';\nimport { getPartXml, getPartRelationships, openPackage } from '../ooxml/reader.js';\nimport type { OoxmlOpenOptions } from '../ooxml/reader.js';\nimport type { OoxmlPackage } from '../ooxml/types.js';\nimport { NS_R, NS_SML } from '../ooxml/namespaces.js';\n\nexport interface XlsxImportOptions extends OoxmlOpenOptions {\n /** Which sheet to import (0-based index or sheet name). Default: all sheets. */\n sheet?: number | string;\n}\n\ninterface SheetRef {\n name: string;\n path: string;\n}\n\nfunction attrNS(el: Element, ns: string, local: string, fallback: string): string | null {\n return el.getAttributeNS(ns, local) ?? el.getAttribute(fallback);\n}\n\n/** Resolve a relationship target (relative to its part's dir) to a zip path. */\nfunction resolveTarget(baseDir: string, target: string): string {\n if (target.startsWith('/')) return target.replace(/^\\//, '');\n const stack = baseDir ? baseDir.split('/') : [];\n for (const seg of target.split('/')) {\n if (seg === '..') stack.pop();\n else if (seg !== '.') stack.push(seg);\n }\n return stack.join('/');\n}\n\nasync function readSheets(pkg: OoxmlPackage): Promise<SheetRef[]> {\n const wb = await getPartXml(pkg, 'xl/workbook.xml');\n if (!wb) return [];\n const rels = await getPartRelationships(pkg, 'xl/workbook.xml');\n const relById = new Map(rels.map((r) => [r.id, r.target]));\n const out: SheetRef[] = [];\n const sheetEls = wb.getElementsByTagNameNS(NS_SML, 'sheet');\n for (let i = 0; i < sheetEls.length; i++) {\n const el = sheetEls[i]!;\n const name = el.getAttribute('name') ?? `Sheet${i + 1}`;\n const rid = attrNS(el, NS_R, 'id', 'r:id');\n const target = rid ? relById.get(rid) : undefined;\n if (target) out.push({ name, path: resolveTarget('xl', target) });\n }\n return out;\n}\n\nasync function readSharedStrings(pkg: OoxmlPackage): Promise<string[]> {\n const doc = await getPartXml(pkg, 'xl/sharedStrings.xml');\n if (!doc) return [];\n const siEls = doc.getElementsByTagNameNS(NS_SML, 'si');\n const out: string[] = [];\n for (let i = 0; i < siEls.length; i++) out.push(siEls[i]!.textContent ?? '');\n return out;\n}\n\n/** Column letters of a cell ref (\"B7\" → 1, \"AA1\" → 26). */\nfunction colIndex(ref: string): number {\n const m = /^([A-Za-z]+)/.exec(ref);\n if (!m) return 0;\n let n = 0;\n for (const ch of m[1]!.toUpperCase()) n = n * 26 + (ch.charCodeAt(0) - 64);\n return n - 1;\n}\n\nfunction cellText(cell: Element, shared: string[]): string {\n const t = cell.getAttribute('t');\n if (t === 'inlineStr') {\n const is = cell.getElementsByTagNameNS(NS_SML, 't');\n return is.length ? (is[0]!.textContent ?? '') : '';\n }\n const vEls = cell.getElementsByTagNameNS(NS_SML, 'v');\n const v = vEls.length ? (vEls[0]!.textContent ?? '') : '';\n if (t === 's') return shared[Number.parseInt(v, 10)] ?? '';\n if (t === 'b') return v === '1' ? 'TRUE' : 'FALSE';\n return v;\n}\n\nasync function sheetToGrid(pkg: OoxmlPackage, path: string, shared: string[]): Promise<string[][]> {\n const doc = await getPartXml(pkg, path);\n if (!doc) return [];\n const rowEls = doc.getElementsByTagNameNS(NS_SML, 'row');\n const grid: string[][] = [];\n for (let r = 0; r < rowEls.length; r++) {\n const cells = rowEls[r]!.getElementsByTagNameNS(NS_SML, 'c');\n const rowArr: string[] = [];\n for (let c = 0; c < cells.length; c++) {\n const cell = cells[c]!;\n const ref = cell.getAttribute('r');\n const idx = ref ? colIndex(ref) : rowArr.length;\n while (rowArr.length < idx) rowArr.push('');\n rowArr[idx] = cellText(cell, shared);\n }\n grid.push(rowArr);\n }\n return grid;\n}\n\nfunction gridToTable(grid: string[][]): MarkdownTable {\n const maxCols = grid.reduce((m, r) => Math.max(m, r.length), 1);\n const rows: MarkdownTableRow[] = grid.map((cells, rowIdx) => {\n const children: MarkdownTableCell[] = [];\n for (let c = 0; c < maxCols; c++) {\n const value = cells[c] ?? '';\n children.push({\n type: 'tableCell',\n ...(rowIdx === 0 ? { isHeader: true } : {}),\n children: value ? [{ type: 'text', value }] : [],\n });\n }\n return { type: 'tableRow', children };\n });\n return { type: 'table', children: rows };\n}\n\nexport async function xlsxToMarkdownDoc(\n data: ArrayBuffer | Blob,\n options: XlsxImportOptions = {},\n): Promise<MarkdownDocument> {\n const pkg = await openPackage(data, options);\n const sheets = await readSheets(pkg);\n const shared = await readSharedStrings(pkg);\n\n let selected = sheets;\n if (options.sheet !== undefined) {\n const picked =\n typeof options.sheet === 'number'\n ? sheets[options.sheet]\n : sheets.find((s) => s.name === options.sheet);\n selected = picked ? [picked] : [];\n }\n\n const children: MarkdownBlockNode[] = [];\n const single = selected.length === 1 && options.sheet !== undefined;\n for (const sheet of selected) {\n const grid = await sheetToGrid(pkg, sheet.path, shared);\n if (!single) {\n children.push({ type: 'heading', depth: 1, children: [{ type: 'text', value: sheet.name }] });\n }\n if (grid.length > 0) children.push(gridToTable(grid));\n }\n return { type: 'document', children };\n}\n","/**\n * XLSX export — MarkdownDocument → SpreadsheetML (.xlsx).\n *\n * Tables-only fidelity (honestly documented): every `table` node in the\n * markdown AST becomes one worksheet; all other content (headings, prose,\n * lists, images, …) is dropped except that the nearest preceding heading is\n * used to name the sheet. This mirrors the import side (`xlsxToMarkdownDoc`),\n * which turns each worksheet grid back into a markdown table.\n *\n * Cells are emitted as inline strings (`t=\"inlineStr\"`) so no sharedStrings\n * part is needed, except values matching a plain-number pattern, which are\n * emitted as numeric cells. The package is assembled with the shared ooxml/\n * writer (auto-generates `[Content_Types].xml` + `_rels`), so only the\n * SpreadsheetML-specific parts (workbook, worksheets, styles) are written here.\n *\n * @example\n * ```ts\n * import { parseMarkdown } from '@bendyline/squisq/markdown';\n * import { markdownDocToXlsx } from '@bendyline/squisq-formats/xlsx';\n *\n * const md = parseMarkdown('# Metrics\\n\\n| A | B |\\n| - | - |\\n| 1 | 2 |');\n * const buffer = await markdownDocToXlsx(md);\n * ```\n */\n\nimport type { Doc } from '@bendyline/squisq/schemas';\nimport { docToMarkdown } from '@bendyline/squisq/doc';\nimport type {\n MarkdownDocument,\n MarkdownBlockNode,\n MarkdownTable,\n MarkdownTableRow,\n} from '@bendyline/squisq/markdown';\n\nimport { createPackage } from '../ooxml/writer.js';\nimport { xmlDeclaration, escapeXml } from '../ooxml/xmlUtils.js';\nimport { extractPlainText } from '../shared/text.js';\nimport {\n NS_SML,\n NS_R,\n REL_OFFICE_DOCUMENT,\n REL_STYLES,\n REL_WORKSHEET,\n CONTENT_TYPE_XLSX_WORKBOOK,\n CONTENT_TYPE_XLSX_WORKSHEET,\n CONTENT_TYPE_XLSX_STYLES,\n} from '../ooxml/namespaces.js';\n\n/**\n * Options for XLSX export.\n */\nexport interface XlsxExportOptions {\n /** Workbook title (written to core properties). */\n title?: string;\n /** Workbook author (written to core properties). */\n author?: string;\n /** Prefix used for auto-named sheets when no heading precedes a table. Default: \"Sheet\". */\n sheetNamePrefix?: string;\n}\n\ninterface SheetData {\n name: string;\n /** Grid of cell text: first row is the header. */\n grid: string[][];\n}\n\n/** A plain integer or decimal (optionally negative) — emitted as a numeric cell. */\nconst NUMERIC_RE = /^-?\\d+(\\.\\d+)?$/;\n\n/**\n * Sanitize a candidate name into a valid, unique Excel sheet name.\n * Strips characters Excel forbids (`[]:*?/\\`), caps at 31 chars, and\n * de-duplicates against already-used names by appending 2, 3, …\n */\nfunction sanitizeSheetName(raw: string, used: Set<string>, fallback: string): string {\n let name = raw.replace(/[[\\]:*?/\\\\]/g, '').trim();\n if (name.length === 0) name = fallback;\n name = name.slice(0, 31);\n\n if (!used.has(name)) {\n used.add(name);\n return name;\n }\n // Dedupe: \"Name\", \"Name2\", \"Name3\", … keeping within the 31-char cap.\n for (let n = 2; ; n++) {\n const suffix = String(n);\n const base = name.slice(0, 31 - suffix.length);\n const candidate = `${base}${suffix}`;\n if (!used.has(candidate)) {\n used.add(candidate);\n return candidate;\n }\n }\n}\n\n/** Convert a table node into a grid of plain-text cells. */\nfunction tableToGrid(table: MarkdownTable): string[][] {\n return table.children.map((row: MarkdownTableRow) =>\n row.children.map((cell) => extractPlainText(cell.children)),\n );\n}\n\n/** Walk the document, pairing each table with the nearest preceding heading. */\nfunction collectSheets(doc: MarkdownDocument, prefix: string): SheetData[] {\n const used = new Set<string>();\n const sheets: SheetData[] = [];\n let pendingHeading: string | null = null;\n\n const visit = (nodes: MarkdownBlockNode[]): void => {\n for (const node of nodes) {\n if (node.type === 'heading') {\n pendingHeading = extractPlainText(node.children);\n } else if (node.type === 'table') {\n const fallback = `${prefix}${sheets.length + 1}`;\n const name = sanitizeSheetName(pendingHeading ?? fallback, used, fallback);\n sheets.push({ name, grid: tableToGrid(node) });\n pendingHeading = null;\n }\n }\n };\n\n visit(doc.children);\n return sheets;\n}\n\n/** Column letters for a zero-based index (0 → \"A\", 26 → \"AA\"). */\nfunction columnLetter(index: number): string {\n let n = index + 1;\n let letters = '';\n while (n > 0) {\n const rem = (n - 1) % 26;\n letters = String.fromCharCode(65 + rem) + letters;\n n = Math.floor((n - 1) / 26);\n }\n return letters;\n}\n\nfunction cellXml(value: string, ref: string): string {\n if (NUMERIC_RE.test(value)) {\n return `<c r=\"${ref}\"><v>${escapeXml(value)}</v></c>`;\n }\n return `<c r=\"${ref}\" t=\"inlineStr\"><is><t xml:space=\"preserve\">${escapeXml(value)}</t></is></c>`;\n}\n\nfunction worksheetXml(grid: string[][]): string {\n const rows: string[] = [];\n for (let r = 0; r < grid.length; r++) {\n const cells = grid[r]!;\n const cellsXml = cells.map((value, c) => cellXml(value, `${columnLetter(c)}${r + 1}`)).join('');\n rows.push(`<row r=\"${r + 1}\">${cellsXml}</row>`);\n }\n return (\n `${xmlDeclaration()}\\n` +\n `<worksheet xmlns=\"${NS_SML}\" xmlns:r=\"${NS_R}\">` +\n `<sheetData>${rows.join('')}</sheetData>` +\n `</worksheet>`\n );\n}\n\nfunction workbookXml(sheets: SheetData[]): string {\n const sheetEls = sheets\n .map(\n (sheet, i) =>\n `<sheet name=\"${escapeXml(sheet.name)}\" sheetId=\"${i + 1}\" r:id=\"rId${i + 1}\"/>`,\n )\n .join('');\n return (\n `${xmlDeclaration()}\\n` +\n `<workbook xmlns=\"${NS_SML}\" xmlns:r=\"${NS_R}\">` +\n `<sheets>${sheetEls}</sheets>` +\n `</workbook>`\n );\n}\n\n/** Minimal but valid styles part (Excel expects the referenced collections to exist). */\nfunction stylesXml(): string {\n return (\n `${xmlDeclaration()}\\n` +\n `<styleSheet xmlns=\"${NS_SML}\">` +\n `<fonts count=\"1\"><font><sz val=\"11\"/><name val=\"Calibri\"/></font></fonts>` +\n `<fills count=\"1\"><fill><patternFill patternType=\"none\"/></fill></fills>` +\n `<borders count=\"1\"><border/></borders>` +\n `<cellStyleXfs count=\"1\"><xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\"/></cellStyleXfs>` +\n `<cellXfs count=\"1\"><xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" xfId=\"0\"/></cellXfs>` +\n `</styleSheet>`\n );\n}\n\n/**\n * Convert a MarkdownDocument to a .xlsx file (tables-only fidelity).\n *\n * Each markdown `table` becomes one worksheet; a document with no tables\n * yields a single empty sheet (a valid, openable file — never throws).\n */\nexport async function markdownDocToXlsx(\n doc: MarkdownDocument,\n options: XlsxExportOptions = {},\n): Promise<ArrayBuffer> {\n const prefix = options.sheetNamePrefix ?? 'Sheet';\n let sheets = collectSheets(doc, prefix);\n\n // Zero tables → one empty sheet so the file is still valid.\n if (sheets.length === 0) {\n sheets = [{ name: `${prefix}1`, grid: [] }];\n }\n\n const pkg = createPackage();\n\n // Worksheets + workbook→worksheet relationships.\n sheets.forEach((sheet, i) => {\n const sheetPath = `xl/worksheets/sheet${i + 1}.xml`;\n pkg.addPart(sheetPath, worksheetXml(sheet.grid), CONTENT_TYPE_XLSX_WORKSHEET);\n pkg.addRelationship('xl/workbook.xml', {\n id: `rId${i + 1}`,\n type: REL_WORKSHEET,\n target: `worksheets/sheet${i + 1}.xml`,\n });\n });\n\n // Styles part (referenced after the sheet relationships).\n pkg.addPart('xl/styles.xml', stylesXml(), CONTENT_TYPE_XLSX_STYLES);\n pkg.addRelationship('xl/workbook.xml', {\n id: `rId${sheets.length + 1}`,\n type: REL_STYLES,\n target: 'styles.xml',\n });\n\n // Workbook + root relationship.\n pkg.addPart('xl/workbook.xml', workbookXml(sheets), CONTENT_TYPE_XLSX_WORKBOOK);\n pkg.addRelationship('', {\n id: 'rId1',\n type: REL_OFFICE_DOCUMENT,\n target: 'xl/workbook.xml',\n });\n\n if (options.title || options.author) {\n pkg.setCoreProperties({\n title: options.title,\n creator: options.author,\n created: new Date().toISOString(),\n modified: new Date().toISOString(),\n });\n }\n\n return pkg.toArrayBuffer();\n}\n\n/**\n * Convert a squisq Doc to a .xlsx file (via the markdown table model).\n */\nexport async function docToXlsx(doc: Doc, options?: XlsxExportOptions): Promise<ArrayBuffer> {\n return markdownDocToXlsx(docToMarkdown(doc), options);\n}\n"],"mappings":"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","names":[]}
@@ -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 {\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 +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 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":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/ooxml/themeReader.ts"],"sourcesContent":["/**\n * OOXML theme reader — parses a `theme1.xml` part (DrawingML `a:theme`)\n * into normalized color and font schemes.\n *\n * Shared by DOCX/PPTX/XLSX theme inference: all three formats carry the same\n * theme part shape, differing only in where the part hangs (document/master/\n * workbook relationships). This module never fails hard — unreadable slots\n * degrade to fallbacks or absence, with a warning per degradation.\n */\n\nimport type { OoxmlPackage } from './types.js';\nimport { getPartRelationships, getPartXml } from './reader.js';\nimport { NS_DRAWINGML, REL_THEME } from './namespaces.js';\nimport { baseDirOf, findRelByType, resolveTarget } from './readUtils.js';\n\n/**\n * The clrScheme slots as normalized `#rrggbb` strings. The four surface/text\n * slots always resolve (falling back to black/white when degraded); accent and\n * hyperlink slots are omitted when unresolvable.\n */\nexport interface OoxmlColorScheme {\n dk1: string;\n lt1: string;\n dk2: string;\n lt2: string;\n accent1?: string;\n accent2?: string;\n accent3?: string;\n accent4?: string;\n accent5?: string;\n accent6?: string;\n hlink?: string;\n folHlink?: string;\n}\n\nexport interface OoxmlFontScheme {\n /** `a:fontScheme > a:majorFont > a:latin@typeface` (headings). */\n majorLatin?: string;\n /** `a:fontScheme > a:minorFont > a:latin@typeface` (body). */\n minorLatin?: string;\n}\n\nexport interface OoxmlTheme {\n /** `a:theme@name` (e.g. \"Office Theme\", \"Ion\"). */\n name?: string;\n /** Absent when the theme carries no parseable `a:clrScheme`. */\n colors?: OoxmlColorScheme;\n /** Absent when the theme carries no `a:fontScheme` latin typefaces. */\n fonts?: OoxmlFontScheme;\n warnings: string[];\n}\n\nconst HEX6_RE = /^[0-9a-fA-F]{6}$/;\n\n/** Well-known sysClr values that resolve without a `lastClr` hint. */\nconst SYS_COLOR_DEFAULTS: Record<string, string> = {\n windowText: '000000',\n window: 'ffffff',\n};\n\n/**\n * Resolve one clrScheme slot element to a `#rrggbb` string, or null.\n * Only the base color matters for theming — trailing transform children\n * (`a:lumMod`, `a:tint`, …) are ignored.\n */\nfunction resolveSchemeColor(slot: Element): string | null {\n for (let i = 0; i < slot.childNodes.length; i++) {\n const child = slot.childNodes[i];\n if (!child || child.nodeType !== 1) continue;\n const el = child as Element;\n if (el.localName === 'srgbClr') {\n const val = el.getAttribute('val');\n return val && HEX6_RE.test(val) ? `#${val.toLowerCase()}` : null;\n }\n if (el.localName === 'sysClr') {\n const lastClr = el.getAttribute('lastClr');\n if (lastClr && HEX6_RE.test(lastClr)) return `#${lastClr.toLowerCase()}`;\n const val = el.getAttribute('val');\n const known = val ? SYS_COLOR_DEFAULTS[val] : undefined;\n return known ? `#${known}` : null;\n }\n // Any other color form (schemeClr self-reference, prstClr, …) is\n // unresolvable without a full DrawingML color pipeline.\n return null;\n }\n return null;\n}\n\nfunction firstNS(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 parseColorScheme(clrScheme: Element, warnings: string[]): OoxmlColorScheme {\n const resolve = (slotName: string): string | null => {\n const slot = firstNS(clrScheme, slotName);\n if (!slot) return null;\n return resolveSchemeColor(slot);\n };\n\n const dk1 = resolve('dk1');\n const lt1 = resolve('lt1');\n if (!dk1) warnings.push('theme: dk1 color could not be resolved; using #000000');\n if (!lt1) warnings.push('theme: lt1 color could not be resolved; using #ffffff');\n\n const dk2 = resolve('dk2');\n const lt2 = resolve('lt2');\n\n const colors: OoxmlColorScheme = {\n dk1: dk1 ?? '#000000',\n lt1: lt1 ?? '#ffffff',\n dk2: dk2 ?? dk1 ?? '#000000',\n lt2: lt2 ?? lt1 ?? '#ffffff',\n };\n\n for (const slot of ['accent1', 'accent2', 'accent3', 'accent4', 'accent5', 'accent6'] as const) {\n const hex = resolve(slot);\n if (hex) colors[slot] = hex;\n else warnings.push(`theme: ${slot} color could not be resolved; dropped`);\n }\n for (const slot of ['hlink', 'folHlink'] as const) {\n const hex = resolve(slot);\n if (hex) colors[slot] = hex;\n }\n return colors;\n}\n\nfunction parseFontScheme(fontScheme: Element, warnings: string[]): OoxmlFontScheme | undefined {\n const readLatin = (fontName: 'majorFont' | 'minorFont'): string | undefined => {\n const font = firstNS(fontScheme, fontName);\n if (!font) return undefined;\n const latin = firstNS(font, 'latin');\n const typeface = latin?.getAttribute('typeface')?.trim();\n if (!typeface) {\n warnings.push(`theme: ${fontName} has no latin typeface`);\n return undefined;\n }\n return typeface;\n };\n\n const majorLatin = readLatin('majorFont');\n const minorLatin = readLatin('minorFont');\n if (!majorLatin && !minorLatin) return undefined;\n return {\n ...(majorLatin ? { majorLatin } : {}),\n ...(minorLatin ? { minorLatin } : {}),\n };\n}\n\n/** Parse an already-loaded theme part Document. */\nexport function parseThemeXml(themeDoc: Document): OoxmlTheme {\n const warnings: string[] = [];\n\n const root = firstNS(themeDoc, 'theme');\n const name = root?.getAttribute('name')?.trim() || undefined;\n\n const clrScheme = firstNS(themeDoc, 'clrScheme');\n let colors: OoxmlColorScheme | undefined;\n if (clrScheme) {\n colors = parseColorScheme(clrScheme, warnings);\n } else {\n warnings.push('theme: no clrScheme found');\n }\n\n const fontScheme = firstNS(themeDoc, 'fontScheme');\n let fonts: OoxmlFontScheme | undefined;\n if (fontScheme) {\n fonts = parseFontScheme(fontScheme, warnings);\n } else {\n warnings.push('theme: no fontScheme found');\n }\n\n return {\n ...(name ? { name } : {}),\n ...(colors ? { colors } : {}),\n ...(fonts ? { fonts } : {}),\n warnings,\n };\n}\n\n/**\n * Resolve the theme part related from `fromPartPath` (via `REL_THEME`) and\n * parse it. Returns null when the part has no theme relationship or the\n * target part is missing — callers decide whether that's an error.\n */\nexport async function readThemePart(\n pkg: OoxmlPackage,\n fromPartPath: string,\n): Promise<OoxmlTheme | null> {\n const rels = await getPartRelationships(pkg, fromPartPath);\n const rel = findRelByType(rels, REL_THEME);\n if (!rel) return null;\n const themePath = resolveTarget(baseDirOf(fromPartPath), rel.target);\n const doc = await getPartXml(pkg, themePath);\n if (!doc) return null;\n return parseThemeXml(doc);\n}\n"],"mappings":"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","names":[]}
@@ -1,28 +0,0 @@
1
- // src/ooxml/readUtils.ts
2
- function attrNS(el, ns, local, qualified) {
3
- return el.getAttributeNS(ns, local) ?? el.getAttribute(qualified);
4
- }
5
- function baseDirOf(path) {
6
- const slash = path.lastIndexOf("/");
7
- return slash === -1 ? "" : path.slice(0, slash);
8
- }
9
- function resolveTarget(baseDir, target) {
10
- if (target.startsWith("/")) return target.replace(/^\//, "");
11
- const stack = baseDir ? baseDir.split("/") : [];
12
- for (const seg of target.split("/")) {
13
- if (seg === "..") stack.pop();
14
- else if (seg !== ".") stack.push(seg);
15
- }
16
- return stack.join("/");
17
- }
18
- function findRelByType(rels, type) {
19
- return rels.find((r) => r.type === type);
20
- }
21
-
22
- export {
23
- attrNS,
24
- baseDirOf,
25
- resolveTarget,
26
- findRelByType
27
- };
28
- //# sourceMappingURL=chunk-YRT7GQ5Y.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/ooxml/readUtils.ts"],"sourcesContent":["/**\n * Shared DOM-read helpers for OOXML importers.\n *\n * Every importer walks parts with `getElementsByTagNameNS` and resolves\n * relationship targets relative to the referencing part; these helpers hold\n * the common pieces so new readers (theme, slide layouts) don't re-implement\n * them per format.\n */\n\nimport type { Relationship } from './types.js';\n\n/**\n * Read a namespaced attribute with a qualified-name fallback for documents\n * whose producer omitted the namespace declaration (e.g. `r:id`).\n */\nexport function attrNS(el: Element, ns: string, local: string, qualified: string): string | null {\n return el.getAttributeNS(ns, local) ?? el.getAttribute(qualified);\n}\n\n/** Directory portion of a part path, e.g. `ppt/slides/slide1.xml` → `ppt/slides`. */\nexport function baseDirOf(path: string): string {\n const slash = path.lastIndexOf('/');\n return slash === -1 ? '' : path.slice(0, slash);\n}\n\n/**\n * Resolve a relationship target against the referencing part's directory.\n * Absolute targets (leading `/`) are package-rooted; relative targets may\n * climb with `..` segments (e.g. `../slideLayouts/slideLayout1.xml`).\n */\nexport function resolveTarget(baseDir: string, target: string): string {\n if (target.startsWith('/')) return target.replace(/^\\//, '');\n const stack = baseDir ? baseDir.split('/') : [];\n for (const seg of target.split('/')) {\n if (seg === '..') stack.pop();\n else if (seg !== '.') stack.push(seg);\n }\n return stack.join('/');\n}\n\n/** First relationship of the given type, if any. */\nexport function findRelByType(rels: Relationship[], type: string): Relationship | undefined {\n return rels.find((r) => r.type === type);\n}\n"],"mappings":";AAeO,SAAS,OAAO,IAAa,IAAY,OAAe,WAAkC;AAC/F,SAAO,GAAG,eAAe,IAAI,KAAK,KAAK,GAAG,aAAa,SAAS;AAClE;AAGO,SAAS,UAAU,MAAsB;AAC9C,QAAM,QAAQ,KAAK,YAAY,GAAG;AAClC,SAAO,UAAU,KAAK,KAAK,KAAK,MAAM,GAAG,KAAK;AAChD;AAOO,SAAS,cAAc,SAAiB,QAAwB;AACrE,MAAI,OAAO,WAAW,GAAG,EAAG,QAAO,OAAO,QAAQ,OAAO,EAAE;AAC3D,QAAM,QAAQ,UAAU,QAAQ,MAAM,GAAG,IAAI,CAAC;AAC9C,aAAW,OAAO,OAAO,MAAM,GAAG,GAAG;AACnC,QAAI,QAAQ,KAAM,OAAM,IAAI;AAAA,aACnB,QAAQ,IAAK,OAAM,KAAK,GAAG;AAAA,EACtC;AACA,SAAO,MAAM,KAAK,GAAG;AACvB;AAGO,SAAS,cAAc,MAAsB,MAAwC;AAC1F,SAAO,KAAK,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AACzC;","names":[]}