@bendyline/squisq-formats 2.8.7 → 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.
Files changed (39) hide show
  1. package/README.md +21 -0
  2. package/dist/chunk-4LIFEQKX.js +358 -0
  3. package/dist/{chunk-UXEANVBI.js → chunk-5HUHSLGA.js} +1 -84
  4. package/dist/{chunk-IYNDHW2C.js → chunk-6HUQFEP3.js} +75 -5
  5. package/dist/{chunk-BXWNU4T5.js → chunk-DTJQK7U7.js} +43 -0
  6. package/dist/{chunk-QU4EVC62.js → chunk-GFHUJ7L4.js} +1 -1
  7. package/dist/{chunk-TMOXUUTG.js → chunk-NQNIFIDP.js} +6 -4
  8. package/dist/{chunk-B6UQPW75.js → chunk-SZ3OIY6G.js} +697 -44
  9. package/dist/{chunk-KROH7FNT.js → chunk-VKLJUHC2.js} +6 -4
  10. package/dist/{chunk-C23JYVPG.js → chunk-WJTC5OD6.js} +2 -0
  11. package/dist/{chunk-ALDCFHZT.js → chunk-WVDAFJFS.js} +59 -21
  12. package/dist/chunk-YRFBWYAD.js +128 -0
  13. package/dist/{chunk-SVYTUYZM.js → chunk-ZJERBWTB.js} +6 -4
  14. package/dist/data/index.d.ts +27 -5
  15. package/dist/data/index.js +6 -2
  16. package/dist/diagrams/index.d.ts +19 -8
  17. package/dist/diagrams/index.js +7 -242
  18. package/dist/docx/index.d.ts +1 -1
  19. package/dist/docx/index.js +3 -3
  20. package/dist/epub/index.d.ts +1 -1
  21. package/dist/epub/index.js +3 -3
  22. package/dist/fontAwesome-C6FRDYTY.js +14 -0
  23. package/dist/html/index.d.ts +214 -2
  24. package/dist/html/index.js +25 -4
  25. package/dist/index.d.ts +4 -2
  26. package/dist/index.js +15 -10
  27. package/dist/{materialize-G4WC5UG3.js → materialize-ICXNO4S4.js} +4 -1
  28. package/dist/outside-in/index.d.ts +21 -2
  29. package/dist/outside-in/index.js +7 -3
  30. package/dist/outside-in/layout.d.ts +7 -1
  31. package/dist/outside-in/layout.js +3 -1
  32. package/dist/pdf/index.d.ts +1 -1
  33. package/dist/pdf/index.js +3 -3
  34. package/dist/plainHtmlIcons-KBSIJ5EN.js +62 -0
  35. package/dist/pptx/index.js +2 -2
  36. package/dist/readers-3P5A6A2A.js +17 -0
  37. package/dist/registry/index.js +1 -1
  38. package/package.json +2 -2
  39. /package/dist/{chunk-LBXBRFBZ.js → chunk-DDMPZZJF.js} +0 -0
package/README.md CHANGED
@@ -141,6 +141,27 @@ const page = markdownDocToPlainHtml(markdownDoc, { themeId: 'warm-earth' });
141
141
  const imported = await htmlToMarkdownDoc(htmlString);
