@bendyline/squisq-formats 1.4.1 → 2.0.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.
- package/README.md +48 -2
- package/dist/{chunk-WWBIKRNP.js → chunk-2CSZJEAL.js} +13 -11
- package/dist/chunk-2CSZJEAL.js.map +1 -0
- package/dist/{chunk-RTS5XBZ7.js → chunk-2EFDWKC6.js} +262 -84
- package/dist/chunk-2EFDWKC6.js.map +1 -0
- package/dist/chunk-2PRVLAU3.js +740 -0
- package/dist/chunk-2PRVLAU3.js.map +1 -0
- package/dist/{chunk-SHLPSADL.js → chunk-4HJ6AK2Q.js} +54 -193
- package/dist/chunk-4HJ6AK2Q.js.map +1 -0
- package/dist/{chunk-5LSSWZPU.js → chunk-4VUWTSGM.js} +72 -25
- package/dist/chunk-4VUWTSGM.js.map +1 -0
- package/dist/{chunk-YESS7VY3.js → chunk-CVNVD7VH.js} +154 -39
- package/dist/chunk-CVNVD7VH.js.map +1 -0
- package/dist/chunk-CX3LH47J.js +99 -0
- package/dist/chunk-CX3LH47J.js.map +1 -0
- package/dist/{chunk-D7IFPWNZ.js → chunk-GVS2XXV6.js} +27 -26
- package/dist/chunk-GVS2XXV6.js.map +1 -0
- package/dist/chunk-H7T5DXUU.js +479 -0
- package/dist/chunk-H7T5DXUU.js.map +1 -0
- package/dist/{chunk-EHLGMSTE.js → chunk-HBSCRS5P.js} +10 -8
- package/dist/chunk-HBSCRS5P.js.map +1 -0
- package/dist/{chunk-46FMDOWZ.js → chunk-LXYLOOST.js} +49 -17
- package/dist/chunk-LXYLOOST.js.map +1 -0
- package/dist/{chunk-MJGRI6XR.js → chunk-MLX2BOJC.js} +12 -7
- package/dist/chunk-MLX2BOJC.js.map +1 -0
- package/dist/chunk-NKAJPJ4G.js +106 -0
- package/dist/chunk-NKAJPJ4G.js.map +1 -0
- package/dist/{chunk-DQAZR57U.js → chunk-O3GVVND4.js} +1 -1
- package/dist/chunk-ODL3SSPT.js +18 -0
- package/dist/chunk-ODL3SSPT.js.map +1 -0
- package/dist/chunk-X4USWOQ2.js +131 -0
- package/dist/chunk-X4USWOQ2.js.map +1 -0
- package/dist/chunk-XTLQXR4U.js +195 -0
- package/dist/chunk-XTLQXR4U.js.map +1 -0
- package/dist/chunk-YRT7GQ5Y.js +28 -0
- package/dist/chunk-YRT7GQ5Y.js.map +1 -0
- package/dist/chunk-ZZ7D4DN6.js +97 -0
- package/dist/chunk-ZZ7D4DN6.js.map +1 -0
- package/dist/container/index.d.ts +6 -2
- package/dist/container/index.js +15 -17
- package/dist/container/index.js.map +1 -1
- package/dist/docx/index.d.ts +6 -2
- package/dist/docx/index.js +5 -3
- package/dist/epub/index.d.ts +3 -1
- package/dist/epub/index.js +3 -3
- package/dist/export-Djev9BLU.d.ts +69 -0
- package/dist/extract-LNOA7DBK.js +15 -0
- package/dist/extract-LNOA7DBK.js.map +1 -0
- package/dist/html/index.d.ts +15 -85
- package/dist/html/index.js +3 -3
- package/dist/images-7FBWPKE3.js +7 -0
- package/dist/images-7FBWPKE3.js.map +1 -0
- package/dist/import-DTkDxHmZ.d.ts +84 -0
- package/dist/import-Yivc3kZM.d.ts +136 -0
- package/dist/index.d.ts +13 -4
- package/dist/index.js +30 -11
- package/dist/infer/index.d.ts +138 -0
- package/dist/infer/index.js +28 -0
- package/dist/infer/index.js.map +1 -0
- package/dist/layouts-7OUUVAGU.js +12 -0
- package/dist/layouts-7OUUVAGU.js.map +1 -0
- package/dist/layouts-CZ0bdsNL.d.ts +150 -0
- package/dist/mapTheme-IR27S6IV.js +11 -0
- package/dist/mapTheme-IR27S6IV.js.map +1 -0
- package/dist/ooxml/index.d.ts +21 -127
- package/dist/ooxml/index.js +31 -9
- package/dist/pdf/index.d.ts +3 -1
- package/dist/pdf/index.js +1 -1
- package/dist/pptx/index.d.ts +8 -108
- package/dist/pptx/index.js +13 -4
- package/dist/reader-Gof6OrJX.d.ts +140 -0
- package/dist/registry/index.d.ts +46 -8
- package/dist/registry/index.js +5 -2
- package/dist/themeReader-DPw4J5Ss.d.ts +56 -0
- package/dist/xlsx/index.d.ts +6 -66
- package/dist/xlsx/index.js +4 -2
- package/dist/zipLimits-bGYMS9cI.d.ts +29 -0
- package/package.json +8 -2
- package/src/__tests__/container.test.ts +41 -0
- package/src/__tests__/convert.test.ts +167 -0
- package/src/__tests__/epub.test.ts +102 -1
- package/src/__tests__/html.test.ts +62 -0
- package/src/__tests__/inferTheme.test.ts +135 -0
- package/src/__tests__/lossyWarnings.test.ts +41 -0
- package/src/__tests__/ooxml.test.ts +59 -2
- package/src/__tests__/ooxmlThemeReader.test.ts +92 -0
- package/src/__tests__/plainHtml.test.ts +15 -1
- package/src/__tests__/plainHtmlBundle.test.ts +18 -0
- package/src/__tests__/pptxImport.test.ts +30 -0
- package/src/__tests__/pptxInferFixtures.ts +314 -0
- package/src/__tests__/pptxLayoutInfer.test.ts +395 -0
- package/src/__tests__/zipSafety.test.ts +317 -0
- package/src/container/index.ts +20 -29
- package/src/docx/export.ts +4 -2
- package/src/docx/import.ts +4 -3
- package/src/epub/export.ts +94 -25
- package/src/html/docsHtmlBundle.ts +6 -2
- package/src/html/htmlTemplate.ts +31 -6
- package/src/html/imageUtils.ts +14 -5
- package/src/html/index.ts +12 -1
- package/src/html/plainHtml.ts +7 -3
- package/src/html/plainHtmlBundle.ts +11 -9
- package/src/index.ts +20 -0
- package/src/infer/extract.ts +127 -0
- package/src/infer/index.ts +168 -0
- package/src/infer/mapTheme.ts +176 -0
- package/src/infer/types.ts +27 -0
- package/src/ooxml/index.ts +14 -0
- package/src/ooxml/readUtils.ts +44 -0
- package/src/ooxml/reader.ts +87 -28
- package/src/ooxml/themeReader.ts +197 -0
- package/src/ooxml/types.ts +8 -9
- package/src/ooxml/writer.ts +28 -10
- package/src/pdf/export.ts +4 -2
- package/src/pdf/import.ts +40 -34
- package/src/pptx/export.ts +4 -2
- package/src/pptx/import.ts +214 -32
- package/src/pptx/index.ts +14 -0
- package/src/pptx/layouts.ts +1168 -0
- package/src/registry/convert.ts +54 -23
- package/src/registry/defaultFormats.ts +131 -44
- package/src/registry/index.ts +3 -0
- package/src/registry/types.ts +52 -6
- package/src/shared/boundedZipArchive.ts +342 -0
- package/src/shared/fidelity.ts +130 -0
- package/src/shared/zipEntryCount.ts +97 -0
- package/src/shared/zipLimits.ts +286 -0
- package/src/shared/zipSafety.ts +19 -0
- package/src/xlsx/import.ts +3 -2
- package/dist/chunk-46FMDOWZ.js.map +0 -1
- package/dist/chunk-5LSSWZPU.js.map +0 -1
- package/dist/chunk-D7IFPWNZ.js.map +0 -1
- package/dist/chunk-EHLGMSTE.js.map +0 -1
- package/dist/chunk-MJGRI6XR.js.map +0 -1
- package/dist/chunk-RTS5XBZ7.js.map +0 -1
- package/dist/chunk-SHLPSADL.js.map +0 -1
- package/dist/chunk-WWBIKRNP.js.map +0 -1
- package/dist/chunk-YESS7VY3.js.map +0 -1
- /package/dist/{chunk-DQAZR57U.js.map → chunk-O3GVVND4.js.map} +0 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ConversionError
|
|
3
|
+
} from "./chunk-ODL3SSPT.js";
|
|
4
|
+
import {
|
|
5
|
+
extractDocxTheme,
|
|
6
|
+
extractPptxTheme,
|
|
7
|
+
extractXlsxTheme
|
|
8
|
+
} from "./chunk-CX3LH47J.js";
|
|
9
|
+
import {
|
|
10
|
+
colorHintsFromExtraction,
|
|
11
|
+
compileExtractedTheme
|
|
12
|
+
} from "./chunk-NKAJPJ4G.js";
|
|
13
|
+
import {
|
|
14
|
+
openPackage
|
|
15
|
+
} from "./chunk-4HJ6AK2Q.js";
|
|
16
|
+
|
|
17
|
+
// src/infer/index.ts
|
|
18
|
+
async function looksLikePdf(data) {
|
|
19
|
+
let head = null;
|
|
20
|
+
const blob = data;
|
|
21
|
+
if (typeof blob.size === "number" && typeof blob.slice === "function" && typeof blob.arrayBuffer === "function") {
|
|
22
|
+
head = new Uint8Array(await blob.slice(0, 5).arrayBuffer());
|
|
23
|
+
} else if (typeof data.byteLength === "number") {
|
|
24
|
+
const buf = data;
|
|
25
|
+
head = new Uint8Array(buf, 0, Math.min(5, buf.byteLength));
|
|
26
|
+
}
|
|
27
|
+
if (!head || head.length < 4) return false;
|
|
28
|
+
return head[0] === 37 && head[1] === 80 && head[2] === 68 && head[3] === 70;
|
|
29
|
+
}
|
|
30
|
+
function sniffOoxmlFormat(pkg) {
|
|
31
|
+
const values = [...pkg.contentTypes.overrides.values(), ...pkg.contentTypes.defaults.values()];
|
|
32
|
+
for (const ct of values) {
|
|
33
|
+
if (ct.includes("wordprocessingml")) return "docx";
|
|
34
|
+
if (ct.includes("presentationml")) return "pptx";
|
|
35
|
+
if (ct.includes("spreadsheetml")) return "xlsx";
|
|
36
|
+
}
|
|
37
|
+
return void 0;
|
|
38
|
+
}
|
|
39
|
+
var EXTRACTORS = {
|
|
40
|
+
docx: extractDocxTheme,
|
|
41
|
+
pptx: extractPptxTheme,
|
|
42
|
+
xlsx: extractXlsxTheme
|
|
43
|
+
};
|
|
44
|
+
async function inferThemeFromFile(data, options = {}) {
|
|
45
|
+
if (await looksLikePdf(data)) {
|
|
46
|
+
throw new ConversionError(
|
|
47
|
+
"unsupported-input",
|
|
48
|
+
"PDF theme inference is not supported \u2014 PDF files carry no theme color/font tables.",
|
|
49
|
+
{ format: "pdf" }
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
let pkg;
|
|
53
|
+
try {
|
|
54
|
+
pkg = await openPackage(data, options);
|
|
55
|
+
} catch (err) {
|
|
56
|
+
throw new ConversionError(
|
|
57
|
+
"invalid-input",
|
|
58
|
+
"Could not read this file as a Word, PowerPoint, or Excel document.",
|
|
59
|
+
{ cause: err }
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
const format = options.format ?? sniffOoxmlFormat(pkg);
|
|
63
|
+
if (!format) {
|
|
64
|
+
throw new ConversionError(
|
|
65
|
+
"invalid-input",
|
|
66
|
+
"Not a Word, PowerPoint, or Excel document \u2014 no theme to infer."
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
const extraction = await EXTRACTORS[format](pkg);
|
|
70
|
+
if (!extraction) {
|
|
71
|
+
throw new ConversionError("invalid-input", "No theme part found in this file.", { format });
|
|
72
|
+
}
|
|
73
|
+
const { theme, warnings: mapWarnings } = compileExtractedTheme(extraction, {
|
|
74
|
+
nameHint: options.nameHint
|
|
75
|
+
});
|
|
76
|
+
const warnings = [...extraction.warnings, ...mapWarnings];
|
|
77
|
+
let layouts;
|
|
78
|
+
if (options.inferLayouts) {
|
|
79
|
+
if (format !== "pptx") {
|
|
80
|
+
warnings.push("Layout inference is only available for PowerPoint files; skipped.");
|
|
81
|
+
} else {
|
|
82
|
+
const { analyzePptxLayouts } = await import("./layouts-7OUUVAGU.js");
|
|
83
|
+
const analysis = await analyzePptxLayouts(pkg, {
|
|
84
|
+
colors: colorHintsFromExtraction(extraction)
|
|
85
|
+
});
|
|
86
|
+
warnings.push(...analysis.warnings);
|
|
87
|
+
const defs = analysis.layouts.map((l) => l.verdict.kind === "custom" ? l.verdict.def : null).filter((d) => d !== null);
|
|
88
|
+
if (defs.length > 0) layouts = defs;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return { theme, extraction, ...layouts ? { layouts } : {}, warnings };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export {
|
|
95
|
+
inferThemeFromFile
|
|
96
|
+
};
|
|
97
|
+
//# sourceMappingURL=chunk-ZZ7D4DN6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/infer/index.ts"],"sourcesContent":["/**\n * @bendyline/squisq-formats Infer Module\n *\n * \"Infer theme and layouts from a file import\": read the OOXML theme\n * (colors + fonts) out of a DOCX/PPTX/XLSX file and compile it into a\n * Squisq `Theme`; for PPTX, optionally derive custom layout templates\n * from the deck's slide layouts/masters.\n *\n * Consumers:\n * - the editor's theme customizer surfaces (upload / drag-drop a file)\n * - the PPTX importer (theme + layouts ride along as frontmatter)\n *\n * PDF is deliberately unsupported: PDF files carry no theme tables, so\n * inference would produce a mostly-default theme. `inferThemeFromFile`\n * rejects PDF bytes with a clear `ConversionError`.\n */\n\nimport type { CustomTemplateDefinition, Theme } from '@bendyline/squisq/schemas';\nimport { openPackage } from '../ooxml/reader.js';\nimport type { OoxmlOpenOptions } from '../ooxml/reader.js';\nimport type { OoxmlPackage } from '../ooxml/types.js';\nimport { ConversionError } from '../registry/errors.js';\nimport type { ExtractedFileTheme, InferSourceFormat } from './types.js';\nimport { extractDocxTheme, extractPptxTheme, extractXlsxTheme } from './extract.js';\nimport { colorHintsFromExtraction, compileExtractedTheme } from './mapTheme.js';\n\nexport type { ExtractedFileTheme, InferSourceFormat, SchemeSlot } from './types.js';\nexport { extractDocxTheme, extractPptxTheme, extractXlsxTheme } from './extract.js';\nexport type { CompileExtractedOptions, MappedThemePartial } from './mapTheme.js';\nexport {\n colorHintsFromExtraction,\n compileExtractedTheme,\n extractedThemeToPartial,\n} from './mapTheme.js';\n\nexport interface InferThemeOptions extends OoxmlOpenOptions {\n /** Skip sniffing when the caller already knows the format (e.g. from the extension). */\n format?: InferSourceFormat;\n /** PPTX only: also derive custom layout templates from slide layouts/masters. */\n inferLayouts?: boolean;\n /** Preferred display name for the compiled theme (e.g. the file's basename). */\n nameHint?: string;\n}\n\nexport interface InferredFileTheme {\n /** Compiled, validated Squisq theme (`custom-<slug>` id, seeds recorded). */\n theme: Theme;\n /** Raw extraction, for callers mapping into their own editing model. */\n extraction: ExtractedFileTheme;\n /** Present only for PPTX with `inferLayouts` and ≥1 non-redundant layout. */\n layouts?: CustomTemplateDefinition[];\n /** Non-fatal notes: sysClr fallbacks, dropped accents, skipped layouts, … */\n warnings: string[];\n}\n\nasync function looksLikePdf(data: ArrayBuffer | Blob): Promise<boolean> {\n // Duck-typed (not instanceof): buffers routinely cross realms in test\n // environments and web workers. Blobs carry `size`; ArrayBuffers carry\n // `byteLength`.\n let head: Uint8Array | null = null;\n const blob = data as Blob;\n if (\n typeof blob.size === 'number' &&\n typeof blob.slice === 'function' &&\n typeof blob.arrayBuffer === 'function'\n ) {\n head = new Uint8Array(await blob.slice(0, 5).arrayBuffer());\n } else if (typeof (data as ArrayBuffer).byteLength === 'number') {\n const buf = data as ArrayBuffer;\n head = new Uint8Array(buf, 0, Math.min(5, buf.byteLength));\n }\n if (!head || head.length < 4) return false;\n // '%PDF'\n return head[0] === 0x25 && head[1] === 0x50 && head[2] === 0x44 && head[3] === 0x46;\n}\n\n/**\n * Classify an opened package from its already-parsed content types.\n * (Deliberately not the registry's byte sniffer — that re-parses the zip\n * and carries `dbk` semantics this path doesn't want.)\n */\nfunction sniffOoxmlFormat(pkg: OoxmlPackage): InferSourceFormat | undefined {\n const values = [...pkg.contentTypes.overrides.values(), ...pkg.contentTypes.defaults.values()];\n for (const ct of values) {\n if (ct.includes('wordprocessingml')) return 'docx';\n if (ct.includes('presentationml')) return 'pptx';\n if (ct.includes('spreadsheetml')) return 'xlsx';\n }\n return undefined;\n}\n\nconst EXTRACTORS: Record<\n InferSourceFormat,\n (pkg: OoxmlPackage) => Promise<ExtractedFileTheme | null>\n> = {\n docx: extractDocxTheme,\n pptx: extractPptxTheme,\n xlsx: extractXlsxTheme,\n};\n\n/**\n * Infer a Squisq theme (and, for PPTX, optionally custom layout templates)\n * from an office file's bytes.\n *\n * Throws `ConversionError`:\n * - `unsupported-input` for PDF bytes (no theme tables to read)\n * - `invalid-input` for non-OOXML data or files with no theme part\n */\nexport async function inferThemeFromFile(\n data: ArrayBuffer | Blob,\n options: InferThemeOptions = {},\n): Promise<InferredFileTheme> {\n if (await looksLikePdf(data)) {\n throw new ConversionError(\n 'unsupported-input',\n 'PDF theme inference is not supported — PDF files carry no theme color/font tables.',\n { format: 'pdf' },\n );\n }\n\n let pkg: OoxmlPackage;\n try {\n pkg = await openPackage(data, options);\n } catch (err: unknown) {\n throw new ConversionError(\n 'invalid-input',\n 'Could not read this file as a Word, PowerPoint, or Excel document.',\n { cause: err },\n );\n }\n\n const format = options.format ?? sniffOoxmlFormat(pkg);\n if (!format) {\n throw new ConversionError(\n 'invalid-input',\n 'Not a Word, PowerPoint, or Excel document — no theme to infer.',\n );\n }\n\n const extraction = await EXTRACTORS[format](pkg);\n if (!extraction) {\n throw new ConversionError('invalid-input', 'No theme part found in this file.', { format });\n }\n\n const { theme, warnings: mapWarnings } = compileExtractedTheme(extraction, {\n nameHint: options.nameHint,\n });\n const warnings = [...extraction.warnings, ...mapWarnings];\n\n let layouts: CustomTemplateDefinition[] | undefined;\n if (options.inferLayouts) {\n if (format !== 'pptx') {\n warnings.push('Layout inference is only available for PowerPoint files; skipped.');\n } else {\n const { analyzePptxLayouts } = await import('../pptx/layouts.js');\n const analysis = await analyzePptxLayouts(pkg, {\n colors: colorHintsFromExtraction(extraction),\n });\n warnings.push(...analysis.warnings);\n const defs = analysis.layouts\n .map((l) => (l.verdict.kind === 'custom' ? l.verdict.def : null))\n .filter((d): d is CustomTemplateDefinition => d !== null);\n if (defs.length > 0) layouts = defs;\n }\n }\n\n return { theme, extraction, ...(layouts ? { layouts } : {}), warnings };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAuDA,eAAe,aAAa,MAA4C;AAItE,MAAI,OAA0B;AAC9B,QAAM,OAAO;AACb,MACE,OAAO,KAAK,SAAS,YACrB,OAAO,KAAK,UAAU,cACtB,OAAO,KAAK,gBAAgB,YAC5B;AACA,WAAO,IAAI,WAAW,MAAM,KAAK,MAAM,GAAG,CAAC,EAAE,YAAY,CAAC;AAAA,EAC5D,WAAW,OAAQ,KAAqB,eAAe,UAAU;AAC/D,UAAM,MAAM;AACZ,WAAO,IAAI,WAAW,KAAK,GAAG,KAAK,IAAI,GAAG,IAAI,UAAU,CAAC;AAAA,EAC3D;AACA,MAAI,CAAC,QAAQ,KAAK,SAAS,EAAG,QAAO;AAErC,SAAO,KAAK,CAAC,MAAM,MAAQ,KAAK,CAAC,MAAM,MAAQ,KAAK,CAAC,MAAM,MAAQ,KAAK,CAAC,MAAM;AACjF;AAOA,SAAS,iBAAiB,KAAkD;AAC1E,QAAM,SAAS,CAAC,GAAG,IAAI,aAAa,UAAU,OAAO,GAAG,GAAG,IAAI,aAAa,SAAS,OAAO,CAAC;AAC7F,aAAW,MAAM,QAAQ;AACvB,QAAI,GAAG,SAAS,kBAAkB,EAAG,QAAO;AAC5C,QAAI,GAAG,SAAS,gBAAgB,EAAG,QAAO;AAC1C,QAAI,GAAG,SAAS,eAAe,EAAG,QAAO;AAAA,EAC3C;AACA,SAAO;AACT;AAEA,IAAM,aAGF;AAAA,EACF,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AACR;AAUA,eAAsB,mBACpB,MACA,UAA6B,CAAC,GACF;AAC5B,MAAI,MAAM,aAAa,IAAI,GAAG;AAC5B,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA,EAAE,QAAQ,MAAM;AAAA,IAClB;AAAA,EACF;AAEA,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,YAAY,MAAM,OAAO;AAAA,EACvC,SAAS,KAAc;AACrB,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA,EAAE,OAAO,IAAI;AAAA,IACf;AAAA,EACF;AAEA,QAAM,SAAS,QAAQ,UAAU,iBAAiB,GAAG;AACrD,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAa,MAAM,WAAW,MAAM,EAAE,GAAG;AAC/C,MAAI,CAAC,YAAY;AACf,UAAM,IAAI,gBAAgB,iBAAiB,qCAAqC,EAAE,OAAO,CAAC;AAAA,EAC5F;AAEA,QAAM,EAAE,OAAO,UAAU,YAAY,IAAI,sBAAsB,YAAY;AAAA,IACzE,UAAU,QAAQ;AAAA,EACpB,CAAC;AACD,QAAM,WAAW,CAAC,GAAG,WAAW,UAAU,GAAG,WAAW;AAExD,MAAI;AACJ,MAAI,QAAQ,cAAc;AACxB,QAAI,WAAW,QAAQ;AACrB,eAAS,KAAK,mEAAmE;AAAA,IACnF,OAAO;AACL,YAAM,EAAE,mBAAmB,IAAI,MAAM,OAAO,uBAAoB;AAChE,YAAM,WAAW,MAAM,mBAAmB,KAAK;AAAA,QAC7C,QAAQ,yBAAyB,UAAU;AAAA,MAC7C,CAAC;AACD,eAAS,KAAK,GAAG,SAAS,QAAQ;AAClC,YAAM,OAAO,SAAS,QACnB,IAAI,CAAC,MAAO,EAAE,QAAQ,SAAS,WAAW,EAAE,QAAQ,MAAM,IAAK,EAC/D,OAAO,CAAC,MAAqC,MAAM,IAAI;AAC1D,UAAI,KAAK,SAAS,EAAG,WAAU;AAAA,IACjC;AAAA,EACF;AAEA,SAAO,EAAE,OAAO,YAAY,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC,GAAI,SAAS;AACxE;","names":[]}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { ContentContainer, MemoryContentContainer } from '@bendyline/squisq/storage';
|
|
2
|
+
import { c as ZipSafetyLimits } from '../zipLimits-bGYMS9cI.js';
|
|
3
|
+
export { Z as ZipSafetyError, a as ZipSafetyErrorCode, b as ZipSafetyErrorOptions } from '../zipLimits-bGYMS9cI.js';
|
|
2
4
|
|
|
3
5
|
/**
|
|
4
6
|
* Container ZIP serialization — convert between ContentContainer and ZIP archives.
|
|
@@ -13,6 +15,8 @@ import { ContentContainer, MemoryContentContainer } from '@bendyline/squisq/stor
|
|
|
13
15
|
* timing.json
|
|
14
16
|
*/
|
|
15
17
|
|
|
18
|
+
type ZipToContainerOptions = ZipSafetyLimits;
|
|
19
|
+
|
|
16
20
|
/**
|
|
17
21
|
* Serialize a ContentContainer to a ZIP blob.
|
|
18
22
|
*
|
|
@@ -33,6 +37,6 @@ declare function containerToZip(container: ContentContainer): Promise<Blob>;
|
|
|
33
37
|
* @param zipData — The ZIP archive as ArrayBuffer, Uint8Array, or Blob
|
|
34
38
|
* @returns A MemoryContentContainer populated with the ZIP's contents
|
|
35
39
|
*/
|
|
36
|
-
declare function zipToContainer(zipData: ArrayBuffer | Uint8Array | Blob): Promise<MemoryContentContainer>;
|
|
40
|
+
declare function zipToContainer(zipData: ArrayBuffer | Uint8Array | Blob, options?: ZipToContainerOptions): Promise<MemoryContentContainer>;
|
|
37
41
|
|
|
38
|
-
export { containerToZip, zipToContainer };
|
|
42
|
+
export { ZipSafetyLimits, type ZipToContainerOptions, containerToZip, zipToContainer };
|
package/dist/container/index.js
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ZipSafetyError,
|
|
3
|
+
assertSafeZipPath,
|
|
4
|
+
openBoundedZipArchive
|
|
5
|
+
} from "../chunk-H7T5DXUU.js";
|
|
6
|
+
|
|
1
7
|
// src/container/index.ts
|
|
2
8
|
import JSZip from "jszip";
|
|
3
9
|
import { MemoryContentContainer } from "@bendyline/squisq/storage";
|
|
@@ -5,6 +11,7 @@ async function containerToZip(container) {
|
|
|
5
11
|
const zip = new JSZip();
|
|
6
12
|
const entries = await container.listFiles();
|
|
7
13
|
for (const entry of entries) {
|
|
14
|
+
assertSafeZipPath(entry.path);
|
|
8
15
|
const data = await container.readFile(entry.path);
|
|
9
16
|
if (data) {
|
|
10
17
|
zip.file(entry.path, new Uint8Array(data));
|
|
@@ -16,27 +23,18 @@ async function containerToZip(container) {
|
|
|
16
23
|
compressionOptions: { level: 6 }
|
|
17
24
|
});
|
|
18
25
|
}
|
|
19
|
-
async function zipToContainer(zipData) {
|
|
20
|
-
const
|
|
26
|
+
async function zipToContainer(zipData, options = {}) {
|
|
27
|
+
const archive = await openBoundedZipArchive(zipData, options);
|
|
21
28
|
const container = new MemoryContentContainer();
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
if (
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (entryPath.startsWith("/") || entryPath.includes("\\") || entryPath.split("/").some((seg) => seg === "..")) {
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
filePromises.push(
|
|
31
|
-
zipEntry.async("arraybuffer").then((data) => {
|
|
32
|
-
return container.writeFile(entryPath, data);
|
|
33
|
-
})
|
|
34
|
-
);
|
|
35
|
-
});
|
|
36
|
-
await Promise.all(filePromises);
|
|
29
|
+
for (const { path } of archive.entries) {
|
|
30
|
+
const data = await archive.read(path);
|
|
31
|
+
if (data) await container.writeFile(path, data);
|
|
32
|
+
archive.release(path);
|
|
33
|
+
}
|
|
37
34
|
return container;
|
|
38
35
|
}
|
|
39
36
|
export {
|
|
37
|
+
ZipSafetyError,
|
|
40
38
|
containerToZip,
|
|
41
39
|
zipToContainer
|
|
42
40
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/container/index.ts"],"sourcesContent":["/**\n * Container ZIP serialization — convert between ContentContainer and ZIP archives.\n *\n * Uses JSZip (already a formats dependency) to serialize a ContentContainer to\n * a ZIP blob and to deserialize a ZIP blob into a MemoryContentContainer.\n *\n * ZIP structure mirrors the container's flat path hierarchy directly:\n * index.md\n * images/hero.jpg\n * audio/narration.mp3\n * timing.json\n */\n\nimport JSZip from 'jszip';\nimport type { ContentContainer } from '@bendyline/squisq/storage';\nimport { MemoryContentContainer } from '@bendyline/squisq/storage';\n\n/**\n * Serialize a ContentContainer to a ZIP blob.\n *\n * All files in the container are written to the ZIP archive preserving\n * their path structure. The resulting blob can be saved as a .zip file.\n *\n * @param container — The container to serialize\n * @returns A Blob containing the ZIP archive\n */\nexport async function containerToZip(container: ContentContainer): Promise<Blob> {\n const zip = new JSZip();\n const entries = await container.listFiles();\n\n for (const entry of entries) {\n const data = await container.readFile(entry.path);\n if (data) {\n zip.file(entry.path, new Uint8Array(data));\n }\n }\n\n return zip.generateAsync({\n type: 'blob',\n compression: 'DEFLATE',\n compressionOptions: { level: 6 },\n });\n}\n\n/**\n * Deserialize a ZIP archive into a MemoryContentContainer.\n *\n * Reads all files from the ZIP and writes them into a new MemoryContentContainer.\n * Directory entries are skipped. The resulting container can be used immediately\n * for rendering, editing, or saving to persistent storage.\n *\n * @param zipData — The ZIP archive as ArrayBuffer, Uint8Array, or Blob\n * @returns A MemoryContentContainer populated with the ZIP's contents\n */\nexport async function zipToContainer(\n zipData: ArrayBuffer | Uint8Array | Blob,\n): Promise<MemoryContentContainer> {\n const
|
|
1
|
+
{"version":3,"sources":["../../src/container/index.ts"],"sourcesContent":["/**\n * Container ZIP serialization — convert between ContentContainer and ZIP archives.\n *\n * Uses JSZip (already a formats dependency) to serialize a ContentContainer to\n * a ZIP blob and to deserialize a ZIP blob into a MemoryContentContainer.\n *\n * ZIP structure mirrors the container's flat path hierarchy directly:\n * index.md\n * images/hero.jpg\n * audio/narration.mp3\n * timing.json\n */\n\nimport JSZip from 'jszip';\nimport type { ContentContainer } from '@bendyline/squisq/storage';\nimport { MemoryContentContainer } from '@bendyline/squisq/storage';\nimport {\n assertSafeZipPath,\n openBoundedZipArchive,\n ZipSafetyError,\n type ZipSafetyLimits,\n type ZipSafetyErrorCode,\n type ZipSafetyErrorOptions,\n} from '../shared/zipSafety.js';\n\nexport type ZipToContainerOptions = ZipSafetyLimits;\nexport { ZipSafetyError };\nexport type { ZipSafetyLimits, ZipSafetyErrorCode, ZipSafetyErrorOptions };\n\n/**\n * Serialize a ContentContainer to a ZIP blob.\n *\n * All files in the container are written to the ZIP archive preserving\n * their path structure. The resulting blob can be saved as a .zip file.\n *\n * @param container — The container to serialize\n * @returns A Blob containing the ZIP archive\n */\nexport async function containerToZip(container: ContentContainer): Promise<Blob> {\n const zip = new JSZip();\n const entries = await container.listFiles();\n\n for (const entry of entries) {\n assertSafeZipPath(entry.path);\n const data = await container.readFile(entry.path);\n if (data) {\n zip.file(entry.path, new Uint8Array(data));\n }\n }\n\n return zip.generateAsync({\n type: 'blob',\n compression: 'DEFLATE',\n compressionOptions: { level: 6 },\n });\n}\n\n/**\n * Deserialize a ZIP archive into a MemoryContentContainer.\n *\n * Reads all files from the ZIP and writes them into a new MemoryContentContainer.\n * Directory entries are skipped. The resulting container can be used immediately\n * for rendering, editing, or saving to persistent storage.\n *\n * @param zipData — The ZIP archive as ArrayBuffer, Uint8Array, or Blob\n * @returns A MemoryContentContainer populated with the ZIP's contents\n */\nexport async function zipToContainer(\n zipData: ArrayBuffer | Uint8Array | Blob,\n options: ZipToContainerOptions = {},\n): Promise<MemoryContentContainer> {\n const archive = await openBoundedZipArchive(zipData, options);\n const container = new MemoryContentContainer();\n for (const { path } of archive.entries) {\n const data = await archive.read(path);\n if (data) await container.writeFile(path, data);\n archive.release(path);\n }\n return container;\n}\n"],"mappings":";;;;;;;AAaA,OAAO,WAAW;AAElB,SAAS,8BAA8B;AAuBvC,eAAsB,eAAe,WAA4C;AAC/E,QAAM,MAAM,IAAI,MAAM;AACtB,QAAM,UAAU,MAAM,UAAU,UAAU;AAE1C,aAAW,SAAS,SAAS;AAC3B,sBAAkB,MAAM,IAAI;AAC5B,UAAM,OAAO,MAAM,UAAU,SAAS,MAAM,IAAI;AAChD,QAAI,MAAM;AACR,UAAI,KAAK,MAAM,MAAM,IAAI,WAAW,IAAI,CAAC;AAAA,IAC3C;AAAA,EACF;AAEA,SAAO,IAAI,cAAc;AAAA,IACvB,MAAM;AAAA,IACN,aAAa;AAAA,IACb,oBAAoB,EAAE,OAAO,EAAE;AAAA,EACjC,CAAC;AACH;AAYA,eAAsB,eACpB,SACA,UAAiC,CAAC,GACD;AACjC,QAAM,UAAU,MAAM,sBAAsB,SAAS,OAAO;AAC5D,QAAM,YAAY,IAAI,uBAAuB;AAC7C,aAAW,EAAE,KAAK,KAAK,QAAQ,SAAS;AACtC,UAAM,OAAO,MAAM,QAAQ,KAAK,IAAI;AACpC,QAAI,KAAM,OAAM,UAAU,UAAU,MAAM,IAAI;AAC9C,YAAQ,QAAQ,IAAI;AAAA,EACtB;AACA,SAAO;AACT;","names":[]}
|
package/dist/docx/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { Doc } from '@bendyline/squisq/schemas';
|
|
1
|
+
import { ThemeRegistry, Doc } from '@bendyline/squisq/schemas';
|
|
2
2
|
import { MarkdownDocument } from '@bendyline/squisq/markdown';
|
|
3
|
+
import { O as OoxmlOpenOptions } from '../reader-Gof6OrJX.js';
|
|
3
4
|
import { ContentContainer } from '@bendyline/squisq/storage';
|
|
5
|
+
import '../zipLimits-bGYMS9cI.js';
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* DOCX Export
|
|
@@ -41,6 +43,8 @@ interface DocxExportOptions {
|
|
|
41
43
|
* the theme's primary color to headings.
|
|
42
44
|
*/
|
|
43
45
|
themeId?: string;
|
|
46
|
+
/** Explicit caller-owned registry for non-document custom themes. */
|
|
47
|
+
themeRegistry?: ThemeRegistry;
|
|
44
48
|
/**
|
|
45
49
|
* Pre-resolved image data keyed by image URL/path as it appears in the
|
|
46
50
|
* markdown source. When provided, images are embedded in the .docx file
|
|
@@ -94,7 +98,7 @@ declare function docToDocx(doc: Doc, options?: DocxExportOptions): Promise<Array
|
|
|
94
98
|
/**
|
|
95
99
|
* Options for DOCX import.
|
|
96
100
|
*/
|
|
97
|
-
interface DocxImportOptions {
|
|
101
|
+
interface DocxImportOptions extends OoxmlOpenOptions {
|
|
98
102
|
/**
|
|
99
103
|
* Whether to extract embedded images as base64 data URIs.
|
|
100
104
|
* When false, images are represented as `[Image]` placeholders.
|
package/dist/docx/index.js
CHANGED
|
@@ -4,13 +4,15 @@ import {
|
|
|
4
4
|
docxToDoc,
|
|
5
5
|
docxToMarkdownDoc,
|
|
6
6
|
markdownDocToDocx
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-2CSZJEAL.js";
|
|
8
8
|
import "../chunk-6M7Z25LA.js";
|
|
9
9
|
import "../chunk-PN52A5AA.js";
|
|
10
|
-
import "../chunk-
|
|
10
|
+
import "../chunk-XTLQXR4U.js";
|
|
11
11
|
import "../chunk-U4MRIFKL.js";
|
|
12
|
+
import "../chunk-4HJ6AK2Q.js";
|
|
13
|
+
import "../chunk-H7T5DXUU.js";
|
|
12
14
|
import "../chunk-SSUPBUF5.js";
|
|
13
|
-
import "../chunk-
|
|
15
|
+
import "../chunk-O3GVVND4.js";
|
|
14
16
|
export {
|
|
15
17
|
docToDocx,
|
|
16
18
|
docxToContainer,
|
package/dist/epub/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AudioSegment, Doc } from '@bendyline/squisq/schemas';
|
|
1
|
+
import { ThemeRegistry, AudioSegment, Doc } from '@bendyline/squisq/schemas';
|
|
2
2
|
import { MarkdownDocument } from '@bendyline/squisq/markdown';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -37,6 +37,8 @@ interface EpubExportOptions {
|
|
|
37
37
|
publisher?: string;
|
|
38
38
|
/** Squisq theme ID for CSS styling */
|
|
39
39
|
themeId?: string;
|
|
40
|
+
/** Explicit caller-owned registry for non-document custom themes. */
|
|
41
|
+
themeRegistry?: ThemeRegistry;
|
|
40
42
|
/** Pre-resolved image data keyed by relative path as it appears in the markdown */
|
|
41
43
|
images?: Map<string, ArrayBuffer>;
|
|
42
44
|
/** Cover image data (JPEG or PNG) */
|
package/dist/epub/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
docToEpub,
|
|
3
3
|
markdownDocToEpub
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-4VUWTSGM.js";
|
|
5
5
|
import "../chunk-PN52A5AA.js";
|
|
6
6
|
import "../chunk-U4MRIFKL.js";
|
|
7
|
-
import "../chunk-
|
|
8
|
-
import "../chunk-
|
|
7
|
+
import "../chunk-MLX2BOJC.js";
|
|
8
|
+
import "../chunk-O3GVVND4.js";
|
|
9
9
|
export {
|
|
10
10
|
docToEpub,
|
|
11
11
|
markdownDocToEpub
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { MarkdownDocument } from '@bendyline/squisq/markdown';
|
|
2
|
+
import { O as OoxmlOpenOptions } from './reader-Gof6OrJX.js';
|
|
3
|
+
import { Doc } from '@bendyline/squisq/schemas';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* XLSX import — SpreadsheetML (.xlsx) → MarkdownDocument.
|
|
7
|
+
*
|
|
8
|
+
* Reuses the shared ooxml/ reader (zip + DOMParser). Reads the workbook's
|
|
9
|
+
* sheet list, resolves each sheet part via relationships, pulls shared strings,
|
|
10
|
+
* and turns each worksheet's cell grid into a markdown table (first row treated
|
|
11
|
+
* as the header). By default every sheet is imported, each preceded by an H1 of
|
|
12
|
+
* the sheet name; pass `options.sheet` (index or name) to import just one.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
interface XlsxImportOptions extends OoxmlOpenOptions {
|
|
16
|
+
/** Which sheet to import (0-based index or sheet name). Default: all sheets. */
|
|
17
|
+
sheet?: number | string;
|
|
18
|
+
}
|
|
19
|
+
declare function xlsxToMarkdownDoc(data: ArrayBuffer | Blob, options?: XlsxImportOptions): Promise<MarkdownDocument>;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* XLSX export — MarkdownDocument → SpreadsheetML (.xlsx).
|
|
23
|
+
*
|
|
24
|
+
* Tables-only fidelity (honestly documented): every `table` node in the
|
|
25
|
+
* markdown AST becomes one worksheet; all other content (headings, prose,
|
|
26
|
+
* lists, images, …) is dropped except that the nearest preceding heading is
|
|
27
|
+
* used to name the sheet. This mirrors the import side (`xlsxToMarkdownDoc`),
|
|
28
|
+
* which turns each worksheet grid back into a markdown table.
|
|
29
|
+
*
|
|
30
|
+
* Cells are emitted as inline strings (`t="inlineStr"`) so no sharedStrings
|
|
31
|
+
* part is needed, except values matching a plain-number pattern, which are
|
|
32
|
+
* emitted as numeric cells. The package is assembled with the shared ooxml/
|
|
33
|
+
* writer (auto-generates `[Content_Types].xml` + `_rels`), so only the
|
|
34
|
+
* SpreadsheetML-specific parts (workbook, worksheets, styles) are written here.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* import { parseMarkdown } from '@bendyline/squisq/markdown';
|
|
39
|
+
* import { markdownDocToXlsx } from '@bendyline/squisq-formats/xlsx';
|
|
40
|
+
*
|
|
41
|
+
* const md = parseMarkdown('# Metrics\n\n| A | B |\n| - | - |\n| 1 | 2 |');
|
|
42
|
+
* const buffer = await markdownDocToXlsx(md);
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Options for XLSX export.
|
|
48
|
+
*/
|
|
49
|
+
interface XlsxExportOptions {
|
|
50
|
+
/** Workbook title (written to core properties). */
|
|
51
|
+
title?: string;
|
|
52
|
+
/** Workbook author (written to core properties). */
|
|
53
|
+
author?: string;
|
|
54
|
+
/** Prefix used for auto-named sheets when no heading precedes a table. Default: "Sheet". */
|
|
55
|
+
sheetNamePrefix?: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Convert a MarkdownDocument to a .xlsx file (tables-only fidelity).
|
|
59
|
+
*
|
|
60
|
+
* Each markdown `table` becomes one worksheet; a document with no tables
|
|
61
|
+
* yields a single empty sheet (a valid, openable file — never throws).
|
|
62
|
+
*/
|
|
63
|
+
declare function markdownDocToXlsx(doc: MarkdownDocument, options?: XlsxExportOptions): Promise<ArrayBuffer>;
|
|
64
|
+
/**
|
|
65
|
+
* Convert a squisq Doc to a .xlsx file (via the markdown table model).
|
|
66
|
+
*/
|
|
67
|
+
declare function docToXlsx(doc: Doc, options?: XlsxExportOptions): Promise<ArrayBuffer>;
|
|
68
|
+
|
|
69
|
+
export { type XlsxExportOptions as X, type XlsxImportOptions as a, docToXlsx as d, markdownDocToXlsx as m, xlsxToMarkdownDoc as x };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
extractDocxTheme,
|
|
3
|
+
extractPptxTheme,
|
|
4
|
+
extractXlsxTheme
|
|
5
|
+
} from "./chunk-CX3LH47J.js";
|
|
6
|
+
import "./chunk-X4USWOQ2.js";
|
|
7
|
+
import "./chunk-YRT7GQ5Y.js";
|
|
8
|
+
import "./chunk-4HJ6AK2Q.js";
|
|
9
|
+
import "./chunk-H7T5DXUU.js";
|
|
10
|
+
export {
|
|
11
|
+
extractDocxTheme,
|
|
12
|
+
extractPptxTheme,
|
|
13
|
+
extractXlsxTheme
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=extract-LNOA7DBK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/html/index.d.ts
CHANGED
|
@@ -1,52 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Theme, ThemeRegistry, Doc } from '@bendyline/squisq/schemas';
|
|
2
|
+
import { H as HtmlExportOptions } from '../import-DTkDxHmZ.js';
|
|
3
|
+
export { a as HtmlImportOptions, c as collectImagePaths, h as htmlToMarkdown, b as htmlToMarkdownDoc, d as htmlToMarkdownDocSync } from '../import-DTkDxHmZ.js';
|
|
2
4
|
import { HtmlPolicy, MarkdownDocument } from '@bendyline/squisq/markdown';
|
|
3
5
|
|
|
4
|
-
/**
|
|
5
|
-
* HTML Template Generation for SquisqPlayer Exports
|
|
6
|
-
*
|
|
7
|
-
* Generates complete, self-contained HTML documents that load the SquisqPlayer
|
|
8
|
-
* IIFE bundle and render a Doc as either an interactive slideshow or a static
|
|
9
|
-
* scrollable document.
|
|
10
|
-
*
|
|
11
|
-
* Two variants:
|
|
12
|
-
* 1. **Inline** — All JS, CSS, and images are embedded in the HTML (single file).
|
|
13
|
-
* 2. **External** — JS is referenced via `<script src>`, images via relative paths.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
interface HtmlExportOptions {
|
|
17
|
-
/** The IIFE player bundle source code (from @bendyline/squisq-react/standalone-source) */
|
|
18
|
-
playerScript: string;
|
|
19
|
-
/**
|
|
20
|
-
* Map of relative image paths (as they appear in the Doc) to binary image data.
|
|
21
|
-
* For inline HTML export, these are converted to base64 data URIs.
|
|
22
|
-
* For ZIP export, these are written as separate files.
|
|
23
|
-
*/
|
|
24
|
-
images?: Map<string, ArrayBuffer>;
|
|
25
|
-
/**
|
|
26
|
-
* Map of audio segment identifiers to binary audio data.
|
|
27
|
-
* Keys should match the audio segment `name` or `url` fields in the Doc.
|
|
28
|
-
* Only used in ZIP exports — single HTML uses timer-based playback.
|
|
29
|
-
*/
|
|
30
|
-
audio?: Map<string, ArrayBuffer>;
|
|
31
|
-
/** Rendering mode: 'slideshow' (interactive, default) or 'static' (scrollable) */
|
|
32
|
-
mode?: 'slideshow' | 'static';
|
|
33
|
-
/** HTML page title (default: 'Squisq Document') */
|
|
34
|
-
title?: string;
|
|
35
|
-
/** Auto-play slideshow on load (default: false) */
|
|
36
|
-
autoPlay?: boolean;
|
|
37
|
-
/**
|
|
38
|
-
* Squisq theme ID to apply (e.g., 'documentary', 'cinematic').
|
|
39
|
-
* When set, the theme is assigned to the Doc before rendering,
|
|
40
|
-
* so the SquisqPlayer renders with that theme's colors and typography.
|
|
41
|
-
*/
|
|
42
|
-
themeId?: string;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Collect all relative image paths referenced in a Doc's layers and template blocks.
|
|
46
|
-
* Returns a Set of unique relative paths that need to be resolved.
|
|
47
|
-
*/
|
|
48
|
-
declare function collectImagePaths(doc: Doc): Set<string>;
|
|
49
|
-
|
|
50
6
|
/**
|
|
51
7
|
* Image Utilities for HTML Export
|
|
52
8
|
*
|
|
@@ -134,6 +90,8 @@ interface PlainHtmlExportOptions {
|
|
|
134
90
|
* When both `theme` and `themeId` are provided, `theme` wins.
|
|
135
91
|
*/
|
|
136
92
|
themeId?: string;
|
|
93
|
+
/** Explicit caller-owned registry for non-document custom themes. */
|
|
94
|
+
themeRegistry?: ThemeRegistry;
|
|
137
95
|
/**
|
|
138
96
|
* Optional FontAwesome CSS text to inline into the rendered page,
|
|
139
97
|
* replacing the default cross-origin `<link>` to cdnjs. Required for
|
|
@@ -191,13 +149,14 @@ interface PlainHtmlBundleOptions {
|
|
|
191
149
|
/** Optional theme applied uniformly to every page. Overrides {@link themeId}. */
|
|
192
150
|
theme?: Theme;
|
|
193
151
|
/**
|
|
194
|
-
* Optional theme id (e.g. `'warm-earth'`, `'gezellig'`)
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
* `themeId` are supplied, `theme` wins.
|
|
152
|
+
* Optional theme id (e.g. `'warm-earth'`, `'gezellig'`) applied to every
|
|
153
|
+
* page. Each document resolves its own inline definition before consulting
|
|
154
|
+
* {@link themeRegistry}. When both `theme` and `themeId` are supplied,
|
|
155
|
+
* `theme` wins.
|
|
199
156
|
*/
|
|
200
157
|
themeId?: string;
|
|
158
|
+
/** Explicit caller-owned registry for non-document custom themes. */
|
|
159
|
+
themeRegistry?: ThemeRegistry;
|
|
201
160
|
/** Maximum recursion depth (default: unlimited; cycles always handled). */
|
|
202
161
|
maxDepth?: number;
|
|
203
162
|
/**
|
|
@@ -242,6 +201,7 @@ declare function collectLinkRefs(doc: MarkdownDocument): Set<string>;
|
|
|
242
201
|
* `<a href>` at runtime — there is no post-render link rewrite hook in
|
|
243
202
|
* the player path.
|
|
244
203
|
*/
|
|
204
|
+
|
|
245
205
|
interface HtmlBundleOptions {
|
|
246
206
|
/** Entry document path relative to the container root (e.g. `'home.md'`). */
|
|
247
207
|
entryPath: string;
|
|
@@ -255,6 +215,8 @@ interface HtmlBundleOptions {
|
|
|
255
215
|
title?: string;
|
|
256
216
|
/** Theme id applied uniformly to every page. */
|
|
257
217
|
themeId?: string;
|
|
218
|
+
/** Explicit caller-owned registry for non-document custom themes. */
|
|
219
|
+
themeRegistry?: ThemeRegistry;
|
|
258
220
|
/** Rendering mode for every page (default: 'static' — scrollable, link-friendly). */
|
|
259
221
|
mode?: 'slideshow' | 'static';
|
|
260
222
|
/** Maximum recursion depth (default: unlimited; cycles always handled). */
|
|
@@ -278,38 +240,6 @@ interface HtmlBundleOptions {
|
|
|
278
240
|
*/
|
|
279
241
|
declare function markdownDocsToHtmlBundle(options: HtmlBundleOptions): Promise<Blob>;
|
|
280
242
|
|
|
281
|
-
/**
|
|
282
|
-
* HTML Import Module — @bendyline/squisq-formats/html
|
|
283
|
-
*
|
|
284
|
-
* Converts an HTML document (or fragment) into a squisq `MarkdownDocument`.
|
|
285
|
-
* Built on the existing `parseHtmlToNodes` (parse5-backed) + `sanitizeHtmlNodes`
|
|
286
|
-
* from `@bendyline/squisq/markdown`, so no new dependency is introduced.
|
|
287
|
-
*
|
|
288
|
-
* The primary consumer is email: HTML mail bodies are hostile input, so the
|
|
289
|
-
* parse is sanitized by default (scripts/styles/event handlers/dangerous URLs
|
|
290
|
-
* stripped) before the tree is walked into markdown nodes.
|
|
291
|
-
*
|
|
292
|
-
* Two entry points mirror the docx/pdf importers:
|
|
293
|
-
* - `htmlToMarkdownDoc(data, options?)` → `MarkdownDocument`
|
|
294
|
-
* - `htmlToMarkdown(html, options?)` → markdown string (convenience for the
|
|
295
|
-
* string-in/string-out path email body conversion needs)
|
|
296
|
-
*/
|
|
297
|
-
|
|
298
|
-
interface HtmlImportOptions {
|
|
299
|
-
/**
|
|
300
|
-
* Strip scripts / styles / event handlers / dangerous URLs before walking
|
|
301
|
-
* the tree. Default `true` — HTML email is untrusted; only disable for
|
|
302
|
-
* trusted input where you want raw fidelity.
|
|
303
|
-
*/
|
|
304
|
-
sanitize?: boolean;
|
|
305
|
-
}
|
|
306
|
-
/** Parse HTML into a squisq `MarkdownDocument`. */
|
|
307
|
-
declare function htmlToMarkdownDocSync(html: string, options?: HtmlImportOptions): MarkdownDocument;
|
|
308
|
-
/** Async, ArrayBuffer-accepting entry mirroring docx/pdf importers. */
|
|
309
|
-
declare function htmlToMarkdownDoc(data: ArrayBuffer | Uint8Array | string, options?: HtmlImportOptions): Promise<MarkdownDocument>;
|
|
310
|
-
/** Convenience string→string conversion (used for email HTML bodies). */
|
|
311
|
-
declare function htmlToMarkdown(html: string, options?: HtmlImportOptions): string;
|
|
312
|
-
|
|
313
243
|
/**
|
|
314
244
|
* HTML Export Module — @bendyline/squisq-formats/html
|
|
315
245
|
*
|
|
@@ -404,4 +334,4 @@ declare function docToHtml(doc: Doc, options: HtmlExportOptions): string;
|
|
|
404
334
|
*/
|
|
405
335
|
declare function docToHtmlZip(doc: Doc, options: HtmlZipExportOptions): Promise<Blob>;
|
|
406
336
|
|
|
407
|
-
export { type HtmlBundleOptions,
|
|
337
|
+
export { type HtmlBundleOptions, HtmlExportOptions, type HtmlZipExportOptions, type PlainHtmlBundleOptions, type PlainHtmlExportOptions, arrayBufferToBase64DataUrl, collectLinkRefs, docToHtml, docToHtmlZip, extractFilename, inferMimeType, markdownDocToPlainHtml, markdownDocsToHtmlBundle, markdownDocsToPlainHtmlBundle };
|
package/dist/html/index.js
CHANGED
|
@@ -9,13 +9,13 @@ import {
|
|
|
9
9
|
markdownDocToPlainHtml,
|
|
10
10
|
markdownDocsToHtmlBundle,
|
|
11
11
|
markdownDocsToPlainHtmlBundle
|
|
12
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-LXYLOOST.js";
|
|
13
13
|
import {
|
|
14
14
|
arrayBufferToBase64DataUrl,
|
|
15
15
|
extractFilename,
|
|
16
16
|
inferMimeType
|
|
17
|
-
} from "../chunk-
|
|
18
|
-
import "../chunk-
|
|
17
|
+
} from "../chunk-MLX2BOJC.js";
|
|
18
|
+
import "../chunk-O3GVVND4.js";
|
|
19
19
|
export {
|
|
20
20
|
arrayBufferToBase64DataUrl,
|
|
21
21
|
collectImagePaths,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { ThemeRegistry, Doc } from '@bendyline/squisq/schemas';
|
|
2
|
+
import { MarkdownDocument } from '@bendyline/squisq/markdown';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* HTML Template Generation for SquisqPlayer Exports
|
|
6
|
+
*
|
|
7
|
+
* Generates complete, self-contained HTML documents that load the SquisqPlayer
|
|
8
|
+
* IIFE bundle and render a Doc as either an interactive slideshow or a static
|
|
9
|
+
* scrollable document.
|
|
10
|
+
*
|
|
11
|
+
* Two variants:
|
|
12
|
+
* 1. **Inline** — All JS, CSS, and images are embedded in the HTML (single file).
|
|
13
|
+
* 2. **External** — JS is referenced via `<script src>`, images via relative paths.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
interface HtmlExportOptions {
|
|
17
|
+
/** The IIFE player bundle source code (from @bendyline/squisq-react/standalone-source) */
|
|
18
|
+
playerScript: string;
|
|
19
|
+
/**
|
|
20
|
+
* Map of relative image paths (as they appear in the Doc) to binary image data.
|
|
21
|
+
* For inline HTML export, these are converted to base64 data URIs.
|
|
22
|
+
* For ZIP export, these are written as separate files.
|
|
23
|
+
*/
|
|
24
|
+
images?: Map<string, ArrayBuffer>;
|
|
25
|
+
/**
|
|
26
|
+
* Map of audio segment identifiers to binary audio data.
|
|
27
|
+
* Keys should match the audio segment `name` or `url` fields in the Doc.
|
|
28
|
+
* Only used in ZIP exports — single HTML uses timer-based playback.
|
|
29
|
+
*/
|
|
30
|
+
audio?: Map<string, ArrayBuffer>;
|
|
31
|
+
/** Rendering mode: 'slideshow' (interactive, default) or 'static' (scrollable) */
|
|
32
|
+
mode?: 'slideshow' | 'static';
|
|
33
|
+
/** HTML page title (default: 'Squisq Document') */
|
|
34
|
+
title?: string;
|
|
35
|
+
/** Auto-play slideshow on load (default: false) */
|
|
36
|
+
autoPlay?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Squisq theme ID to apply (e.g., 'documentary', 'cinematic').
|
|
39
|
+
* When set, the theme is assigned to the Doc before rendering,
|
|
40
|
+
* so the SquisqPlayer renders with that theme's colors and typography.
|
|
41
|
+
*/
|
|
42
|
+
themeId?: string;
|
|
43
|
+
/** Explicit caller-owned registry for non-document custom themes. */
|
|
44
|
+
themeRegistry?: ThemeRegistry;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Collect all relative image paths referenced in a Doc's layers and template blocks.
|
|
48
|
+
* Returns a Set of unique relative paths that need to be resolved.
|
|
49
|
+
*/
|
|
50
|
+
declare function collectImagePaths(doc: Doc): Set<string>;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* HTML Import Module — @bendyline/squisq-formats/html
|
|
54
|
+
*
|
|
55
|
+
* Converts an HTML document (or fragment) into a squisq `MarkdownDocument`.
|
|
56
|
+
* Built on the existing `parseHtmlToNodes` (parse5-backed) + `sanitizeHtmlNodes`
|
|
57
|
+
* from `@bendyline/squisq/markdown`, so no new dependency is introduced.
|
|
58
|
+
*
|
|
59
|
+
* The primary consumer is email: HTML mail bodies are hostile input, so the
|
|
60
|
+
* parse is sanitized by default (scripts/styles/event handlers/dangerous URLs
|
|
61
|
+
* stripped) before the tree is walked into markdown nodes.
|
|
62
|
+
*
|
|
63
|
+
* Two entry points mirror the docx/pdf importers:
|
|
64
|
+
* - `htmlToMarkdownDoc(data, options?)` → `MarkdownDocument`
|
|
65
|
+
* - `htmlToMarkdown(html, options?)` → markdown string (convenience for the
|
|
66
|
+
* string-in/string-out path email body conversion needs)
|
|
67
|
+
*/
|
|
68
|
+
|
|
69
|
+
interface HtmlImportOptions {
|
|
70
|
+
/**
|
|
71
|
+
* Strip scripts / styles / event handlers / dangerous URLs before walking
|
|
72
|
+
* the tree. Default `true` — HTML email is untrusted; only disable for
|
|
73
|
+
* trusted input where you want raw fidelity.
|
|
74
|
+
*/
|
|
75
|
+
sanitize?: boolean;
|
|
76
|
+
}
|
|
77
|
+
/** Parse HTML into a squisq `MarkdownDocument`. */
|
|
78
|
+
declare function htmlToMarkdownDocSync(html: string, options?: HtmlImportOptions): MarkdownDocument;
|
|
79
|
+
/** Async, ArrayBuffer-accepting entry mirroring docx/pdf importers. */
|
|
80
|
+
declare function htmlToMarkdownDoc(data: ArrayBuffer | Uint8Array | string, options?: HtmlImportOptions): Promise<MarkdownDocument>;
|
|
81
|
+
/** Convenience string→string conversion (used for email HTML bodies). */
|
|
82
|
+
declare function htmlToMarkdown(html: string, options?: HtmlImportOptions): string;
|
|
83
|
+
|
|
84
|
+
export { type HtmlExportOptions as H, type HtmlImportOptions as a, htmlToMarkdownDoc as b, collectImagePaths as c, htmlToMarkdownDocSync as d, htmlToMarkdown as h };
|