@bendyline/squisq-formats 2.8.8 → 2.8.9
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/dist/chunk-4LIFEQKX.js +358 -0
- package/dist/{chunk-UXEANVBI.js → chunk-5HUHSLGA.js} +1 -84
- package/dist/{chunk-6ALSRHD7.js → chunk-6HUQFEP3.js} +61 -4
- package/dist/{chunk-BXWNU4T5.js → chunk-DTJQK7U7.js} +43 -0
- package/dist/{chunk-QU4EVC62.js → chunk-GFHUJ7L4.js} +1 -1
- package/dist/{chunk-TMOXUUTG.js → chunk-NQNIFIDP.js} +6 -4
- package/dist/{chunk-LK4KCVN6.js → chunk-SZ3OIY6G.js} +150 -28
- package/dist/{chunk-KROH7FNT.js → chunk-VKLJUHC2.js} +6 -4
- package/dist/{chunk-GDUZJ75A.js → chunk-WVDAFJFS.js} +59 -21
- package/dist/chunk-YRFBWYAD.js +128 -0
- package/dist/{chunk-SVYTUYZM.js → chunk-ZJERBWTB.js} +6 -4
- package/dist/data/index.d.ts +27 -5
- package/dist/data/index.js +6 -2
- package/dist/diagrams/index.d.ts +19 -8
- package/dist/diagrams/index.js +7 -242
- package/dist/docx/index.d.ts +1 -1
- package/dist/docx/index.js +3 -3
- package/dist/epub/index.d.ts +1 -1
- package/dist/epub/index.js +3 -3
- package/dist/fontAwesome-C6FRDYTY.js +14 -0
- package/dist/html/index.d.ts +85 -1
- package/dist/html/index.js +9 -4
- package/dist/index.d.ts +2 -0
- package/dist/index.js +10 -9
- package/dist/{materialize-G4WC5UG3.js → materialize-ICXNO4S4.js} +4 -1
- package/dist/outside-in/index.d.ts +12 -0
- package/dist/outside-in/index.js +2 -2
- package/dist/pdf/index.d.ts +1 -1
- package/dist/pdf/index.js +3 -3
- package/dist/plainHtmlIcons-KBSIJ5EN.js +62 -0
- package/dist/pptx/index.js +2 -2
- package/dist/readers-3P5A6A2A.js +17 -0
- package/dist/registry/index.js +1 -1
- package/package.json +2 -2
- /package/dist/{chunk-LBXBRFBZ.js → chunk-DDMPZZJF.js} +0 -0
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
findDiagrams,
|
|
3
|
+
rasterizeDiagrams
|
|
4
|
+
} from "./chunk-4LIFEQKX.js";
|
|
1
5
|
import {
|
|
2
6
|
arrayBufferToBase64DataUrl,
|
|
3
7
|
extractFilename,
|
|
@@ -8,8 +12,9 @@ import {
|
|
|
8
12
|
} from "./chunk-VCZUXQUL.js";
|
|
9
13
|
import {
|
|
10
14
|
FootnoteIndex,
|
|
11
|
-
footnoteIds
|
|
12
|
-
|
|
15
|
+
footnoteIds,
|
|
16
|
+
withoutBlockTags
|
|
17
|
+
} from "./chunk-DTJQK7U7.js";
|
|
13
18
|
import {
|
|
14
19
|
imageSizeAttributes
|
|
15
20
|
} from "./chunk-JZR32FON.js";
|
|
@@ -294,7 +299,9 @@ function escapeHtml(str) {
|
|
|
294
299
|
import {
|
|
295
300
|
findBlockVideoEmbed,
|
|
296
301
|
isSvgIslandLang,
|
|
302
|
+
mediaKindForUrl,
|
|
297
303
|
parseSvgIsland,
|
|
304
|
+
parseTimeSeconds,
|
|
298
305
|
sanitizeHtmlNodes,
|
|
299
306
|
svgIslandDataUrl,
|
|
300
307
|
svgSourceFromDataUrl,
|
|
@@ -304,7 +311,11 @@ import {
|
|
|
304
311
|
readFrontmatterThemeId as readFrontmatterThemeId2
|
|
305
312
|
} from "@bendyline/squisq/markdown";
|
|
306
313
|
import { resolveFontFamily, buildGoogleFontsUrl } from "@bendyline/squisq/schemas";
|
|
307
|
-
import {
|
|
314
|
+
import {
|
|
315
|
+
isMediaAnnotationName,
|
|
316
|
+
parseStandaloneAnnotation,
|
|
317
|
+
resolveThemeForDoc
|
|
318
|
+
} from "@bendyline/squisq/doc";
|
|
308
319
|
function markdownDocToPlainHtml(doc, options = {}) {
|
|
309
320
|
const { title, body, fontsLink, iconsLink, themedCss, featureCss } = renderPlainHtml(
|
|
310
321
|
doc,
|
|
@@ -347,7 +358,8 @@ function renderPlainHtml(doc, options) {
|
|
|
347
358
|
iconsCss,
|
|
348
359
|
htmlPolicy = "sanitize",
|
|
349
360
|
externalResources = "deny",
|
|
350
|
-
videoEmbeds
|
|
361
|
+
videoEmbeds,
|
|
362
|
+
icons
|
|
351
363
|
} = options;
|
|
352
364
|
const resolveId = themeId ?? readFrontmatterThemeId2(doc.frontmatter);
|
|
353
365
|
const theme = options.theme ?? (resolveId ? resolveThemeForDoc(doc, resolveId, options.themeRegistry) : void 0);
|
|
@@ -358,13 +370,14 @@ function renderPlainHtml(doc, options) {
|
|
|
358
370
|
htmlPolicy,
|
|
359
371
|
footnotes,
|
|
360
372
|
videoEmbeds,
|
|
373
|
+
icons,
|
|
361
374
|
textColor: theme?.colors.text
|
|
362
375
|
};
|
|
363
|
-
const
|
|
376
|
+
const blocks = withoutBlockTags(doc, { keepMedia: true }).children;
|
|
377
|
+
const body = renderTopLevel(blocks, ctx) + renderFootnotesSection(footnotes, ctx);
|
|
364
378
|
const fontsLink = theme && externalResources === "allow" ? renderFontsLink(theme) : "";
|
|
365
|
-
const usesIcons = docUsesIcons(doc);
|
|
366
379
|
let iconsLink = "";
|
|
367
|
-
if (
|
|
380
|
+
if (ctx.usesFontIcons) {
|
|
368
381
|
iconsLink = iconsCss ? `<style data-fa-inline>
|
|
369
382
|
${escapeStyleText(iconsCss)}
|
|
370
383
|
</style>
|
|
@@ -375,13 +388,17 @@ ${escapeStyleText(iconsCss)}
|
|
|
375
388
|
${VIDEO_EMBED_CSS}` : "";
|
|
376
389
|
const svgCss = docUsesSvgIslands(doc) ? `
|
|
377
390
|
${SVG_ISLAND_CSS}` : "";
|
|
391
|
+
const mediaCss = ctx.usesMediaPlayers ? `
|
|
392
|
+
${MEDIA_PLAYER_CSS}` : "";
|
|
393
|
+
const iconCss = ctx.usesSvgIcons ? `
|
|
394
|
+
${SVG_ICON_CSS}` : "";
|
|
378
395
|
return {
|
|
379
396
|
title,
|
|
380
397
|
body,
|
|
381
398
|
fontsLink,
|
|
382
399
|
iconsLink,
|
|
383
400
|
themedCss,
|
|
384
|
-
featureCss: `${FEATURE_CSS}${videoCss}${svgCss}`
|
|
401
|
+
featureCss: `${FEATURE_CSS}${videoCss}${svgCss}${mediaCss}${iconCss}`
|
|
385
402
|
};
|
|
386
403
|
}
|
|
387
404
|
function escapeStyleText(css) {
|
|
@@ -389,18 +406,7 @@ function escapeStyleText(css) {
|
|
|
389
406
|
}
|
|
390
407
|
var FONT_AWESOME_LINK = `<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.3.1/css/all.min.css" crossorigin="anonymous" referrerpolicy="no-referrer">
|
|
391
408
|
`;
|
|
392
|
-
|
|
393
|
-
function visit(node) {
|
|
394
|
-
if (!node || typeof node !== "object") return false;
|
|
395
|
-
const n = node;
|
|
396
|
-
if (n.type === "inlineIcon") return true;
|
|
397
|
-
if (Array.isArray(n.children)) {
|
|
398
|
-
for (const child of n.children) if (visit(child)) return true;
|
|
399
|
-
}
|
|
400
|
-
return false;
|
|
401
|
-
}
|
|
402
|
-
return visit(doc);
|
|
403
|
-
}
|
|
409
|
+
var SVG_ICON_CSS = ` .squisq-icon { display: inline-block; height: 1em; vertical-align: -0.125em; overflow: visible; }`;
|
|
404
410
|
function docUsesVideoEmbeds(doc, htmlPolicy) {
|
|
405
411
|
const iframeIn = (nodes) => nodes.some(
|
|
406
412
|
(node) => node.type === "htmlElement" && (videoEmbedFromIframe(node) !== null || iframeIn(node.children))
|
|
@@ -441,15 +447,21 @@ function renderTopLevel(children, ctx) {
|
|
|
441
447
|
continue;
|
|
442
448
|
}
|
|
443
449
|
}
|
|
444
|
-
const
|
|
445
|
-
if (
|
|
446
|
-
out.push(videoEmbedToHtml(video.embed, video.title, ctx));
|
|
447
|
-
continue;
|
|
448
|
-
}
|
|
449
|
-
out.push(nodeToHtml(node, ctx));
|
|
450
|
+
const html = topLevelBlockToHtml(node, ctx);
|
|
451
|
+
if (html !== null) out.push(html);
|
|
450
452
|
}
|
|
451
453
|
return out.join("\n");
|
|
452
454
|
}
|
|
455
|
+
function topLevelBlockToHtml(node, ctx) {
|
|
456
|
+
if (node?.type !== "paragraph") return nodeToHtml(node, ctx);
|
|
457
|
+
const video = findBlockVideoEmbed(node);
|
|
458
|
+
if (video) return videoEmbedToHtml(video.embed, video.title, ctx);
|
|
459
|
+
const tag = parseStandaloneAnnotation(node);
|
|
460
|
+
if (tag?.template && isMediaAnnotationName(tag.template)) {
|
|
461
|
+
return mediaAnnotationToHtml(tag.template, tag.params, ctx);
|
|
462
|
+
}
|
|
463
|
+
return nodeToHtml(node, ctx);
|
|
464
|
+
}
|
|
453
465
|
function renderFootnotesSection(footnotes, ctx) {
|
|
454
466
|
if (footnotes.isEmpty) return "";
|
|
455
467
|
const items = footnotes.ordered().map((fn) => {
|
|
@@ -484,7 +496,7 @@ function renderFeatureSection(heading, bodyNodes, side, ctx) {
|
|
|
484
496
|
const headingHtml = `<${headingTag}>${childrenToHtml({ children: heading.children }, ctx)}</${headingTag}>`;
|
|
485
497
|
const featured = takeFirstImage(bodyNodes);
|
|
486
498
|
const media = featured.image ? renderFeatureImage(featured.image, ctx) : '<div class="squisq-feature__media squisq-feature__media--empty"></div>';
|
|
487
|
-
const textHtml = [headingHtml, ...featured.remaining.map((n) =>
|
|
499
|
+
const textHtml = [headingHtml, ...featured.remaining.map((n) => topLevelBlockToHtml(n, ctx))].filter((s) => !!s).join("\n");
|
|
488
500
|
const sideClass = side === "leftFeature" ? "squisq-feature--left" : "squisq-feature--right";
|
|
489
501
|
return `<section class="squisq-feature ${sideClass}">
|
|
490
502
|
${media}
|
|
@@ -807,6 +819,11 @@ function nodeToHtml(node, ctx) {
|
|
|
807
819
|
case "image": {
|
|
808
820
|
const original = node.url ?? "";
|
|
809
821
|
const resolved = ctx?.images?.get(original) ?? original;
|
|
822
|
+
const mediaKind = mediaKindForUrl(original);
|
|
823
|
+
if (mediaKind) {
|
|
824
|
+
const label = node.alt || node.title || void 0;
|
|
825
|
+
return mediaPlayerHtml(mediaKind, resolved, label, ctx) ?? escapeHtml2(node.alt ?? "");
|
|
826
|
+
}
|
|
810
827
|
const safeSrc = sanitizeUrl(resolved, "media") ?? svgDataImageToHtmlSrc(resolved);
|
|
811
828
|
if (!safeSrc) return escapeHtml2(node.alt ?? "");
|
|
812
829
|
return `<img src="${escapeAttr(safeSrc)}" alt="${escapeAttr(node.alt ?? "")}"${imageSizeAttributes(node)} />`;
|
|
@@ -816,9 +833,16 @@ function nodeToHtml(node, ctx) {
|
|
|
816
833
|
case "table":
|
|
817
834
|
return tableToHtml(node, ctx);
|
|
818
835
|
case "inlineIcon": {
|
|
836
|
+
const token = escapeAttr(node.token ?? `${node.family}:${node.name}`);
|
|
837
|
+
const svg = ctx?.icons?.get(`${node.family}:${node.name}`);
|
|
838
|
+
if (svg) {
|
|
839
|
+
ctx.usesSvgIcons = true;
|
|
840
|
+
const width = Number((svg.width / svg.height).toFixed(4));
|
|
841
|
+
return `<svg class="squisq-icon" viewBox="0 0 ${svg.width} ${svg.height}" width="${width}em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" data-icon="${token}"><path d="${escapeAttr(svg.path)}"/></svg>`;
|
|
842
|
+
}
|
|
843
|
+
if (ctx) ctx.usesFontIcons = true;
|
|
819
844
|
const family = escapeAttr(node.family ?? "solid");
|
|
820
845
|
const name = escapeAttr(node.name ?? "");
|
|
821
|
-
const token = escapeAttr(node.token ?? `${node.family}:${node.name}`);
|
|
822
846
|
return `<i class="fa-${family} fa-${name}" data-icon="${token}" aria-hidden="true"></i>`;
|
|
823
847
|
}
|
|
824
848
|
case "htmlBlock":
|
|
@@ -955,6 +979,28 @@ var VIDEO_EMBED_CSS = ` .squisq-video-embed { display: block; max-width: 720px;
|
|
|
955
979
|
.squisq-video-embed-play::after { content: ''; position: absolute; left: 26px; top: 12px; border-style: solid; border-width: 10px 0 10px 16px; border-color: transparent transparent transparent #fff; }
|
|
956
980
|
.squisq-video-embed-provider { position: absolute; left: 12px; bottom: 10px; color: #fff; font-size: 0.8em; font-weight: 600; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8); }
|
|
957
981
|
.squisq-video-embed-caption { margin-top: 0.4em; font-size: 0.875em; opacity: 0.8; }`;
|
|
982
|
+
function mediaPlayerHtml(kind, src, label, ctx) {
|
|
983
|
+
const safeSrc = sanitizeUrl(src, "media");
|
|
984
|
+
if (!safeSrc) return null;
|
|
985
|
+
if (ctx) ctx.usesMediaPlayers = true;
|
|
986
|
+
const aria = label ? ` aria-label="${escapeAttr(label)}"` : "";
|
|
987
|
+
return `<${kind} class="squisq-media" src="${escapeAttr(safeSrc)}" controls preload="metadata"${aria}></${kind}>`;
|
|
988
|
+
}
|
|
989
|
+
function mediaAnnotationToHtml(template, params, ctx) {
|
|
990
|
+
if (!params.src) return null;
|
|
991
|
+
const kind = template === "video" ? "video" : "audio";
|
|
992
|
+
let src = ctx?.images?.get(params.src) ?? params.src;
|
|
993
|
+
const start = parseTimeSeconds(params.clipStart ?? "");
|
|
994
|
+
const end = parseTimeSeconds(params.clipEnd ?? "");
|
|
995
|
+
if ((start !== null || end !== null) && !src.includes("#")) {
|
|
996
|
+
src += `#t=${start ?? ""}${end !== null ? `,${end}` : ""}`;
|
|
997
|
+
}
|
|
998
|
+
const player = mediaPlayerHtml(kind, src, void 0, ctx);
|
|
999
|
+
return player ? `<figure class="squisq-media-clip">${player}</figure>` : null;
|
|
1000
|
+
}
|
|
1001
|
+
var MEDIA_PLAYER_CSS = ` .squisq-media-clip { margin: 1.25em 0; }
|
|
1002
|
+
video.squisq-media { display: block; width: 100%; max-width: 720px; height: auto; border-radius: 6px; }
|
|
1003
|
+
audio.squisq-media { display: block; width: 100%; max-width: 480px; }`;
|
|
958
1004
|
function svgDataImageToHtmlSrc(url) {
|
|
959
1005
|
const source = svgSourceFromDataUrl(url);
|
|
960
1006
|
const result = source === null ? null : parseSvgIsland(source);
|
|
@@ -976,6 +1022,80 @@ function escapeAttr(s) {
|
|
|
976
1022
|
return escapeHtml2(s).replace(/"/g, """);
|
|
977
1023
|
}
|
|
978
1024
|
|
|
1025
|
+
// src/html/plainHtmlPrepare.ts
|
|
1026
|
+
import { isDataFilePath } from "@bendyline/squisq/doc";
|
|
1027
|
+
var PAGE_DIAGRAM_KINDS = [
|
|
1028
|
+
"mermaid",
|
|
1029
|
+
"diagram",
|
|
1030
|
+
"timeline",
|
|
1031
|
+
"container",
|
|
1032
|
+
"chart"
|
|
1033
|
+
];
|
|
1034
|
+
function needsPlainHtmlPreparation(doc, options = {}) {
|
|
1035
|
+
let icons = false;
|
|
1036
|
+
let data = false;
|
|
1037
|
+
const visit = (node) => {
|
|
1038
|
+
if (!node || typeof node !== "object" || icons && data) return;
|
|
1039
|
+
const n = node;
|
|
1040
|
+
if (n.type === "inlineIcon") icons = true;
|
|
1041
|
+
if (n.type === "heading") {
|
|
1042
|
+
const src = n.templateAnnotation?.params?.src;
|
|
1043
|
+
if (src && isDataFilePath(src)) data = true;
|
|
1044
|
+
}
|
|
1045
|
+
if (Array.isArray(n.children)) n.children.forEach(visit);
|
|
1046
|
+
};
|
|
1047
|
+
doc.children.forEach(visit);
|
|
1048
|
+
if (icons || data && options.container) return true;
|
|
1049
|
+
if (!options.renderDiagram) return false;
|
|
1050
|
+
return findDiagrams(doc).some((diagram) => PAGE_DIAGRAM_KINDS.includes(diagram.kind));
|
|
1051
|
+
}
|
|
1052
|
+
async function prepareMarkdownDocForPlainHtml(doc, options = {}) {
|
|
1053
|
+
const { renderDiagram, container, signal, onWarning } = options;
|
|
1054
|
+
let markdownDoc = doc;
|
|
1055
|
+
if (container) {
|
|
1056
|
+
const { materializeDataReferences, DATA_PREVIEW_ROWS } = await import("./materialize-ICXNO4S4.js");
|
|
1057
|
+
markdownDoc = await materializeDataReferences(markdownDoc, container, onWarning, {
|
|
1058
|
+
maxRows: options.maxDataRows ?? DATA_PREVIEW_ROWS,
|
|
1059
|
+
tableCache: options.dataTableCache
|
|
1060
|
+
});
|
|
1061
|
+
}
|
|
1062
|
+
signal?.throwIfAborted();
|
|
1063
|
+
const { plainHtmlIcons } = await import("./plainHtmlIcons-KBSIJ5EN.js");
|
|
1064
|
+
const icons = await plainHtmlIcons(markdownDoc);
|
|
1065
|
+
const images = /* @__PURE__ */ new Map();
|
|
1066
|
+
if (!renderDiagram) return { markdownDoc, images, icons };
|
|
1067
|
+
const pictured = await rasterizeDiagrams(markdownDoc, renderDiagram, {
|
|
1068
|
+
kinds: PAGE_DIAGRAM_KINDS,
|
|
1069
|
+
urlPrefix: "squisq-picture",
|
|
1070
|
+
signal,
|
|
1071
|
+
onWarning
|
|
1072
|
+
});
|
|
1073
|
+
const widths = /* @__PURE__ */ new Map();
|
|
1074
|
+
for (const [url, picture] of pictured.images) {
|
|
1075
|
+
const bytes = picture.data;
|
|
1076
|
+
const buffer = bytes.buffer.slice(
|
|
1077
|
+
bytes.byteOffset,
|
|
1078
|
+
bytes.byteOffset + bytes.byteLength
|
|
1079
|
+
);
|
|
1080
|
+
images.set(url, arrayBufferToBase64DataUrl(buffer, picture.contentType));
|
|
1081
|
+
widths.set(url, Math.round(picture.width));
|
|
1082
|
+
}
|
|
1083
|
+
return { markdownDoc: withPictureWidths(pictured.markdownDoc, widths), images, icons };
|
|
1084
|
+
}
|
|
1085
|
+
function withPictureWidths(doc, widths) {
|
|
1086
|
+
if (widths.size === 0) return doc;
|
|
1087
|
+
const visit = (node) => {
|
|
1088
|
+
if (node.type === "image") {
|
|
1089
|
+
const width = widths.get(node.url);
|
|
1090
|
+
return width === void 0 ? node : { ...node, width };
|
|
1091
|
+
}
|
|
1092
|
+
const children = node.children;
|
|
1093
|
+
if (!Array.isArray(children)) return node;
|
|
1094
|
+
return { ...node, children: children.map(visit) };
|
|
1095
|
+
};
|
|
1096
|
+
return { ...doc, children: doc.children.map(visit) };
|
|
1097
|
+
}
|
|
1098
|
+
|
|
979
1099
|
// src/html/plainHtmlBundle.ts
|
|
980
1100
|
import JSZip from "jszip";
|
|
981
1101
|
import { parseMarkdown, inferDocumentTitle } from "@bendyline/squisq/markdown";
|
|
@@ -2645,6 +2765,8 @@ export {
|
|
|
2645
2765
|
generateExternalHtml,
|
|
2646
2766
|
markdownDocToPlainHtml,
|
|
2647
2767
|
markdownDocToPlainHtmlParts,
|
|
2768
|
+
needsPlainHtmlPreparation,
|
|
2769
|
+
prepareMarkdownDocForPlainHtml,
|
|
2648
2770
|
markdownDocsToPlainHtmlBundle,
|
|
2649
2771
|
collectLinkRefs,
|
|
2650
2772
|
HTML_PAGE_TEMPLATE_CONTENT_START,
|
|
@@ -55,8 +55,9 @@ import {
|
|
|
55
55
|
resolveTarget
|
|
56
56
|
} from "./chunk-S5PCVMKU.js";
|
|
57
57
|
import {
|
|
58
|
-
renumberFootnotes
|
|
59
|
-
|
|
58
|
+
renumberFootnotes,
|
|
59
|
+
withoutBlockTags
|
|
60
|
+
} from "./chunk-DTJQK7U7.js";
|
|
60
61
|
import {
|
|
61
62
|
buildContainer
|
|
62
63
|
} from "./chunk-IIQYS2YH.js";
|
|
@@ -65,7 +66,7 @@ import {
|
|
|
65
66
|
fontAwesomeFaces,
|
|
66
67
|
fontAwesomeGlyph,
|
|
67
68
|
obfuscateDocxFont
|
|
68
|
-
} from "./chunk-
|
|
69
|
+
} from "./chunk-DDMPZZJF.js";
|
|
69
70
|
import {
|
|
70
71
|
authoredImageSize,
|
|
71
72
|
extToMime,
|
|
@@ -214,8 +215,9 @@ function pointsToTwips(points) {
|
|
|
214
215
|
}
|
|
215
216
|
|
|
216
217
|
// src/docx/export.ts
|
|
217
|
-
async function markdownDocToDocx(
|
|
218
|
+
async function markdownDocToDocx(source, options = {}) {
|
|
218
219
|
options.signal?.throwIfAborted();
|
|
220
|
+
const doc = withoutBlockTags(source);
|
|
219
221
|
const resolvedOptions = options.themeId !== void 0 ? options : { ...options, themeId: readFrontmatterThemeId(doc.frontmatter) };
|
|
220
222
|
const ctx = new ExportContext(resolvedOptions, doc);
|
|
221
223
|
const stories = partitionDocumentStories(doc.children);
|
|
@@ -251,7 +251,7 @@ async function collectContainerAssets(container, pattern, signal, flattenBasenam
|
|
|
251
251
|
async function collectContainerImages(container, signal) {
|
|
252
252
|
return collectContainerAssets(container, IMAGE_ASSET_RE, signal);
|
|
253
253
|
}
|
|
254
|
-
function
|
|
254
|
+
function dataReferenceSources(doc) {
|
|
255
255
|
const srcs = /* @__PURE__ */ new Set();
|
|
256
256
|
const visit = (blocks) => {
|
|
257
257
|
for (const block of blocks) {
|
|
@@ -261,10 +261,38 @@ function dataReferenceWarnings(doc, formatLabel) {
|
|
|
261
261
|
}
|
|
262
262
|
};
|
|
263
263
|
visit(doc.blocks);
|
|
264
|
-
return
|
|
265
|
-
|
|
264
|
+
return srcs;
|
|
265
|
+
}
|
|
266
|
+
function dataReferenceWarnings(doc, formatLabel) {
|
|
267
|
+
return [...dataReferenceSources(doc)].map(
|
|
268
|
+
(src) => `${formatLabel} cannot embed the data sidecar "${src}"; the export shows its first rows and the link will not resolve outside the source container.`
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
async function markdownWithDataPreview(input, warnings) {
|
|
272
|
+
const markdownDoc = await markdownOf(input);
|
|
273
|
+
if (dataReferenceSources(input.doc).size === 0) return markdownDoc;
|
|
274
|
+
const { materializeDataReferences, DATA_PREVIEW_ROWS } = await import("./materialize-ICXNO4S4.js");
|
|
275
|
+
return materializeDataReferences(
|
|
276
|
+
markdownDoc,
|
|
277
|
+
input.container,
|
|
278
|
+
(message) => warnings.push(message),
|
|
279
|
+
{ maxRows: DATA_PREVIEW_ROWS }
|
|
266
280
|
);
|
|
267
281
|
}
|
|
282
|
+
async function docWithDataPreview(input, warnings) {
|
|
283
|
+
if (dataReferenceSources(input.doc).size === 0) return input.doc;
|
|
284
|
+
const [{ resolveDataReferences }, { defaultDataReaders }] = await Promise.all([
|
|
285
|
+
import("@bendyline/squisq/doc"),
|
|
286
|
+
import("./readers-3P5A6A2A.js")
|
|
287
|
+
]);
|
|
288
|
+
const { doc, diagnostics } = await resolveDataReferences(input.doc, input.container, {
|
|
289
|
+
readers: defaultDataReaders()
|
|
290
|
+
});
|
|
291
|
+
for (const diagnostic of diagnostics) {
|
|
292
|
+
if (diagnostic.severity !== "info") warnings.push(diagnostic.message);
|
|
293
|
+
}
|
|
294
|
+
return doc;
|
|
295
|
+
}
|
|
268
296
|
async function collectContainerDocxImages(container, signal) {
|
|
269
297
|
const images = await collectContainerImages(container, signal);
|
|
270
298
|
const { extToMime } = await import("./images-PQCYRJJ5.js");
|
|
@@ -351,7 +379,8 @@ function defaultFormats() {
|
|
|
351
379
|
async exportDoc(input, options) {
|
|
352
380
|
const { markdownDocToDocx } = await import("./docx/index.js");
|
|
353
381
|
const raw = optionsFor(options, "docx");
|
|
354
|
-
const
|
|
382
|
+
const warnings = [];
|
|
383
|
+
const markdownDoc = await markdownWithDataPreview(input, warnings);
|
|
355
384
|
const containerImages = await collectContainerDocxImages(input.container, options.signal);
|
|
356
385
|
const images = new Map([...containerImages, ...raw.images ?? /* @__PURE__ */ new Map()]);
|
|
357
386
|
const buf = await markdownDocToDocx(markdownDoc, {
|
|
@@ -361,7 +390,10 @@ function defaultFormats() {
|
|
|
361
390
|
themeRegistry: options.themeRegistry ?? raw.themeRegistry,
|
|
362
391
|
images
|
|
363
392
|
});
|
|
364
|
-
return ok(await toBytes(buf), MIME.docx,
|
|
393
|
+
return ok(await toBytes(buf), MIME.docx, [
|
|
394
|
+
...markdownFidelityWarnings(markdownDoc, "docx"),
|
|
395
|
+
...warnings
|
|
396
|
+
]);
|
|
365
397
|
}
|
|
366
398
|
};
|
|
367
399
|
const pdf = {
|
|
@@ -381,8 +413,8 @@ function defaultFormats() {
|
|
|
381
413
|
async exportDoc(input, options) {
|
|
382
414
|
const { markdownDocToPdf } = await import("./pdf/index.js");
|
|
383
415
|
const raw = optionsFor(options, "pdf");
|
|
384
|
-
const markdownDoc = await markdownOf(input);
|
|
385
416
|
const pdfWarnings = [];
|
|
417
|
+
const markdownDoc = await markdownWithDataPreview(input, pdfWarnings);
|
|
386
418
|
const containerImages = await collectContainerDocxImages(input.container, options.signal);
|
|
387
419
|
const images = new Map([...containerImages, ...raw.images ?? /* @__PURE__ */ new Map()]);
|
|
388
420
|
const buf = await markdownDocToPdf(markdownDoc, {
|
|
@@ -420,7 +452,8 @@ function defaultFormats() {
|
|
|
420
452
|
const containerImages = await collectContainerImages(input.container, options.signal);
|
|
421
453
|
const images = new Map([...containerImages, ...raw.images ?? /* @__PURE__ */ new Map()]);
|
|
422
454
|
const pptxWarnings = [];
|
|
423
|
-
const
|
|
455
|
+
const doc = await docWithDataPreview(input, pptxWarnings);
|
|
456
|
+
const buf = await docToPptx(doc, {
|
|
424
457
|
...raw,
|
|
425
458
|
...options.title !== void 0 ? { title: options.title } : {},
|
|
426
459
|
themeId: resolveThemeId(input, options),
|
|
@@ -456,7 +489,7 @@ function defaultFormats() {
|
|
|
456
489
|
},
|
|
457
490
|
async exportDoc(input, options) {
|
|
458
491
|
const { markdownDocToXlsx } = await import("./xlsx/index.js");
|
|
459
|
-
const { materializeDataReferences } = await import("./materialize-
|
|
492
|
+
const { materializeDataReferences } = await import("./materialize-ICXNO4S4.js");
|
|
460
493
|
const warnings = [];
|
|
461
494
|
const markdownDoc = await materializeDataReferences(
|
|
462
495
|
await markdownOf(input),
|
|
@@ -495,7 +528,7 @@ function defaultFormats() {
|
|
|
495
528
|
},
|
|
496
529
|
async exportDoc(input, options) {
|
|
497
530
|
const { markdownDocToCsv } = await import("./csv/index.js");
|
|
498
|
-
const { materializeDataReferences } = await import("./materialize-
|
|
531
|
+
const { materializeDataReferences } = await import("./materialize-ICXNO4S4.js");
|
|
499
532
|
const warnings = [];
|
|
500
533
|
const markdownDoc = await materializeDataReferences(
|
|
501
534
|
await markdownOf(input),
|
|
@@ -528,9 +561,11 @@ function defaultFormats() {
|
|
|
528
561
|
// so there is nothing to extract into a container this wave.
|
|
529
562
|
async exportDoc(input, options) {
|
|
530
563
|
const raw = optionsFor(options, "html");
|
|
564
|
+
const warnings = [];
|
|
565
|
+
const doc = await docWithDataPreview(input, warnings);
|
|
531
566
|
if (raw.playerScriptPath) {
|
|
532
567
|
const { generateExternalHtml } = await import("./html/index.js");
|
|
533
|
-
const htmlText2 = generateExternalHtml(
|
|
568
|
+
const htmlText2 = generateExternalHtml(doc, {
|
|
534
569
|
...raw,
|
|
535
570
|
playerScriptPath: raw.playerScriptPath,
|
|
536
571
|
title: options.title ?? input.baseName,
|
|
@@ -538,7 +573,7 @@ function defaultFormats() {
|
|
|
538
573
|
themeId: resolveThemeId(input, options),
|
|
539
574
|
themeRegistry: options.themeRegistry ?? raw.themeRegistry
|
|
540
575
|
});
|
|
541
|
-
return ok(new TextEncoder().encode(htmlText2), MIME.html);
|
|
576
|
+
return ok(new TextEncoder().encode(htmlText2), MIME.html, warnings);
|
|
542
577
|
}
|
|
543
578
|
const playerScript = await requirePlayerScript(options, "html");
|
|
544
579
|
const { docToHtml } = await import("./html/index.js");
|
|
@@ -550,7 +585,7 @@ function defaultFormats() {
|
|
|
550
585
|
false
|
|
551
586
|
);
|
|
552
587
|
const images = new Map([...containerImages, ...media, ...raw.images ?? /* @__PURE__ */ new Map()]);
|
|
553
|
-
const htmlText = docToHtml(
|
|
588
|
+
const htmlText = docToHtml(doc, {
|
|
554
589
|
...raw,
|
|
555
590
|
playerScript,
|
|
556
591
|
images,
|
|
@@ -560,11 +595,10 @@ function defaultFormats() {
|
|
|
560
595
|
themeId: resolveThemeId(input, options),
|
|
561
596
|
themeRegistry: options.themeRegistry ?? raw.themeRegistry
|
|
562
597
|
});
|
|
563
|
-
return ok(
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
);
|
|
598
|
+
return ok(new TextEncoder().encode(htmlText), MIME.html, [
|
|
599
|
+
...dataReferenceWarnings(input.doc, "Single-file HTML"),
|
|
600
|
+
...warnings
|
|
601
|
+
]);
|
|
568
602
|
}
|
|
569
603
|
};
|
|
570
604
|
const htmlzip = {
|
|
@@ -596,7 +630,9 @@ function defaultFormats() {
|
|
|
596
630
|
...media,
|
|
597
631
|
...raw.images ?? /* @__PURE__ */ new Map()
|
|
598
632
|
]);
|
|
599
|
-
const
|
|
633
|
+
const warnings = [];
|
|
634
|
+
const doc = await docWithDataPreview(input, warnings);
|
|
635
|
+
const blob = await docToHtmlZip(doc, {
|
|
600
636
|
...raw,
|
|
601
637
|
playerScript,
|
|
602
638
|
images,
|
|
@@ -606,7 +642,7 @@ function defaultFormats() {
|
|
|
606
642
|
themeId: resolveThemeId(input, options),
|
|
607
643
|
themeRegistry: options.themeRegistry ?? raw.themeRegistry
|
|
608
644
|
});
|
|
609
|
-
return ok(await toBytes(blob), MIME.zip);
|
|
645
|
+
return ok(await toBytes(blob), MIME.zip, warnings);
|
|
610
646
|
}
|
|
611
647
|
};
|
|
612
648
|
const epub = {
|
|
@@ -618,7 +654,8 @@ function defaultFormats() {
|
|
|
618
654
|
async exportDoc(input, options) {
|
|
619
655
|
const { markdownDocToEpub } = await import("./epub/index.js");
|
|
620
656
|
const raw = optionsFor(options, "epub");
|
|
621
|
-
const
|
|
657
|
+
const warnings = [];
|
|
658
|
+
const markdownDoc = await markdownWithDataPreview(input, warnings);
|
|
622
659
|
const containerImages = await collectContainerImages(input.container, options.signal);
|
|
623
660
|
const images = new Map([...containerImages, ...raw.images ?? /* @__PURE__ */ new Map()]);
|
|
624
661
|
const buf = await markdownDocToEpub(markdownDoc, {
|
|
@@ -630,7 +667,8 @@ function defaultFormats() {
|
|
|
630
667
|
});
|
|
631
668
|
return ok(await toBytes(buf), MIME.epub, [
|
|
632
669
|
...markdownFidelityWarnings(markdownDoc, "epub"),
|
|
633
|
-
...dataReferenceWarnings(input.doc, "EPUB")
|
|
670
|
+
...dataReferenceWarnings(input.doc, "EPUB"),
|
|
671
|
+
...warnings
|
|
634
672
|
]);
|
|
635
673
|
}
|
|
636
674
|
};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defaultDataReaders
|
|
3
|
+
} from "./chunk-5HUHSLGA.js";
|
|
4
|
+
|
|
5
|
+
// src/data/materialize.ts
|
|
6
|
+
import {
|
|
7
|
+
isDataFilePath
|
|
8
|
+
} from "@bendyline/squisq/doc";
|
|
9
|
+
function tableRow(cells) {
|
|
10
|
+
return {
|
|
11
|
+
type: "tableRow",
|
|
12
|
+
children: cells.map((value) => ({
|
|
13
|
+
type: "tableCell",
|
|
14
|
+
children: value ? [{ type: "text", value }] : []
|
|
15
|
+
}))
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function count(n) {
|
|
19
|
+
return n.toLocaleString("en-US");
|
|
20
|
+
}
|
|
21
|
+
function extensionOf(path) {
|
|
22
|
+
const base = path.split("/").pop() ?? path;
|
|
23
|
+
const dot = base.lastIndexOf(".");
|
|
24
|
+
return dot > 0 ? base.slice(dot + 1).toLowerCase() : "";
|
|
25
|
+
}
|
|
26
|
+
var DATA_PREVIEW_ROWS = 100;
|
|
27
|
+
async function materializeDataReferences(markdownDoc, container, onWarning, options = {}) {
|
|
28
|
+
const readers = defaultDataReaders();
|
|
29
|
+
const children = [];
|
|
30
|
+
let changed = false;
|
|
31
|
+
for (const [index, node] of markdownDoc.children.entries()) {
|
|
32
|
+
children.push(node);
|
|
33
|
+
if (node.type !== "heading") continue;
|
|
34
|
+
const params = node.templateAnnotation?.params;
|
|
35
|
+
const src = params?.src;
|
|
36
|
+
if (!src || !isDataFilePath(src)) continue;
|
|
37
|
+
if (markdownDoc.children[index + 1]?.type === "table") continue;
|
|
38
|
+
const label = params?.sheet && params?.anchor ? `${params.sheet}!${params.anchor}` : src;
|
|
39
|
+
if (!container) {
|
|
40
|
+
onWarning?.(
|
|
41
|
+
`Data reference "${src}" could not be embedded: the export has no source container to read it from.`
|
|
42
|
+
);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const ext = extensionOf(src);
|
|
46
|
+
const reader = readers.find((r) => r.extensions.includes(ext));
|
|
47
|
+
if (!reader) {
|
|
48
|
+
onWarning?.(`Data reference "${src}" could not be embedded: no reader for ".${ext}".`);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const previewRows = Number.parseInt(params?.previewRows ?? "", 10);
|
|
52
|
+
const maxRows = options.maxRows === void 0 ? Number.POSITIVE_INFINITY : previewRows > 0 ? previewRows : options.maxRows;
|
|
53
|
+
const readOptions = {
|
|
54
|
+
maxRows,
|
|
55
|
+
...params?.sheet ? { sheet: params.sheet } : {},
|
|
56
|
+
...params?.anchor ? { anchor: params.anchor } : {},
|
|
57
|
+
...params?.headerRow !== void 0 ? { headerRow: params.headerRow !== "false" } : {},
|
|
58
|
+
// Exports honor the author's curated view: the sort/filter params
|
|
59
|
+
// shape the embedded full table exactly as they shape previews.
|
|
60
|
+
...params?.sort ? { sort: params.sort } : {},
|
|
61
|
+
...params?.filter ? { filter: params.filter } : {}
|
|
62
|
+
};
|
|
63
|
+
const cacheKey = [
|
|
64
|
+
src,
|
|
65
|
+
readOptions.sheet ?? "",
|
|
66
|
+
readOptions.anchor ?? "",
|
|
67
|
+
String(readOptions.headerRow ?? ""),
|
|
68
|
+
readOptions.sort ?? "",
|
|
69
|
+
readOptions.filter ?? "",
|
|
70
|
+
String(maxRows)
|
|
71
|
+
].join("\0");
|
|
72
|
+
let pending = options.tableCache?.get(cacheKey);
|
|
73
|
+
if (!pending) {
|
|
74
|
+
let bytes = null;
|
|
75
|
+
try {
|
|
76
|
+
bytes = await container.readFile(src);
|
|
77
|
+
} catch {
|
|
78
|
+
bytes = null;
|
|
79
|
+
}
|
|
80
|
+
if (!bytes) {
|
|
81
|
+
onWarning?.(`Data reference "${src}" could not be embedded: file not found in container.`);
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
pending = reader.read(bytes, readOptions);
|
|
85
|
+
options.tableCache?.set(cacheKey, pending);
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
const table = await pending;
|
|
89
|
+
const mdTable = {
|
|
90
|
+
type: "table",
|
|
91
|
+
children: [tableRow(table.headers), ...table.rows.map(tableRow)]
|
|
92
|
+
};
|
|
93
|
+
children.push(mdTable);
|
|
94
|
+
if (table.totalRows > table.rows.length) {
|
|
95
|
+
children.push({
|
|
96
|
+
type: "paragraph",
|
|
97
|
+
children: [
|
|
98
|
+
{
|
|
99
|
+
type: "emphasis",
|
|
100
|
+
children: [
|
|
101
|
+
{
|
|
102
|
+
type: "text",
|
|
103
|
+
value: `Showing ${count(table.rows.length)} of ${count(table.totalRows)} rows.`
|
|
104
|
+
}
|
|
105
|
+
]
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
changed = true;
|
|
111
|
+
if (ext === "xlsx") {
|
|
112
|
+
onWarning?.(
|
|
113
|
+
`Region ${label} exported as values; formulas in the sidecar workbook were not carried over.`
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
} catch (err) {
|
|
117
|
+
onWarning?.(
|
|
118
|
+
`Data reference "${src}" could not be embedded: ${err instanceof Error ? err.message : String(err)}`
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return changed ? { ...markdownDoc, children } : markdownDoc;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export {
|
|
126
|
+
DATA_PREVIEW_ROWS,
|
|
127
|
+
materializeDataReferences
|
|
128
|
+
};
|
|
@@ -14,13 +14,14 @@ import {
|
|
|
14
14
|
} from "./chunk-JU2RHXUB.js";
|
|
15
15
|
import {
|
|
16
16
|
FootnoteIndex,
|
|
17
|
-
footnoteIds
|
|
18
|
-
|
|
17
|
+
footnoteIds,
|
|
18
|
+
withoutBlockTags
|
|
19
|
+
} from "./chunk-DTJQK7U7.js";
|
|
19
20
|
import {
|
|
20
21
|
collectInlineIconFamilies,
|
|
21
22
|
fontAwesomeFaces,
|
|
22
23
|
fontAwesomeGlyph
|
|
23
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-DDMPZZJF.js";
|
|
24
25
|
import {
|
|
25
26
|
imageSizeAttributes
|
|
26
27
|
} from "./chunk-JZR32FON.js";
|
|
@@ -30,8 +31,9 @@ import JSZip from "jszip";
|
|
|
30
31
|
import { resolveFontFamily } from "@bendyline/squisq/schemas";
|
|
31
32
|
import { resolveThemeForDoc } from "@bendyline/squisq/doc";
|
|
32
33
|
import { isHtmlLineBreak, readFrontmatterThemeId, sanitizeUrl } from "@bendyline/squisq/markdown";
|
|
33
|
-
async function markdownDocToEpub(
|
|
34
|
+
async function markdownDocToEpub(authoredDoc, options = {}) {
|
|
34
35
|
options.signal?.throwIfAborted();
|
|
36
|
+
const sourceDoc = withoutBlockTags(authoredDoc);
|
|
35
37
|
const themeId = options.themeId ?? readFrontmatterThemeId(sourceDoc.frontmatter);
|
|
36
38
|
const islandColor = themeId ? resolveThemeForDoc(sourceDoc, themeId, options.themeRegistry).colors.text : void 0;
|
|
37
39
|
const { doc, images: islandImages } = svgIslandsAsImages(sourceDoc, { color: islandColor });
|