142
142
  ```
143
143
 
144
+ To place a document inside your own page — a site header, navigation, footer, and stylesheet — write the page as an HTML template with standard `<slot>` elements and fill it:
145
+
146
+ ```ts
147
+ import { applyHtmlPageTemplate, markdownDocToPlainHtmlParts } from '@bendyline/squisq-formats/html';
148
+
149
+ // template: <title><slot name="title">Post</slot> · My Blog</title> … <h1><slot name="title"></slot></h1> <slot></slot>
150
+ const parts = markdownDocToPlainHtmlParts(markdownDoc);
151
+ const page = applyHtmlPageTemplate(
152
+ template,
153
+ {
154
+ bodyHtml: parts.bodyHtml,
155
+ headHtml: parts.featureHeadHtml,
156
+ title: 'Hello',
157
+ values: { date: '2026-10-28' },
158
+ },
159
+ { templatePath: '_templates/post.html', outputPath: 'posts/hello.html' },
160
+ );
161
+ ```
162
+
163
+ The unnamed `<slot>` receives the body (between `<!-- squisq:content -->` markers, which `htmlToMarkdownDoc` honors on re-import), named slots receive text values or keep their fallback children, relative URLs are rebased from the template's folder to the page's, and everything else in the template is copied byte for byte.
164
+
144
165
  The subpath also exports `markdownDocsToPlainHtmlBundle` / `markdownDocsToHtmlBundle` (recursive multi-doc ZIP bundles with `.md` links rewritten to `.html`), `htmlToMarkdownDocSync` / `htmlToMarkdown`, and helpers (`collectImagePaths`, `collectLinkRefs`, `inferMimeType`).
145
166
 
146
167
  ### EPUB
@@ -0,0 +1,358 @@
1
+ // src/diagrams/index.ts
2
+ import {
3
+ extractPlainText,
4
+ isSvgIslandLang,
5
+ parseSvgIsland,
6
+ stringifyMarkdown
7
+ } from "@bendyline/squisq/markdown";
8
+ import {
9
+ TABLE_FED_TEMPLATES,
10
+ buildChartData,
11
+ detectAsciiDiagram,
12
+ detectAsciiTimeline,
13
+ detectTree,
14
+ isContainerTemplate,
15
+ isEligibleAsciiFenceLang,
16
+ isEligibleAsciiTimelineFenceLang,
17
+ isEligibleTreeFenceLang,
18
+ isExplicitDiagramLang,
19
+ isExplicitTimelineLang,
20
+ isExplicitTreeLang,
21
+ resolveTemplateName
22
+ } from "@bendyline/squisq/doc";
23
+ var DEFAULT_KINDS = [
24
+ "mermaid",
25
+ "diagram",
26
+ "timeline",
27
+ "tree",
28
+ "container",
29
+ "chart"
30
+ ];
31
+ var EXPORT_DIAGRAM_KINDS = [...DEFAULT_KINDS, "svg"];
32
+ var KIND_NAMES = {
33
+ mermaid: "Diagram",
34
+ diagram: "Diagram",
35
+ timeline: "Timeline",
36
+ tree: "Tree",
37
+ container: "Diagram",
38
+ svg: "Illustration",
39
+ chart: "Chart"
40
+ };
41
+ function fenceDiagramKind(node) {
42
+ const lang = node.lang ?? null;
43
+ if ((lang ?? "").trim().toLowerCase() === "mermaid") return "mermaid";
44
+ if (isSvgIslandLang(lang)) return parseSvgIsland(node.value).ok ? "svg" : null;
45
+ if (isEligibleAsciiFenceLang(lang)) {
46
+ const detection = detectAsciiDiagram(node.value, { explicit: isExplicitDiagramLang(lang) });
47
+ if (detection.isDiagram) return "diagram";
48
+ }
49
+ if (isEligibleTreeFenceLang(lang)) {
50
+ if (detectTree(node.value, { explicit: isExplicitTreeLang(lang) }).isTree) return "tree";
51
+ }
52
+ if (isEligibleAsciiTimelineFenceLang(lang)) {
53
+ const detection = detectAsciiTimeline(node.value, { explicit: isExplicitTimelineLang(lang) });
54
+ if (detection.isTimeline) return "timeline";
55
+ }
56
+ return null;
57
+ }
58
+ function containerTemplateOf(node) {
59
+ if (node.type !== "heading") return null;
60
+ const requested = node.templateAnnotation?.template;
61
+ if (!requested || !isContainerTemplate(requested)) return null;
62
+ return resolveTemplateName(requested);
63
+ }
64
+ function mermaidAlt(source) {
65
+ const title = /^\s*accTitle\s*:\s*(.+?)\s*$/mu.exec(source)?.[1] ?? "";
66
+ const description = /^\s*accDescr\s*:\s*(.+?)\s*$/mu.exec(source)?.[1] ?? "";
67
+ return [title, description].filter(Boolean).join(". ");
68
+ }
69
+ function fenceAlt(kind, source) {
70
+ if (kind === "mermaid") return mermaidAlt(source);
71
+ if (kind === "svg") {
72
+ const result = parseSvgIsland(source);
73
+ return result.ok && result.island.title || "";
74
+ }
75
+ return "";
76
+ }
77
+ function fenceMarkdown(node) {
78
+ return stringifyMarkdown({ type: "document", children: [node] }).trim();
79
+ }
80
+ function tableText(table) {
81
+ const [header, ...body] = table.children.map(
82
+ (row) => row.children.map((cell) => extractPlainText(cell).trim())
83
+ );
84
+ return { headers: header ?? [], rows: body };
85
+ }
86
+ function listParam(value) {
87
+ const entries = value?.split(",").map((entry) => entry.trim()).filter(Boolean);
88
+ return entries && entries.length > 0 ? entries : void 0;
89
+ }
90
+ var NON_CHART_PARAMS = /* @__PURE__ */ new Set([
91
+ "showTable",
92
+ "src",
93
+ "sheet",
94
+ "anchor",
95
+ "headerRow",
96
+ "titleAnchor",
97
+ "previewRows",
98
+ "sort",
99
+ "filter"
100
+ ]);
101
+ function isTruthyParam(value) {
102
+ return value !== void 0 && value !== "false" && value !== "0";
103
+ }
104
+ function findChart(children, index) {
105
+ const heading = children[index];
106
+ const requested = heading.templateAnnotation?.template;
107
+ const template = requested ? resolveTemplateName(requested) : "";
108
+ if (!TABLE_FED_TEMPLATES.has(template) || template === "dataTable") return null;
109
+ let tableIndex = -1;
110
+ for (let at = index + 1; at < children.length; at++) {
111
+ const node = children[at];
112
+ if (node.type === "heading") break;
113
+ if (node.type === "table") {
114
+ tableIndex = at;
115
+ break;
116
+ }
117
+ }
118
+ if (tableIndex < 0) return null;
119
+ const table = children[tableIndex];
120
+ const params = heading.templateAnnotation?.params ?? {};
121
+ const data = buildChartData(tableText(table), {
122
+ labelColumn: params.labelColumn,
123
+ valueColumns: listParam(params.valueColumns)
124
+ });
125
+ if (!data) return null;
126
+ const { showTable } = params;
127
+ const chartParams = Object.fromEntries(
128
+ Object.entries(params).filter(([key]) => !NON_CHART_PARAMS.has(key))
129
+ );
130
+ const chartHeading = {
131
+ ...heading,
132
+ templateAnnotation: { template, params: chartParams }
133
+ };
134
+ const title = extractPlainText(heading).trim();
135
+ const plotted = data.series.map((series) => series.name).join(", ");
136
+ const what = `${template.replace(/Chart$/, "")} chart of ${plotted}${data.labelHeader ? ` by ${data.labelHeader}` : ""}`;
137
+ return {
138
+ chart: { headingIndex: index, tableIndex, keepTable: isTruthyParam(showTable) },
139
+ diagram: {
140
+ kind: "chart",
141
+ markdown: stringifyMarkdown({ type: "document", children: [chartHeading, table] }).trim(),
142
+ source: "",
143
+ template,
144
+ alt: title ? `${title}: ${what}` : what.charAt(0).toUpperCase() + what.slice(1)
145
+ }
146
+ };
147
+ }
148
+ function findInDocument(doc) {
149
+ const found = [];
150
+ const children = doc.children;
151
+ const walk = (nodes) => {
152
+ for (const node of nodes) {
153
+ if (node.type === "code") {
154
+ const fence = node;
155
+ const kind = fenceDiagramKind(fence);
156
+ if (kind) {
157
+ found.push({
158
+ fence,
159
+ diagram: {
160
+ kind,
161
+ markdown: fenceMarkdown(fence),
162
+ source: fence.value,
163
+ template: "",
164
+ alt: fenceAlt(kind, fence.value) || KIND_NAMES[kind]
165
+ }
166
+ });
167
+ }
168
+ continue;
169
+ }
170
+ const nested = node.children;
171
+ if (Array.isArray(nested) && node.type !== "heading" && node.type !== "paragraph") {
172
+ walk(nested);
173
+ }
174
+ }
175
+ };
176
+ for (let index = 0; index < children.length; index++) {
177
+ const node = children[index];
178
+ const template = containerTemplateOf(node);
179
+ if (!template) {
180
+ const chart = node.type === "heading" ? findChart(children, index) : null;
181
+ if (chart) found.push(chart);
182
+ walk([node]);
183
+ continue;
184
+ }
185
+ const depth = node.depth;
186
+ let end = index + 1;
187
+ while (end < children.length) {
188
+ const next = children[end];
189
+ if (next.type === "heading" && next.depth <= depth) break;
190
+ end++;
191
+ }
192
+ const heading = extractPlainText(node).trim();
193
+ found.push({
194
+ containerIndex: index,
195
+ containerEnd: end,
196
+ diagram: {
197
+ kind: "container",
198
+ markdown: stringifyMarkdown({
199
+ type: "document",
200
+ children: children.slice(index, end)
201
+ }).trim(),
202
+ source: "",
203
+ template,
204
+ alt: heading || KIND_NAMES.container
205
+ }
206
+ });
207
+ index = end - 1;
208
+ }
209
+ return found;
210
+ }
211
+ function imageUrls(nodes, into) {
212
+ for (const node of nodes) {
213
+ if (node.type === "image") into.add(node.url);
214
+ const nested = node.children;
215
+ if (Array.isArray(nested)) imageUrls(nested, into);
216
+ }
217
+ return into;
218
+ }
219
+ function findDiagrams(doc) {
220
+ return findInDocument(doc).map((entry) => entry.diagram);
221
+ }
222
+ function withoutTemplate(heading) {
223
+ const { templateAnnotation: _template, ...plain } = heading;
224
+ return plain;
225
+ }
226
+ function imageParagraph(url, alt) {
227
+ const image = { type: "image", url, alt, title: null };
228
+ return { type: "paragraph", children: [image] };
229
+ }
230
+ function replaceFences(nodes, replacements) {
231
+ let changed = false;
232
+ const next = nodes.map((node) => {
233
+ const replacement = replacements.get(node);
234
+ if (replacement) {
235
+ changed = true;
236
+ return replacement;
237
+ }
238
+ const nested = node.children;
239
+ if (Array.isArray(nested)) {
240
+ const replaced = replaceFences(nested, replacements);
241
+ if (replaced !== nested) {
242
+ changed = true;
243
+ return { ...node, children: replaced };
244
+ }
245
+ }
246
+ return node;
247
+ });
248
+ return changed ? next : nodes;
249
+ }
250
+ function cachingDiagramRasterizer(render, limit = 64) {
251
+ const drawn = /* @__PURE__ */ new Map();
252
+ return (diagram) => {
253
+ const key = `${diagram.kind}\0${diagram.markdown}\0${diagram.source}`;
254
+ let picture = drawn.get(key);
255
+ if (picture) {
256
+ drawn.delete(key);
257
+ } else {
258
+ picture = render(diagram);
259
+ picture.catch(() => drawn.delete(key));
260
+ }
261
+ drawn.set(key, picture);
262
+ if (drawn.size > limit) drawn.delete(drawn.keys().next().value);
263
+ return picture;
264
+ };
265
+ }
266
+ async function rasterizeDiagrams(doc, render, options = {}) {
267
+ const kinds = new Set(options.kinds ?? DEFAULT_KINDS);
268
+ const prefix = options.urlPrefix ?? "diagram";
269
+ const taken = imageUrls(doc.children, /* @__PURE__ */ new Set());
270
+ let counter = 0;
271
+ const nextUrl = () => {
272
+ let url;
273
+ do
274
+ url = `${prefix}-${String(++counter)}.png`;
275
+ while (taken.has(url));
276
+ taken.add(url);
277
+ return url;
278
+ };
279
+ const images = /* @__PURE__ */ new Map();
280
+ const mermaid = /* @__PURE__ */ new Map();
281
+ const svg = /* @__PURE__ */ new Map();
282
+ const fenceReplacements = /* @__PURE__ */ new Map();
283
+ const blockReplacements = [];
284
+ for (const entry of findInDocument(doc)) {
285
+ options.signal?.throwIfAborted();
286
+ if (!kinds.has(entry.diagram.kind)) continue;
287
+ let picture = null;
288
+ try {
289
+ picture = await render(entry.diagram);
290
+ } catch (error) {
291
+ options.onWarning?.(
292
+ `A ${KIND_NAMES[entry.diagram.kind].toLowerCase()} could not be drawn and was kept as text: ${error instanceof Error ? error.message : String(error)}`
293
+ );
294
+ }
295
+ if (!picture || picture.width <= 0 || picture.height <= 0) continue;
296
+ const data = picture.data instanceof Uint8Array ? picture.data : new Uint8Array(picture.data);
297
+ const url = nextUrl();
298
+ images.set(url, {
299
+ data,
300
+ contentType: "image/png",
301
+ width: picture.width,
302
+ height: picture.height
303
+ });
304
+ if (entry.diagram.kind === "mermaid") mermaid.set(entry.diagram.source.trim(), picture);
305
+ if (entry.diagram.kind === "svg") svg.set(entry.diagram.source.trim(), picture);
306
+ const paragraph = imageParagraph(url, entry.diagram.alt);
307
+ if (entry.fence) {
308
+ fenceReplacements.set(entry.fence, paragraph);
309
+ } else if (entry.containerIndex !== void 0 && entry.containerEnd !== void 0) {
310
+ blockReplacements.push({
311
+ start: entry.containerIndex,
312
+ end: entry.containerEnd,
313
+ nodes: [withoutTemplate(doc.children[entry.containerIndex]), paragraph]
314
+ });
315
+ } else if (entry.chart) {
316
+ const { headingIndex, tableIndex, keepTable } = entry.chart;
317
+ const table = doc.children[tableIndex];
318
+ blockReplacements.push(
319
+ {
320
+ start: headingIndex,
321
+ end: headingIndex + 1,
322
+ nodes: [withoutTemplate(doc.children[headingIndex])]
323
+ },
324
+ {
325
+ start: tableIndex,
326
+ end: tableIndex + 1,
327
+ nodes: keepTable ? [paragraph, table] : [paragraph]
328
+ }
329
+ );
330
+ }
331
+ }
332
+ let children = doc.children;
333
+ if (blockReplacements.length > 0) {
334
+ const rebuilt = [];
335
+ let cursor = 0;
336
+ for (const replacement of blockReplacements) {
337
+ rebuilt.push(...children.slice(cursor, replacement.start), ...replacement.nodes);
338
+ cursor = replacement.end;
339
+ }
340
+ rebuilt.push(...children.slice(cursor));
341
+ children = rebuilt;
342
+ }
343
+ if (fenceReplacements.size > 0) children = replaceFences(children, fenceReplacements);
344
+ return {
345
+ markdownDoc: children === doc.children ? doc : { ...doc, children },
346
+ images,
347
+ mermaid,
348
+ svg
349
+ };
350
+ }
351
+
352
+ export {
353
+ EXPORT_DIAGRAM_KINDS,
354
+ fenceDiagramKind,
355
+ findDiagrams,
356
+ cachingDiagramRasterizer,
357
+ rasterizeDiagrams
358
+ };
@@ -8,9 +8,6 @@ import {
8
8
  parseCsv
9
9
  } from "./chunk-Q77KNJIN.js";
10
10
 
11
- // src/data/materialize.ts
12
- import { isDataFilePath } from "@bendyline/squisq/doc";
13
-
14
11
  // src/data/readers.ts
15
12
  import { applyTableViewState, parseTableViewState } from "@bendyline/squisq/table";
16
13
  function applyViewParams(headers, body, opts) {
@@ -152,89 +149,9 @@ function defaultDataReaders() {
152
149
  return [csvDataReader, xlsxDataReader, parquetDataReader];
153
150
  }
154
151
 
155
- // src/data/materialize.ts
156
- function tableRow(cells) {
157
- return {
158
- type: "tableRow",
159
- children: cells.map((value) => ({
160
- type: "tableCell",
161
- children: value ? [{ type: "text", value }] : []
162
- }))
163
- };
164
- }
165
- function extensionOf(path) {
166
- const base = path.split("/").pop() ?? path;
167
- const dot = base.lastIndexOf(".");
168
- return dot > 0 ? base.slice(dot + 1).toLowerCase() : "";
169
- }
170
- async function materializeDataReferences(markdownDoc, container, onWarning) {
171
- const readers = defaultDataReaders();
172
- const children = [];
173
- let changed = false;
174
- for (const node of markdownDoc.children) {
175
- children.push(node);
176
- if (node.type !== "heading") continue;
177
- const params = node.templateAnnotation?.params;
178
- const src = params?.src;
179
- if (!src || !isDataFilePath(src)) continue;
180
- const label = params?.sheet && params?.anchor ? `${params.sheet}!${params.anchor}` : src;
181
- if (!container) {
182
- onWarning?.(
183
- `Data reference "${src}" could not be embedded: the export has no source container to read it from.`
184
- );
185
- continue;
186
- }
187
- const ext = extensionOf(src);
188
- const reader = readers.find((r) => r.extensions.includes(ext));
189
- if (!reader) {
190
- onWarning?.(`Data reference "${src}" could not be embedded: no reader for ".${ext}".`);
191
- continue;
192
- }
193
- let bytes = null;
194
- try {
195
- bytes = await container.readFile(src);
196
- } catch {
197
- bytes = null;
198
- }
199
- if (!bytes) {
200
- onWarning?.(`Data reference "${src}" could not be embedded: file not found in container.`);
201
- continue;
202
- }
203
- try {
204
- const table = await reader.read(bytes, {
205
- maxRows: Number.POSITIVE_INFINITY,
206
- ...params?.sheet ? { sheet: params.sheet } : {},
207
- ...params?.anchor ? { anchor: params.anchor } : {},
208
- ...params?.headerRow !== void 0 ? { headerRow: params.headerRow !== "false" } : {},
209
- // Exports honor the author's curated view: the sort/filter params
210
- // shape the embedded full table exactly as they shape previews.
211
- ...params?.sort ? { sort: params.sort } : {},
212
- ...params?.filter ? { filter: params.filter } : {}
213
- });
214
- const mdTable = {
215
- type: "table",
216
- children: [tableRow(table.headers), ...table.rows.map(tableRow)]
217
- };
218
- children.push(mdTable);
219
- changed = true;
220
- if (ext === "xlsx") {
221
- onWarning?.(
222
- `Region ${label} exported as values; formulas in the sidecar workbook were not carried over.`
223
- );
224
- }
225
- } catch (err) {
226
- onWarning?.(
227
- `Data reference "${src}" could not be embedded: ${err instanceof Error ? err.message : String(err)}`
228
- );
229
- }
230
- }
231
- return changed ? { ...markdownDoc, children } : markdownDoc;
232
- }
233
-
234
152
  export {
235
153
  csvDataReader,
236
154
  xlsxDataReader,
237
155
  parquetDataReader,
238
- defaultDataReaders,
239
- materializeDataReferences
156
+ defaultDataReaders
240
157
  };
@@ -1,14 +1,15 @@
1
1
  import {
2
2
  convert,
3
3
  defaultRegistry
4
- } from "./chunk-ALDCFHZT.js";
4
+ } from "./chunk-WVDAFJFS.js";
5
5
  import {
6
6
  ConversionError
7
7
  } from "./chunk-KXOZMWBS.js";
8
8
  import {
9
9
  OUTSIDE_IN_FORMAT_IDS,
10
+ OUTSIDE_IN_OUTPUT_TEMPLATE_KEY,
10
11
  resolveOutsideInLayout
11
- } from "./chunk-C23JYVPG.js";
12
+ } from "./chunk-WJTC5OD6.js";
12
13
 
13
14
  // src/outside-in/index.ts
14
15
  import {
@@ -63,6 +64,17 @@ function isOutsideInMarkdownEditingEnabled(source) {
63
64
  const frontmatter = yaml === null ? null : parseFrontmatter(yaml);
64
65
  return frontmatter?.[OUTSIDE_IN_UPDATE_FROM_MARKDOWN_KEY] === true;
65
66
  }
67
+ function readOutsideInOutputTemplate(source) {
68
+ const frontmatter = typeof source === "string" ? (() => {
69
+ const yaml = rawFrontmatter(source);
70
+ return yaml === null ? null : parseFrontmatter(yaml);
71
+ })() : source.frontmatter;
72
+ const value = frontmatter?.[OUTSIDE_IN_OUTPUT_TEMPLATE_KEY];
73
+ if (typeof value !== "string") return null;
74
+ const trimmed = value.trim();
75
+ if (!trimmed) return null;
76
+ return trimmed.toLowerCase() === "none" ? "none" : trimmed;
77
+ }
66
78
  function withOutsideInMarkdownEditing(source, layout, enabled = true) {
67
79
  return setFrontmatterValues(withOutsideInMetadata(source, layout), {
68
80
  [OUTSIDE_IN_UPDATE_FROM_MARKDOWN_KEY]: enabled
@@ -176,7 +188,9 @@ async function renderOutsideInDocument(source, options = {}) {
176
188
  { format: "html" }
177
189
  );
178
190
  }
179
- const formatOptions = { ...options.formatOptions ?? {} };
191
+ const formatOptions = {
192
+ ...options.formatOptions ?? {}
193
+ };
180
194
  if (layout.format === "html" && options.html) {
181
195
  formatOptions.html = {
182
196
  ...formatOptions.html ?? {},
@@ -184,10 +198,19 @@ async function renderOutsideInDocument(source, options = {}) {
184
198
  basePath: options.html.basePath ?? layout.companionName
185
199
  };
186
200
  }
187
- return convert(
201
+ const warnings = [];
202
+ const markdown = await prepareOutsideInMarkdown(
203
+ source.markdown,
204
+ layout.format,
205
+ source.container,
206
+ options,
207
+ formatOptions,
208
+ warnings
209
+ );
210
+ const result = await convert(
188
211
  {
189
212
  kind: "markdown",
190
- markdown: source.markdown,
213
+ markdown,
191
214
  container: source.container,
192
215
  baseName: layout.stem
193
216
  },
@@ -198,6 +221,52 @@ async function renderOutsideInDocument(source, options = {}) {
198
221
  formatOptions
199
222
  }
200
223
  );
224
+ return warnings.length > 0 ? { ...result, warnings: [...warnings, ...result.warnings] } : result;
225
+ }
226
+ async function prepareOutsideInMarkdown(markdown, format, container, options, formatOptions, warnings) {
227
+ const render = options.renderDiagram;
228
+ if (!render || format !== "docx" && format !== "pdf" && format !== "pptx") return markdown;
229
+ const onWarning = (message) => {
230
+ warnings.push(message);
231
+ };
232
+ let doc = typeof markdown === "string" ? parseMarkdown(markdown) : markdown;
233
+ const { rasterizeDiagrams, EXPORT_DIAGRAM_KINDS } = await import("./diagrams/index.js");
234
+ const signal = options.signal;
235
+ if (format === "pptx") {
236
+ const { mermaid, svg } = await rasterizeDiagrams(doc, render, {
237
+ kinds: ["mermaid", "svg"],
238
+ signal,
239
+ onWarning
240
+ });
241
+ formatOptions.pptx = {
242
+ ...formatOptions.pptx,
243
+ diagramImages: new Map([...mermaid, ...svg, ...formatOptions.pptx?.diagramImages ?? []])
244
+ };
245
+ return doc;
246
+ }
247
+ const { materializeDataReferences, DATA_PREVIEW_ROWS } = await import("./materialize-ICXNO4S4.js");
248
+ doc = await materializeDataReferences(doc, container, onWarning, {
249
+ maxRows: DATA_PREVIEW_ROWS
250
+ });
251
+ const pictured = await rasterizeDiagrams(doc, render, {
252
+ kinds: format === "pdf" ? EXPORT_DIAGRAM_KINDS : void 0,
253
+ signal,
254
+ onWarning
255
+ });
256
+ if (format === "docx") {
257
+ const { svg } = await rasterizeDiagrams(doc, render, { kinds: ["svg"], signal, onWarning });
258
+ formatOptions.docx = {
259
+ ...formatOptions.docx,
260
+ images: new Map([...formatOptions.docx?.images ?? [], ...pictured.images]),
261
+ svgIslandFallbacks: new Map([...svg, ...formatOptions.docx?.svgIslandFallbacks ?? []])
262
+ };
263
+ } else {
264
+ formatOptions.pdf = {
265
+ ...formatOptions.pdf,
266
+ images: new Map([...formatOptions.pdf?.images ?? [], ...pictured.images])
267
+ };
268
+ }
269
+ return pictured.markdownDoc;
201
270
  }
202
271
 
203
272
  export {
@@ -205,6 +274,7 @@ export {
205
274
  readOutsideInMetadata,
206
275
  withOutsideInMetadata,
207
276
  isOutsideInMarkdownEditingEnabled,
277
+ readOutsideInOutputTemplate,
208
278
  withOutsideInMarkdownEditing,
209
279
  importOutsideInDocument,
210
280
  renderOutsideInDocument
@@ -1,3 +1,45 @@
1
+ // src/shared/blockTags.ts
2
+ import {
3
+ detectPromotableBodyAnnotation,
4
+ hasTemplate,
5
+ isMediaAnnotationName,
6
+ parseStandaloneAnnotation
7
+ } from "@bendyline/squisq/doc";
8
+ function withoutBlockTags(doc, options = {}) {
9
+ const children = withoutPromotedTags(doc.children);
10
+ const kept = children.filter((node) => !isRemovedTag(node, options));
11
+ return kept.length === doc.children.length && children === doc.children ? doc : { ...doc, children: kept };
12
+ }
13
+ function isRemovedTag(node, options) {
14
+ const tag = parseStandaloneAnnotation(node)?.template;
15
+ if (!tag) return false;
16
+ if (isMediaAnnotationName(tag)) return !options.keepMedia;
17
+ return hasTemplate(tag);
18
+ }
19
+ function withoutPromotedTags(children) {
20
+ const out = [];
21
+ let changed = false;
22
+ let index = 0;
23
+ while (index < children.length) {
24
+ const node = children[index++];
25
+ out.push(node);
26
+ if (node.type !== "heading" || node.templateAnnotation?.template) continue;
27
+ let end = index;
28
+ while (end < children.length && children[end].type !== "heading") end++;
29
+ const body = children.slice(index, end);
30
+ const found = detectPromotableBodyAnnotation(body);
31
+ const tag = found?.data.template;
32
+ if (found && tag && !isMediaAnnotationName(tag) && hasTemplate(tag)) {
33
+ out.push(...found.strippedContents);
34
+ changed = true;
35
+ } else {
36
+ out.push(...body);
37
+ }
38
+ index = end;
39
+ }
40
+ return changed ? out : children;
41
+ }
42
+
1
43
  // src/shared/footnotes.ts
2
44
  var FootnoteIndex = class {
3
45
  constructor(doc) {
@@ -102,6 +144,7 @@ function renumberFootnotes(doc) {
102
144
  }
103
145
 
104
146
  export {
147
+ withoutBlockTags,
105
148
  FootnoteIndex,
106
149
  footnoteIds,
107
150
  renumberFootnotes
@@ -60,7 +60,7 @@ import {
60
60
  fontAwesomeFace,
61
61
  fontAwesomeFaces,
62
62
  fontAwesomeGlyph
63
- } from "./chunk-LBXBRFBZ.js";
63
+ } from "./chunk-DDMPZZJF.js";
64
64
  import {
65
65
  extToMime,
66
66
  readImageDimensions