@sofereditor/export-docx 0.7.0 → 0.9.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/dist/index.cjs +55 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +57 -18
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -56,8 +56,8 @@ function normalize(doc) {
|
|
|
56
56
|
return (0, import_core.isLegacySerializedDocument)(doc) ? { blocks: doc } : doc;
|
|
57
57
|
}
|
|
58
58
|
function buildDocument(doc, options, images) {
|
|
59
|
-
const children = blocksToDocxChildren(doc, images);
|
|
60
59
|
const settings = doc.pageSettings ?? import_core.DEFAULT_PAGE_SETTINGS;
|
|
60
|
+
const children = blocksToDocxChildren(doc, images, settings);
|
|
61
61
|
return new import_docx.Document({
|
|
62
62
|
creator: options.creator,
|
|
63
63
|
title: options.title,
|
|
@@ -98,7 +98,7 @@ function sectionPropertiesFor(settings) {
|
|
|
98
98
|
}
|
|
99
99
|
};
|
|
100
100
|
}
|
|
101
|
-
function blocksToDocxChildren(doc, images) {
|
|
101
|
+
function blocksToDocxChildren(doc, images, settings) {
|
|
102
102
|
const out = [];
|
|
103
103
|
const blocks = doc.blocks;
|
|
104
104
|
for (let i = 0; i < blocks.length; i++) {
|
|
@@ -120,7 +120,7 @@ function blocksToDocxChildren(doc, images) {
|
|
|
120
120
|
out.push(makeListItem(block, images));
|
|
121
121
|
break;
|
|
122
122
|
case "table":
|
|
123
|
-
out.push(makeTable(block, images));
|
|
123
|
+
out.push(makeTable(block, images, settings));
|
|
124
124
|
break;
|
|
125
125
|
default:
|
|
126
126
|
out.push(makeParagraph(block, images));
|
|
@@ -183,10 +183,11 @@ function makeListItem(block, images) {
|
|
|
183
183
|
children: deltaToRuns(block.delta, ARIAL, images)
|
|
184
184
|
});
|
|
185
185
|
}
|
|
186
|
-
function makeTable(block, images) {
|
|
186
|
+
function makeTable(block, images, settings) {
|
|
187
187
|
const rows = typeof block.attrs.rows === "number" ? block.attrs.rows : 0;
|
|
188
188
|
const cols = typeof block.attrs.cols === "number" ? block.attrs.cols : 0;
|
|
189
189
|
const cells = block.cells ?? [];
|
|
190
|
+
const alturas = block.attrs.rowHeights;
|
|
190
191
|
const rowsOut = [];
|
|
191
192
|
for (let r = 0; r < rows; r++) {
|
|
192
193
|
const cellsOut = [];
|
|
@@ -199,22 +200,36 @@ function makeTable(block, images) {
|
|
|
199
200
|
if (cell.attrs?.covered) continue;
|
|
200
201
|
cellsOut.push(makeCell(cell, images));
|
|
201
202
|
}
|
|
202
|
-
|
|
203
|
+
const raw = Array.isArray(alturas) && alturas.length === rows ? alturas[r] : void 0;
|
|
204
|
+
const h = typeof raw === "number" && isFinite(raw) ? Math.max(0, raw) : void 0;
|
|
205
|
+
rowsOut.push(
|
|
206
|
+
new import_docx.TableRow({
|
|
207
|
+
children: cellsOut,
|
|
208
|
+
...h != null ? { height: { value: (0, import_docx.convertMillimetersToTwip)((0, import_core.pxToMm)(h)), rule: import_docx.HeightRule.ATLEAST } } : {}
|
|
209
|
+
})
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
if (cols <= 0) {
|
|
213
|
+
return new import_docx.Table({
|
|
214
|
+
rows: rowsOut,
|
|
215
|
+
borders: docxTableBorders(block.attrs.borderPreset, block.attrs.borderColor),
|
|
216
|
+
width: { size: 100, type: import_docx.WidthType.PERCENTAGE }
|
|
217
|
+
});
|
|
203
218
|
}
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
219
|
+
const larguraUtilTwips = (0, import_docx.convertMillimetersToTwip)(
|
|
220
|
+
(0, import_core.pxToMm)(settings.width - settings.marginLeft - settings.marginRight)
|
|
221
|
+
);
|
|
222
|
+
const tabelaTwips = Math.round(larguraUtilTwips * ((block.attrs.tableWidth ?? 100) / 100));
|
|
223
|
+
const pct = (0, import_core.normalizarLarguras)(block.attrs.colWidths, cols);
|
|
224
|
+
const columnWidths = pct.map((p) => Math.round(tabelaTwips * (p / 100)));
|
|
207
225
|
return new import_docx.Table({
|
|
208
226
|
rows: rowsOut,
|
|
209
227
|
borders: docxTableBorders(block.attrs.borderPreset, block.attrs.borderColor),
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
layout: import_docx.TableLayoutType.FIXED,
|
|
216
|
-
width: { size: columnWidths.reduce((a, b) => a + b, 0), type: import_docx.WidthType.DXA }
|
|
217
|
-
} : { width: { size: 100, type: import_docx.WidthType.PERCENTAGE } }
|
|
228
|
+
columnWidths,
|
|
229
|
+
// O `layout: FIXED` permanece pelo mesmo motivo de antes: sem ele o Word
|
|
230
|
+
// autoajusta ao conteúdo e trata `columnWidths` como mero palpite.
|
|
231
|
+
layout: import_docx.TableLayoutType.FIXED,
|
|
232
|
+
width: { size: columnWidths.reduce((a, b) => a + b, 0), type: import_docx.WidthType.DXA }
|
|
218
233
|
});
|
|
219
234
|
}
|
|
220
235
|
function docxTableBorders(preset, color) {
|
|
@@ -311,6 +326,18 @@ function makeTextRun(text, marks, defaults) {
|
|
|
311
326
|
function makeImageRun(embed, images) {
|
|
312
327
|
const resolved = images.get(embed.src);
|
|
313
328
|
if (!resolved) return null;
|
|
329
|
+
if (resolved.type === "svg") {
|
|
330
|
+
if (!resolved.svgFallback) return null;
|
|
331
|
+
return new import_docx.ImageRun({
|
|
332
|
+
type: "svg",
|
|
333
|
+
data: resolved.data,
|
|
334
|
+
fallback: { type: resolved.svgFallback.type, data: resolved.svgFallback.data },
|
|
335
|
+
transformation: {
|
|
336
|
+
width: Math.max(1, Math.round(embed.width)),
|
|
337
|
+
height: Math.max(1, Math.round(embed.height))
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
}
|
|
314
341
|
return new import_docx.ImageRun({
|
|
315
342
|
data: resolved.data,
|
|
316
343
|
type: resolved.type,
|
|
@@ -355,8 +382,14 @@ function typeFromExtension(src) {
|
|
|
355
382
|
}
|
|
356
383
|
async function resolveAllImages(doc, resolve) {
|
|
357
384
|
const srcs = /* @__PURE__ */ new Set();
|
|
385
|
+
const fallbacks = /* @__PURE__ */ new Map();
|
|
358
386
|
const collect = (delta) => {
|
|
359
|
-
for (const op of delta)
|
|
387
|
+
for (const op of delta) {
|
|
388
|
+
if (!(0, import_core.isImageEmbed)(op.insert)) continue;
|
|
389
|
+
srcs.add(op.insert.src);
|
|
390
|
+
const fb = op.insert.svgFallback;
|
|
391
|
+
if (fb && !fallbacks.has(op.insert.src)) fallbacks.set(op.insert.src, fb);
|
|
392
|
+
}
|
|
360
393
|
};
|
|
361
394
|
for (const block of doc.blocks) {
|
|
362
395
|
collect(block.delta);
|
|
@@ -371,7 +404,11 @@ async function resolveAllImages(doc, resolve) {
|
|
|
371
404
|
} catch {
|
|
372
405
|
resolved = null;
|
|
373
406
|
}
|
|
374
|
-
if (resolved?.type === "svg")
|
|
407
|
+
if (resolved?.type === "svg") {
|
|
408
|
+
const fb = fallbacks.get(src);
|
|
409
|
+
const decodedFb = fb ? decodeDataUrl(fb) : null;
|
|
410
|
+
resolved = decodedFb && decodedFb.kind !== "svg" ? { ...resolved, svgFallback: { data: decodedFb.bytes, type: decodedFb.kind } } : null;
|
|
411
|
+
}
|
|
375
412
|
images.set(src, resolved);
|
|
376
413
|
})
|
|
377
414
|
);
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/docx.ts"],"sourcesContent":["export { documentToDocxBlob, documentToDocxBuffer } from \"./docx\";\nexport type { DocumentToDocxOptions, ResolvedImage } from \"./docx\";\n","import type {\n AlignValue,\n DeltaOp,\n ImageEmbed,\n LegacySerializedDocument,\n ListKind,\n MarkAttrs,\n SerializedBlock,\n SerializedCell,\n SerializedDocument,\n TableBorderPreset,\n} from \"@sofereditor/core\";\nimport {\n DEFAULT_PAGE_SETTINGS,\n isImageEmbed,\n isLegacySerializedDocument,\n pxToMm,\n type PageSettings,\n} from \"@sofereditor/core\";\nimport {\n AlignmentType,\n BorderStyle,\n Document,\n HeadingLevel,\n ImageRun,\n LevelFormat,\n LineRuleType,\n Packer,\n Paragraph,\n PageOrientation,\n ShadingType,\n Table,\n TableCell,\n TableLayoutType,\n TableRow,\n TextRun,\n UnderlineType,\n VerticalAlign,\n WidthType,\n convertMillimetersToTwip,\n} from \"docx\";\n\nconst BULLET_REF = \"ed-bullet\";\nconst ORDERED_REF = \"ed-ordered\";\n\nexport interface ResolvedImage {\n data: Uint8Array;\n type: \"png\" | \"jpg\" | \"gif\" | \"bmp\" | \"svg\";\n}\n\nexport interface DocumentToDocxOptions {\n /** Document title; embedded in core properties. */\n title?: string;\n /** Author for core properties. */\n creator?: string;\n /**\n * Resolve um `src` de imagem para bytes. Default: data URLs (decodificadas\n * localmente) e http(s) via fetch. Retornar null pula a imagem (contada em\n * `skippedImages`) sem abortar o export.\n */\n resolveImage?: (src: string) => Promise<ResolvedImage | null>;\n}\n\n/**\n * Build a docx `Document` from a `SerializedDocument`. Output is a Blob you can\n * download with `downloadBlob` from `@sofereditor/export-pdf`.\n *\n * Mappings:\n * - paragraph / heading / blockquote / codeBlock → Paragraph (with `heading`,\n * shading, monospace font for code)\n * - listItem → Paragraph with `numbering: { reference, level }`\n * - table → docx `Table`. `rowspan`/`colspan` map to TableCell's `rowSpan`/\n * `columnSpan`; \"covered\" cells are skipped (docx infers cover from spans)\n * - inline marks → TextRun props (bold, italics, underline, strike, color,\n * font, size in half-points)\n * - image embeds → ImageRun with bytes resolved via `resolveImage` (default:\n * data URLs decoded locally, http(s) fetched; unresolved images are\n * skipped and counted in `skippedImages` instead of aborting the export)\n */\nexport async function documentToDocxBlob(\n doc: SerializedDocument | LegacySerializedDocument,\n options: DocumentToDocxOptions = {},\n): Promise<{ blob: Blob; skippedImages: number }> {\n const normalized = normalize(doc);\n const { images, skipped } = await resolveAllImages(\n normalized,\n options.resolveImage ?? defaultResolveImage,\n );\n const built = buildDocument(normalized, options, images);\n return { blob: await Packer.toBlob(built), skippedImages: skipped };\n}\n\n/** Same as `documentToDocxBlob` but returns a Uint8Array (useful in Node/tests). */\nexport async function documentToDocxBuffer(\n doc: SerializedDocument | LegacySerializedDocument,\n options: DocumentToDocxOptions = {},\n): Promise<{ buffer: Uint8Array; skippedImages: number }> {\n const normalized = normalize(doc);\n const { images, skipped } = await resolveAllImages(\n normalized,\n options.resolveImage ?? defaultResolveImage,\n );\n const built = buildDocument(normalized, options, images);\n const buf = await Packer.toBuffer(built);\n // `Packer.toBuffer` returns a Node Buffer at runtime — coerce for consumers.\n return {\n buffer: buf instanceof Uint8Array ? buf : new Uint8Array(buf),\n skippedImages: skipped,\n };\n}\n\nfunction normalize(doc: SerializedDocument | LegacySerializedDocument): SerializedDocument {\n return isLegacySerializedDocument(doc) ? { blocks: doc } : doc;\n}\n\nfunction buildDocument(\n doc: SerializedDocument,\n options: DocumentToDocxOptions,\n images: Map<string, ResolvedImage | null>,\n): Document {\n const children = blocksToDocxChildren(doc, images);\n const settings = doc.pageSettings ?? DEFAULT_PAGE_SETTINGS;\n return new Document({\n creator: options.creator,\n title: options.title,\n numbering: {\n config: [\n {\n reference: BULLET_REF,\n levels: buildBulletLevels(),\n },\n {\n reference: ORDERED_REF,\n levels: buildOrderedLevels(),\n },\n ],\n },\n sections: [\n {\n properties: sectionPropertiesFor(settings),\n children,\n },\n ],\n });\n}\n\nfunction sectionPropertiesFor(settings: PageSettings) {\n return {\n page: {\n size: {\n width: convertMillimetersToTwip(pxToMm(settings.width)),\n height: convertMillimetersToTwip(pxToMm(settings.height)),\n orientation: PageOrientation.PORTRAIT,\n },\n margin: {\n top: convertMillimetersToTwip(pxToMm(settings.marginTop)),\n bottom: convertMillimetersToTwip(pxToMm(settings.marginBottom)),\n left: convertMillimetersToTwip(pxToMm(settings.marginLeft)),\n right: convertMillimetersToTwip(pxToMm(settings.marginRight)),\n },\n },\n };\n}\n\nfunction blocksToDocxChildren(\n doc: SerializedDocument,\n images: Map<string, ResolvedImage | null>,\n): Array<Paragraph | Table> {\n const out: Array<Paragraph | Table> = [];\n const blocks = doc.blocks;\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i];\n switch (block.type) {\n case \"paragraph\":\n out.push(makeParagraph(block, images));\n break;\n case \"heading\":\n out.push(makeHeading(block, images));\n break;\n case \"blockquote\":\n out.push(makeBlockquote(block, images));\n break;\n case \"codeBlock\":\n out.push(makeCodeBlock(block, images));\n break;\n case \"listItem\":\n out.push(makeListItem(block, images));\n break;\n case \"table\":\n out.push(makeTable(block, images));\n break;\n default:\n out.push(makeParagraph(block, images));\n }\n }\n return out;\n}\n\n// ---------- block builders ----------\n\n// School standard: Arial for all body text. Code blocks override with\n// Consolas (monospace is more legible for code). Italics on blockquote is\n// kept as a stylistic default.\nconst ARIAL: RunDefaults = { font: \"Arial\" };\n\nfunction makeParagraph(\n block: SerializedBlock,\n images: Map<string, ResolvedImage | null>,\n): Paragraph {\n return new Paragraph({\n alignment: alignFor(block.attrs.align),\n bidirectional: block.attrs.dir === \"rtl\" ? true : undefined,\n ...answerLineProps(block.attrs),\n children: deltaToRuns(block.delta, ARIAL, images),\n });\n}\n\n/**\n * Linha de resposta → borda inferior de parágrafo (`w:pBdr`) + entrelinha.\n * É como um documento profissional desenha uma pauta: a régua acompanha a\n * margem automaticamente, ao contrário de uma fileira de underlines.\n *\n * 240 twips = uma linha simples no OOXML.\n */\nfunction answerLineProps(attrs: SerializedBlock[\"attrs\"]) {\n if (attrs.answerLine !== true) return {};\n const spacing = attrs.answerLineSpacing ?? 1;\n return {\n border: {\n bottom: { style: BorderStyle.SINGLE, size: 6, color: \"000000\", space: 1 },\n },\n spacing: { line: Math.round(240 * spacing), lineRule: LineRuleType.AUTO },\n };\n}\n\nfunction makeHeading(\n block: SerializedBlock,\n images: Map<string, ResolvedImage | null>,\n): Paragraph {\n const level = clampHeadingLevel(block.attrs.level);\n return new Paragraph({\n heading: HEADING_LEVELS[level - 1],\n alignment: alignFor(block.attrs.align),\n children: deltaToRuns(block.delta, ARIAL, images),\n });\n}\n\nfunction makeBlockquote(\n block: SerializedBlock,\n images: Map<string, ResolvedImage | null>,\n): Paragraph {\n return new Paragraph({\n alignment: alignFor(block.attrs.align),\n indent: { left: 480 }, // ~0.25\"\n border: {\n left: { color: \"CBD5E1\", space: 12, style: BorderStyle.SINGLE, size: 12 },\n },\n children: deltaToRuns(block.delta, { ...ARIAL, italics: true }, images),\n });\n}\n\nfunction makeCodeBlock(\n block: SerializedBlock,\n images: Map<string, ResolvedImage | null>,\n): Paragraph {\n return new Paragraph({\n spacing: { before: 100, after: 100 },\n shading: { type: ShadingType.CLEAR, color: \"auto\", fill: \"F1F5F9\" },\n children: deltaToRuns(block.delta, { font: \"Consolas\", size: 20 }, images),\n });\n}\n\nfunction makeListItem(\n block: SerializedBlock,\n images: Map<string, ResolvedImage | null>,\n): Paragraph {\n const kind: ListKind = block.attrs.listKind === \"ordered\" ? \"ordered\" : \"bullet\";\n const reference = kind === \"ordered\" ? ORDERED_REF : BULLET_REF;\n const level = clampListLevel(block.attrs.listLevel);\n return new Paragraph({\n numbering: { reference, level },\n alignment: alignFor(block.attrs.align),\n children: deltaToRuns(block.delta, ARIAL, images),\n });\n}\n\nfunction makeTable(block: SerializedBlock, images: Map<string, ResolvedImage | null>): Table {\n const rows = typeof block.attrs.rows === \"number\" ? block.attrs.rows : 0;\n const cols = typeof block.attrs.cols === \"number\" ? block.attrs.cols : 0;\n const cells = block.cells ?? [];\n\n const rowsOut: TableRow[] = [];\n for (let r = 0; r < rows; r++) {\n const cellsOut: TableCell[] = [];\n for (let c = 0; c < cols; c++) {\n const cell = cells[r * cols + c];\n if (!cell) {\n cellsOut.push(emptyCell());\n continue;\n }\n if (cell.attrs?.covered) continue;\n cellsOut.push(makeCell(cell, images));\n }\n rowsOut.push(new TableRow({ children: cellsOut }));\n }\n\n // Validate the RAW array against `cols` — filtering invalid entries first\n // (e.g. dropping a negative width) would silently shift the remaining\n // widths onto the wrong columns while still passing a length check.\n const rawColWidths = block.attrs.colWidths;\n const isValidColWidths =\n Array.isArray(rawColWidths) &&\n cols > 0 &&\n rawColWidths.length === cols &&\n rawColWidths.every((w): w is number => typeof w === \"number\" && w > 0);\n const columnWidths = isValidColWidths\n ? rawColWidths.map((px) => convertMillimetersToTwip(pxToMm(px)))\n : undefined;\n\n return new Table({\n rows: rowsOut,\n borders: docxTableBorders(block.attrs.borderPreset, block.attrs.borderColor),\n ...(columnWidths\n ? {\n columnWidths,\n // Fix the layout so Word honors the column widths verbatim instead\n // of autofitting to content (the OOXML default when `tblLayout` is\n // absent, which would make `columnWidths` a mere hint).\n layout: TableLayoutType.FIXED,\n width: { size: columnWidths.reduce((a, b) => a + b, 0), type: WidthType.DXA },\n }\n : { width: { size: 100, type: WidthType.PERCENTAGE } }),\n });\n}\n\n/**\n * Traduz o preset para `w:tblBorders`. Lado desligado = `BorderStyle.NONE`.\n *\n * A tabela-verdade sai direto de `cellBorderColors`: o que aquele helper liga em\n * TODA célula vira o par externo MAIS o interno correspondente. Ex.: em\n * `vertical`, toda célula tem left/right ligados — logo as laterais externas\n * (left/right) E as internas (insideV) ficam ligadas, e topo/base\n * (top/bottom/insideH) desligados.\n *\n * A tabela é a especificação; a função sai dela, não o contrário.\n */\nfunction docxTableBorders(preset: TableBorderPreset | undefined, color?: string) {\n // Cor inválida ou ausente cai no padrão: `cssColorToDocxHex` devolve undefined\n // para o que não souber converter.\n const hex = cssColorToDocxHex(color) ?? \"CBD5E1\";\n const on = { style: BorderStyle.SINGLE, size: 6, color: hex };\n const off = { style: BorderStyle.NONE, size: 0, color: \"auto\" };\n const s = (visivel: boolean) => (visivel ? on : off);\n\n // [top/bottom, left/right, insideH, insideV]\n const TRUTH: Record<TableBorderPreset, [boolean, boolean, boolean, boolean]> = {\n all: [true, true, true, true],\n outer: [true, true, false, false],\n horizontal: [true, false, true, false],\n vertical: [false, true, false, true],\n none: [false, false, false, false],\n };\n const [tb, lr, iH, iV] = TRUTH[preset ?? \"all\"];\n return {\n top: s(tb),\n bottom: s(tb),\n left: s(lr),\n right: s(lr),\n insideHorizontal: s(iH),\n insideVertical: s(iV),\n };\n}\n\nfunction makeCell(cell: SerializedCell, images: Map<string, ResolvedImage | null>): TableCell {\n const span = cell.attrs?.colspan && cell.attrs.colspan > 1 ? cell.attrs.colspan : 1;\n const rowSpan = cell.attrs?.rowspan && cell.attrs.rowspan > 1 ? cell.attrs.rowspan : 1;\n const fill = cssColorToDocxHex(cell.attrs?.bgColor);\n return new TableCell({\n columnSpan: span,\n rowSpan,\n verticalAlign: VerticalAlign.TOP,\n shading: fill ? { type: ShadingType.CLEAR, color: \"auto\", fill } : undefined,\n children: [\n new Paragraph({\n alignment: alignFor(cell.attrs?.align),\n children: deltaToRuns(cell.delta, ARIAL, images),\n }),\n ],\n });\n}\n\nfunction emptyCell(): TableCell {\n return new TableCell({ children: [new Paragraph(\"\")] });\n}\n\n// ---------- inline ----------\n\ninterface RunDefaults {\n bold?: boolean;\n italics?: boolean;\n font?: string;\n size?: number;\n}\n\nfunction deltaToRuns(\n delta: DeltaOp[],\n defaults: RunDefaults = {},\n images: Map<string, ResolvedImage | null>,\n): Array<TextRun | ImageRun> {\n if (delta.length === 0) return [new TextRun(\"\")];\n const out: Array<TextRun | ImageRun> = [];\n for (const op of delta) {\n if (typeof op.insert === \"string\") {\n if (op.insert.length === 0) continue;\n out.push(makeTextRun(op.insert, op.attributes, defaults));\n } else if (isImageEmbed(op.insert)) {\n const embed = op.insert;\n const img = makeImageRun(embed, images);\n if (img) out.push(img);\n // Captions are emitted as italic-smaller text on a new line right after\n // the image. Word-style \"Caption\" paragraph would need a paragraph\n // break, which we can't do mid-delta — visually correct but loses the\n // semantic \"Caption\" style.\n if (embed.caption && embed.caption.length > 0) {\n out.push(\n new TextRun({\n text: embed.caption,\n italics: true,\n size: 18, // 9pt — typical caption size\n break: 1,\n }),\n );\n }\n }\n }\n if (out.length === 0) out.push(new TextRun(\"\"));\n return out;\n}\n\n/**\n * Props de um `TextRun` a partir das marks. Fica numa função só porque\n * `makeTextRun` tem dois caminhos (linha única e multi-linha) que antes\n * duplicavam esta lista inteira — uma mark acrescentada em apenas um dos dois\n * se perdia silenciosamente em texto com quebra de linha.\n *\n * `highlight` sai como `w:shd` e NÃO como `w:highlight`: este último só aceita\n * ~15 valores nomeados e não sobreviveria a uma cor arbitrária do picker.\n */\nfunction textRunProps(text: string, m: MarkAttrs, defaults: RunDefaults) {\n const fill = cssColorToDocxHex(m.highlight);\n return {\n text,\n bold: m.bold || defaults.bold,\n italics: m.italic || defaults.italics,\n underline: m.underline ? { type: UnderlineType.SINGLE } : undefined,\n strike: m.strike,\n color: cssColorToDocxHex(m.color),\n font: m.fontFamily ?? defaults.font,\n size: parseFontSizeToHalfPoints(m.fontSize) ?? defaults.size,\n shading: fill ? { type: ShadingType.CLEAR, color: \"auto\", fill } : undefined,\n };\n}\n\nfunction makeTextRun(\n text: string,\n marks: MarkAttrs | undefined,\n defaults: RunDefaults,\n): TextRun {\n const m = marks ?? {};\n // TextRun reads newlines via `break`; convert \\n into break runs.\n const segments = text.split(\"\\n\");\n if (segments.length === 1) {\n return new TextRun(textRunProps(text, m, defaults));\n }\n // Multi-line: rejoin via TextRun children — but TextRun expects a single text\n // string. Approximate with non-printing line breaks: produce a sequence of\n // TextRuns separated by `new TextRun({ break: 1 })` packed into the parent.\n // Simpler: collapse to a single TextRun with the string, treating \\n as a\n // soft-break placeholder. Word renders \\n inside a w:t as a literal space,\n // so we replace with a small symbol-friendly fallback.\n return new TextRun(textRunProps(text.replace(/\\n/g, \" \"), m, defaults));\n}\n\nfunction makeImageRun(\n embed: ImageEmbed,\n images: Map<string, ResolvedImage | null>,\n): ImageRun | null {\n const resolved = images.get(embed.src);\n if (!resolved) return null;\n return new ImageRun({\n data: resolved.data,\n type: resolved.type,\n transformation: {\n width: Math.max(1, Math.round(embed.width)),\n height: Math.max(1, Math.round(embed.height)),\n },\n } as ConstructorParameters<typeof ImageRun>[0]);\n}\n\ninterface DecodedImage {\n bytes: Uint8Array;\n kind: \"png\" | \"jpg\" | \"gif\" | \"bmp\" | \"svg\";\n}\n\nfunction decodeDataUrl(src: string): DecodedImage | null {\n const m = /^data:image\\/(png|jpe?g|gif|bmp|svg\\+xml);base64,(.+)$/i.exec(src);\n if (!m) return null;\n const fmt = m[1].toLowerCase();\n const kind: DecodedImage[\"kind\"] =\n fmt === \"jpeg\" || fmt === \"jpg\"\n ? \"jpg\"\n : fmt === \"svg+xml\"\n ? \"svg\"\n : (fmt as \"png\" | \"gif\" | \"bmp\");\n const base64 = m[2];\n const bytes = base64ToBytes(base64);\n return { bytes, kind };\n}\n\n/**\n * Default `resolveImage`: decode data URLs locally, fetch http(s) URLs, and\n * return null for anything else (caller counts it in `skippedImages`).\n */\nasync function defaultResolveImage(src: string): Promise<ResolvedImage | null> {\n const decoded = decodeDataUrl(src);\n if (decoded) return { data: decoded.bytes, type: decoded.kind };\n if (/^https?:\\/\\//i.test(src) && typeof fetch === \"function\") {\n try {\n const res = await fetch(src);\n if (!res.ok) return null;\n const ct = (res.headers.get(\"content-type\") ?? \"\").toLowerCase();\n const matchedType: ResolvedImage[\"type\"] | null = ct.includes(\"png\")\n ? \"png\"\n : ct.includes(\"jpeg\") || ct.includes(\"jpg\")\n ? \"jpg\"\n : ct.includes(\"gif\")\n ? \"gif\"\n : ct.includes(\"bmp\")\n ? \"bmp\"\n : ct.includes(\"svg\")\n ? \"svg\"\n : null;\n // Unknown content-type (e.g. image/webp) with no recognizable extension\n // in the URL: skip rather than mislabeling bytes as PNG (would produce\n // a broken image in Word — contract is \"failure to resolve → skip\").\n const type = matchedType ?? typeFromExtension(src);\n if (!type) return null;\n return { data: new Uint8Array(await res.arrayBuffer()), type };\n } catch {\n return null;\n }\n }\n return null;\n}\n\nfunction typeFromExtension(src: string): ResolvedImage[\"type\"] | null {\n const m = /\\.(png|jpe?g|gif|bmp|svg)(\\?|#|$)/i.exec(src);\n if (!m) return null;\n const ext = m[1].toLowerCase();\n return ext === \"jpeg\" || ext === \"jpg\" ? \"jpg\" : (ext as ResolvedImage[\"type\"]);\n}\n\n/**\n * Async pre-pass: collect every image `src` referenced by the document\n * (block deltas and table cell deltas), resolve them in parallel via\n * `resolve`, and return a lookup map plus the count of embeds that failed to\n * resolve. The rest of the build pipeline stays synchronous and reads from\n * this map.\n */\nasync function resolveAllImages(\n doc: SerializedDocument,\n resolve: (src: string) => Promise<ResolvedImage | null>,\n): Promise<{ images: Map<string, ResolvedImage | null>; skipped: number }> {\n const srcs = new Set<string>();\n const collect = (delta: DeltaOp[]) => {\n for (const op of delta) if (isImageEmbed(op.insert)) srcs.add(op.insert.src);\n };\n for (const block of doc.blocks) {\n collect(block.delta);\n for (const cell of block.cells ?? []) collect(cell.delta);\n }\n const images = new Map<string, ResolvedImage | null>();\n await Promise.all(\n [...srcs].map(async (src) => {\n let resolved: ResolvedImage | null = null;\n try {\n resolved = await resolve(src);\n } catch {\n resolved = null;\n }\n // docx's ImageRun requires a `fallback` for type \"svg\" (RegularImageOptions);\n // without it the constructor throws synchronously inside buildDocument,\n // which is outside this try/catch and would abort the whole export. Treat\n // svg as unresolved (skip) until we add fallback support.\n if (resolved?.type === \"svg\") resolved = null;\n images.set(src, resolved);\n }),\n );\n // skipped conta OCORRÊNCIAS de embed sem resolução (não srcs únicos).\n let skipped = 0;\n const count = (delta: DeltaOp[]) => {\n for (const op of delta)\n if (isImageEmbed(op.insert) && !images.get(op.insert.src)) skipped++;\n };\n for (const block of doc.blocks) {\n count(block.delta);\n for (const cell of block.cells ?? []) count(cell.delta);\n }\n return { images, skipped };\n}\n\nfunction base64ToBytes(b64: string): Uint8Array {\n if (typeof atob === \"function\") {\n const bin = atob(b64);\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\n return out;\n }\n // Node fallback.\n return new Uint8Array(Buffer.from(b64, \"base64\"));\n}\n\n// ---------- attribute mapping ----------\n\nconst HEADING_LEVELS = [\n HeadingLevel.HEADING_1,\n HeadingLevel.HEADING_2,\n HeadingLevel.HEADING_3,\n HeadingLevel.HEADING_4,\n HeadingLevel.HEADING_5,\n HeadingLevel.HEADING_6,\n];\n\nfunction clampHeadingLevel(l: unknown): 1 | 2 | 3 | 4 | 5 | 6 {\n if (typeof l !== \"number\") return 1;\n const n = Math.trunc(l);\n if (n < 1) return 1;\n if (n > 6) return 6;\n return n as 1 | 2 | 3 | 4 | 5 | 6;\n}\n\nfunction clampListLevel(l: unknown): number {\n if (typeof l !== \"number\" || !Number.isFinite(l)) return 0;\n return Math.max(0, Math.min(5, Math.trunc(l)));\n}\n\nfunction alignFor(a: AlignValue | undefined): (typeof AlignmentType)[keyof typeof AlignmentType] | undefined {\n switch (a) {\n case \"left\":\n return AlignmentType.LEFT;\n case \"center\":\n return AlignmentType.CENTER;\n case \"right\":\n return AlignmentType.RIGHT;\n case \"justify\":\n return AlignmentType.JUSTIFIED;\n default:\n return undefined;\n }\n}\n\nfunction cssColorToDocxHex(color: string | undefined): string | undefined {\n if (!color) return undefined;\n // docx expects RRGGBB without leading '#'.\n const c = color.trim();\n if (/^#[0-9a-f]{6}$/i.test(c)) return c.slice(1).toUpperCase();\n if (/^#[0-9a-f]{3}$/i.test(c)) {\n // expand short hex\n return c\n .slice(1)\n .split(\"\")\n .map((d) => d + d)\n .join(\"\")\n .toUpperCase();\n }\n const rgb = /^rgb\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)/i.exec(c);\n if (rgb) {\n const r = Number(rgb[1]);\n const g = Number(rgb[2]);\n const b = Number(rgb[3]);\n return [r, g, b].map((n) => Math.max(0, Math.min(255, n)).toString(16).padStart(2, \"0\")).join(\"\").toUpperCase();\n }\n // Named colors / other forms — let docx fall back to default.\n return undefined;\n}\n\n/**\n * docx sizes are in half-points (24 = 12pt). Parse common CSS sizes.\n * Returns `undefined` when not parseable so callers can pick a default.\n */\nfunction parseFontSizeToHalfPoints(size: string | undefined): number | undefined {\n if (!size) return undefined;\n const s = size.trim();\n const m = /^(-?\\d*\\.?\\d+)\\s*(pt|px|em|rem)?$/i.exec(s);\n if (!m) return undefined;\n const n = Number(m[1]);\n if (!Number.isFinite(n) || n <= 0) return undefined;\n const unit = (m[2] ?? \"pt\").toLowerCase();\n const pt =\n unit === \"pt\"\n ? n\n : unit === \"px\"\n ? n * 0.75 // CSS px → pt at 96dpi\n : n * 12;\n return Math.round(pt * 2);\n}\n\n// ---------- list numbering definitions ----------\n\nfunction buildBulletLevels(): Array<{\n level: number;\n format: (typeof LevelFormat)[keyof typeof LevelFormat];\n text: string;\n alignment: (typeof AlignmentType)[keyof typeof AlignmentType];\n style?: { paragraph?: { indent?: { left: number; hanging: number } } };\n}> {\n const symbols = [\"•\", \"◦\", \"▪\", \"•\", \"◦\", \"▪\"];\n return symbols.map((sym, i) => ({\n level: i,\n format: LevelFormat.BULLET,\n text: sym,\n alignment: AlignmentType.LEFT,\n style: {\n paragraph: { indent: { left: 360 + i * 360, hanging: 260 } },\n },\n }));\n}\n\nfunction buildOrderedLevels(): Array<{\n level: number;\n format: (typeof LevelFormat)[keyof typeof LevelFormat];\n text: string;\n alignment: (typeof AlignmentType)[keyof typeof AlignmentType];\n style?: { paragraph?: { indent?: { left: number; hanging: number } } };\n}> {\n const formats = [\n LevelFormat.DECIMAL,\n LevelFormat.LOWER_LETTER,\n LevelFormat.LOWER_ROMAN,\n LevelFormat.DECIMAL,\n LevelFormat.LOWER_LETTER,\n LevelFormat.LOWER_ROMAN,\n ];\n return formats.map((format, i) => ({\n level: i,\n format,\n text: `%${i + 1}.`,\n alignment: AlignmentType.LEFT,\n style: {\n paragraph: { indent: { left: 360 + i * 360, hanging: 260 } },\n },\n }));\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/docx.ts"],"sourcesContent":["export { documentToDocxBlob, documentToDocxBuffer } from \"./docx\";\nexport type { DocumentToDocxOptions, ResolvedImage } from \"./docx\";\n","import type {\n AlignValue,\n DeltaOp,\n ImageEmbed,\n LegacySerializedDocument,\n ListKind,\n MarkAttrs,\n SerializedBlock,\n SerializedCell,\n SerializedDocument,\n TableBorderPreset,\n} from \"@sofereditor/core\";\nimport {\n DEFAULT_PAGE_SETTINGS,\n isImageEmbed,\n isLegacySerializedDocument,\n normalizarLarguras,\n pxToMm,\n type PageSettings,\n} from \"@sofereditor/core\";\nimport {\n AlignmentType,\n BorderStyle,\n Document,\n HeadingLevel,\n HeightRule,\n ImageRun,\n LevelFormat,\n LineRuleType,\n Packer,\n Paragraph,\n PageOrientation,\n ShadingType,\n Table,\n TableCell,\n TableLayoutType,\n TableRow,\n TextRun,\n UnderlineType,\n VerticalAlign,\n WidthType,\n convertMillimetersToTwip,\n} from \"docx\";\n\nconst BULLET_REF = \"ed-bullet\";\nconst ORDERED_REF = \"ed-ordered\";\n\nexport interface ResolvedImage {\n data: Uint8Array;\n type: \"png\" | \"jpg\" | \"gif\" | \"bmp\" | \"svg\";\n /**\n * Só presente quando `type === \"svg\"`: o fallback raster já decodificado,\n * exigido pelo `ImageRun` do docx para `type: \"svg\"`. Preenchido\n * internamente por `resolveAllImages` a partir do `svgFallback` do embed —\n * nunca por um `resolveImage` customizado. Fica aqui (no valor resolvido\n * por `src`, não num mapa paralelo por embed) porque é exatamente isso que\n * \"resolvido\" significa para um svg: dois embeds com o mesmo `src` — um\n * com `svgFallback`, outro sem — compartilham o mesmo `src` e portanto o\n * mesmo SVG; o fallback de qualquer um dos dois serve para ambos.\n */\n svgFallback?: { data: Uint8Array; type: Exclude<ResolvedImage[\"type\"], \"svg\"> };\n}\n\nexport interface DocumentToDocxOptions {\n /** Document title; embedded in core properties. */\n title?: string;\n /** Author for core properties. */\n creator?: string;\n /**\n * Resolve um `src` de imagem para bytes. Default: data URLs (decodificadas\n * localmente) e http(s) via fetch. Retornar null pula a imagem (contada em\n * `skippedImages`) sem abortar o export.\n */\n resolveImage?: (src: string) => Promise<ResolvedImage | null>;\n}\n\n/**\n * Build a docx `Document` from a `SerializedDocument`. Output is a Blob you can\n * download with `downloadBlob` from `@sofereditor/export-pdf`.\n *\n * Mappings:\n * - paragraph / heading / blockquote / codeBlock → Paragraph (with `heading`,\n * shading, monospace font for code)\n * - listItem → Paragraph with `numbering: { reference, level }`\n * - table → docx `Table`. `rowspan`/`colspan` map to TableCell's `rowSpan`/\n * `columnSpan`; \"covered\" cells are skipped (docx infers cover from spans)\n * - inline marks → TextRun props (bold, italics, underline, strike, color,\n * font, size in half-points)\n * - image embeds → ImageRun with bytes resolved via `resolveImage` (default:\n * data URLs decoded locally, http(s) fetched; unresolved images are\n * skipped and counted in `skippedImages` instead of aborting the export)\n */\nexport async function documentToDocxBlob(\n doc: SerializedDocument | LegacySerializedDocument,\n options: DocumentToDocxOptions = {},\n): Promise<{ blob: Blob; skippedImages: number }> {\n const normalized = normalize(doc);\n const { images, skipped } = await resolveAllImages(\n normalized,\n options.resolveImage ?? defaultResolveImage,\n );\n const built = buildDocument(normalized, options, images);\n return { blob: await Packer.toBlob(built), skippedImages: skipped };\n}\n\n/** Same as `documentToDocxBlob` but returns a Uint8Array (useful in Node/tests). */\nexport async function documentToDocxBuffer(\n doc: SerializedDocument | LegacySerializedDocument,\n options: DocumentToDocxOptions = {},\n): Promise<{ buffer: Uint8Array; skippedImages: number }> {\n const normalized = normalize(doc);\n const { images, skipped } = await resolveAllImages(\n normalized,\n options.resolveImage ?? defaultResolveImage,\n );\n const built = buildDocument(normalized, options, images);\n const buf = await Packer.toBuffer(built);\n // `Packer.toBuffer` returns a Node Buffer at runtime — coerce for consumers.\n return {\n buffer: buf instanceof Uint8Array ? buf : new Uint8Array(buf),\n skippedImages: skipped,\n };\n}\n\nfunction normalize(doc: SerializedDocument | LegacySerializedDocument): SerializedDocument {\n return isLegacySerializedDocument(doc) ? { blocks: doc } : doc;\n}\n\nfunction buildDocument(\n doc: SerializedDocument,\n options: DocumentToDocxOptions,\n images: Map<string, ResolvedImage | null>,\n): Document {\n const settings = doc.pageSettings ?? DEFAULT_PAGE_SETTINGS;\n const children = blocksToDocxChildren(doc, images, settings);\n return new Document({\n creator: options.creator,\n title: options.title,\n numbering: {\n config: [\n {\n reference: BULLET_REF,\n levels: buildBulletLevels(),\n },\n {\n reference: ORDERED_REF,\n levels: buildOrderedLevels(),\n },\n ],\n },\n sections: [\n {\n properties: sectionPropertiesFor(settings),\n children,\n },\n ],\n });\n}\n\nfunction sectionPropertiesFor(settings: PageSettings) {\n return {\n page: {\n size: {\n width: convertMillimetersToTwip(pxToMm(settings.width)),\n height: convertMillimetersToTwip(pxToMm(settings.height)),\n orientation: PageOrientation.PORTRAIT,\n },\n margin: {\n top: convertMillimetersToTwip(pxToMm(settings.marginTop)),\n bottom: convertMillimetersToTwip(pxToMm(settings.marginBottom)),\n left: convertMillimetersToTwip(pxToMm(settings.marginLeft)),\n right: convertMillimetersToTwip(pxToMm(settings.marginRight)),\n },\n },\n };\n}\n\nfunction blocksToDocxChildren(\n doc: SerializedDocument,\n images: Map<string, ResolvedImage | null>,\n settings: PageSettings,\n): Array<Paragraph | Table> {\n const out: Array<Paragraph | Table> = [];\n const blocks = doc.blocks;\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i];\n switch (block.type) {\n case \"paragraph\":\n out.push(makeParagraph(block, images));\n break;\n case \"heading\":\n out.push(makeHeading(block, images));\n break;\n case \"blockquote\":\n out.push(makeBlockquote(block, images));\n break;\n case \"codeBlock\":\n out.push(makeCodeBlock(block, images));\n break;\n case \"listItem\":\n out.push(makeListItem(block, images));\n break;\n case \"table\":\n out.push(makeTable(block, images, settings));\n break;\n default:\n out.push(makeParagraph(block, images));\n }\n }\n return out;\n}\n\n// ---------- block builders ----------\n\n// School standard: Arial for all body text. Code blocks override with\n// Consolas (monospace is more legible for code). Italics on blockquote is\n// kept as a stylistic default.\nconst ARIAL: RunDefaults = { font: \"Arial\" };\n\nfunction makeParagraph(\n block: SerializedBlock,\n images: Map<string, ResolvedImage | null>,\n): Paragraph {\n return new Paragraph({\n alignment: alignFor(block.attrs.align),\n bidirectional: block.attrs.dir === \"rtl\" ? true : undefined,\n ...answerLineProps(block.attrs),\n children: deltaToRuns(block.delta, ARIAL, images),\n });\n}\n\n/**\n * Linha de resposta → borda inferior de parágrafo (`w:pBdr`) + entrelinha.\n * É como um documento profissional desenha uma pauta: a régua acompanha a\n * margem automaticamente, ao contrário de uma fileira de underlines.\n *\n * 240 twips = uma linha simples no OOXML.\n */\nfunction answerLineProps(attrs: SerializedBlock[\"attrs\"]) {\n if (attrs.answerLine !== true) return {};\n const spacing = attrs.answerLineSpacing ?? 1;\n return {\n border: {\n bottom: { style: BorderStyle.SINGLE, size: 6, color: \"000000\", space: 1 },\n },\n spacing: { line: Math.round(240 * spacing), lineRule: LineRuleType.AUTO },\n };\n}\n\nfunction makeHeading(\n block: SerializedBlock,\n images: Map<string, ResolvedImage | null>,\n): Paragraph {\n const level = clampHeadingLevel(block.attrs.level);\n return new Paragraph({\n heading: HEADING_LEVELS[level - 1],\n alignment: alignFor(block.attrs.align),\n children: deltaToRuns(block.delta, ARIAL, images),\n });\n}\n\nfunction makeBlockquote(\n block: SerializedBlock,\n images: Map<string, ResolvedImage | null>,\n): Paragraph {\n return new Paragraph({\n alignment: alignFor(block.attrs.align),\n indent: { left: 480 }, // ~0.25\"\n border: {\n left: { color: \"CBD5E1\", space: 12, style: BorderStyle.SINGLE, size: 12 },\n },\n children: deltaToRuns(block.delta, { ...ARIAL, italics: true }, images),\n });\n}\n\nfunction makeCodeBlock(\n block: SerializedBlock,\n images: Map<string, ResolvedImage | null>,\n): Paragraph {\n return new Paragraph({\n spacing: { before: 100, after: 100 },\n shading: { type: ShadingType.CLEAR, color: \"auto\", fill: \"F1F5F9\" },\n children: deltaToRuns(block.delta, { font: \"Consolas\", size: 20 }, images),\n });\n}\n\nfunction makeListItem(\n block: SerializedBlock,\n images: Map<string, ResolvedImage | null>,\n): Paragraph {\n const kind: ListKind = block.attrs.listKind === \"ordered\" ? \"ordered\" : \"bullet\";\n const reference = kind === \"ordered\" ? ORDERED_REF : BULLET_REF;\n const level = clampListLevel(block.attrs.listLevel);\n return new Paragraph({\n numbering: { reference, level },\n alignment: alignFor(block.attrs.align),\n children: deltaToRuns(block.delta, ARIAL, images),\n });\n}\n\nfunction makeTable(\n block: SerializedBlock,\n images: Map<string, ResolvedImage | null>,\n settings: PageSettings,\n): Table {\n const rows = typeof block.attrs.rows === \"number\" ? block.attrs.rows : 0;\n const cols = typeof block.attrs.cols === \"number\" ? block.attrs.cols : 0;\n const cells = block.cells ?? [];\n const alturas = block.attrs.rowHeights;\n\n const rowsOut: TableRow[] = [];\n for (let r = 0; r < rows; r++) {\n const cellsOut: TableCell[] = [];\n for (let c = 0; c < cols; c++) {\n const cell = cells[r * cols + c];\n if (!cell) {\n cellsOut.push(emptyCell());\n continue;\n }\n if (cell.attrs?.covered) continue;\n cellsOut.push(makeCell(cell, images));\n }\n // `atLeast` e NÃO `exact`: é a mesma semântica de mínimo do editor. Com\n // `exact` o Word cortaria o conteúdo, e texto sumindo da prova é o pior\n // desfecho possível — pior que uma linha mais alta do que o pedido.\n // `Math.max(0, h)`: um documento antigo/malformado poderia trazer uma\n // entrada negativa em `rowHeights`; sem o piso, isso viraria um\n // `w:val` negativo no XML, que o Word rejeita.\n const raw = Array.isArray(alturas) && alturas.length === rows ? alturas[r] : undefined;\n const h = typeof raw === \"number\" && isFinite(raw) ? Math.max(0, raw) : undefined;\n rowsOut.push(\n new TableRow({\n children: cellsOut,\n ...(h != null\n ? { height: { value: convertMillimetersToTwip(pxToMm(h)), rule: HeightRule.ATLEAST } }\n : {}),\n }),\n );\n }\n\n // cols<=0 é uma tabela malformada (rows/cols ausentes no bloco) — sem coluna\n // nenhuma para distribuir largura, cai no fallback percentual histórico em\n // vez de produzir um `<w:gridCol w:w=\"0\"/>`.\n if (cols <= 0) {\n return new Table({\n rows: rowsOut,\n borders: docxTableBorders(block.attrs.borderPreset, block.attrs.borderColor),\n width: { size: 100, type: WidthType.PERCENTAGE },\n });\n }\n\n // Proporção contra a largura útil REAL da página — é isto que faz a tabela\n // no Word ter a mesma largura do editor. Antes convertia a soma dos px do\n // modelo (513 px numa tabela que o professor via com 600). `pageSettings`\n // vem do documento (A4/Carta/Ofício/custom) e nunca de uma constante\n // cravada, senão qualquer tamanho de página que não A4 quebraria calado.\n const larguraUtilTwips = convertMillimetersToTwip(\n pxToMm(settings.width - settings.marginLeft - settings.marginRight),\n );\n const tabelaTwips = Math.round(larguraUtilTwips * ((block.attrs.tableWidth ?? 100) / 100));\n const pct = normalizarLarguras(block.attrs.colWidths, cols);\n const columnWidths = pct.map((p) => Math.round(tabelaTwips * (p / 100)));\n\n return new Table({\n rows: rowsOut,\n borders: docxTableBorders(block.attrs.borderPreset, block.attrs.borderColor),\n columnWidths,\n // O `layout: FIXED` permanece pelo mesmo motivo de antes: sem ele o Word\n // autoajusta ao conteúdo e trata `columnWidths` como mero palpite.\n layout: TableLayoutType.FIXED,\n width: { size: columnWidths.reduce((a, b) => a + b, 0), type: WidthType.DXA },\n });\n}\n\n/**\n * Traduz o preset para `w:tblBorders`. Lado desligado = `BorderStyle.NONE`.\n *\n * A tabela-verdade sai direto de `cellBorderColors`: o que aquele helper liga em\n * TODA célula vira o par externo MAIS o interno correspondente. Ex.: em\n * `vertical`, toda célula tem left/right ligados — logo as laterais externas\n * (left/right) E as internas (insideV) ficam ligadas, e topo/base\n * (top/bottom/insideH) desligados.\n *\n * A tabela é a especificação; a função sai dela, não o contrário.\n */\nfunction docxTableBorders(preset: TableBorderPreset | undefined, color?: string) {\n // Cor inválida ou ausente cai no padrão: `cssColorToDocxHex` devolve undefined\n // para o que não souber converter.\n const hex = cssColorToDocxHex(color) ?? \"CBD5E1\";\n const on = { style: BorderStyle.SINGLE, size: 6, color: hex };\n const off = { style: BorderStyle.NONE, size: 0, color: \"auto\" };\n const s = (visivel: boolean) => (visivel ? on : off);\n\n // [top/bottom, left/right, insideH, insideV]\n const TRUTH: Record<TableBorderPreset, [boolean, boolean, boolean, boolean]> = {\n all: [true, true, true, true],\n outer: [true, true, false, false],\n horizontal: [true, false, true, false],\n vertical: [false, true, false, true],\n none: [false, false, false, false],\n };\n const [tb, lr, iH, iV] = TRUTH[preset ?? \"all\"];\n return {\n top: s(tb),\n bottom: s(tb),\n left: s(lr),\n right: s(lr),\n insideHorizontal: s(iH),\n insideVertical: s(iV),\n };\n}\n\nfunction makeCell(cell: SerializedCell, images: Map<string, ResolvedImage | null>): TableCell {\n const span = cell.attrs?.colspan && cell.attrs.colspan > 1 ? cell.attrs.colspan : 1;\n const rowSpan = cell.attrs?.rowspan && cell.attrs.rowspan > 1 ? cell.attrs.rowspan : 1;\n const fill = cssColorToDocxHex(cell.attrs?.bgColor);\n return new TableCell({\n columnSpan: span,\n rowSpan,\n verticalAlign: VerticalAlign.TOP,\n shading: fill ? { type: ShadingType.CLEAR, color: \"auto\", fill } : undefined,\n children: [\n new Paragraph({\n alignment: alignFor(cell.attrs?.align),\n children: deltaToRuns(cell.delta, ARIAL, images),\n }),\n ],\n });\n}\n\nfunction emptyCell(): TableCell {\n return new TableCell({ children: [new Paragraph(\"\")] });\n}\n\n// ---------- inline ----------\n\ninterface RunDefaults {\n bold?: boolean;\n italics?: boolean;\n font?: string;\n size?: number;\n}\n\nfunction deltaToRuns(\n delta: DeltaOp[],\n defaults: RunDefaults = {},\n images: Map<string, ResolvedImage | null>,\n): Array<TextRun | ImageRun> {\n if (delta.length === 0) return [new TextRun(\"\")];\n const out: Array<TextRun | ImageRun> = [];\n for (const op of delta) {\n if (typeof op.insert === \"string\") {\n if (op.insert.length === 0) continue;\n out.push(makeTextRun(op.insert, op.attributes, defaults));\n } else if (isImageEmbed(op.insert)) {\n const embed = op.insert;\n const img = makeImageRun(embed, images);\n if (img) out.push(img);\n // Captions are emitted as italic-smaller text on a new line right after\n // the image. Word-style \"Caption\" paragraph would need a paragraph\n // break, which we can't do mid-delta — visually correct but loses the\n // semantic \"Caption\" style.\n if (embed.caption && embed.caption.length > 0) {\n out.push(\n new TextRun({\n text: embed.caption,\n italics: true,\n size: 18, // 9pt — typical caption size\n break: 1,\n }),\n );\n }\n }\n }\n if (out.length === 0) out.push(new TextRun(\"\"));\n return out;\n}\n\n/**\n * Props de um `TextRun` a partir das marks. Fica numa função só porque\n * `makeTextRun` tem dois caminhos (linha única e multi-linha) que antes\n * duplicavam esta lista inteira — uma mark acrescentada em apenas um dos dois\n * se perdia silenciosamente em texto com quebra de linha.\n *\n * `highlight` sai como `w:shd` e NÃO como `w:highlight`: este último só aceita\n * ~15 valores nomeados e não sobreviveria a uma cor arbitrária do picker.\n */\nfunction textRunProps(text: string, m: MarkAttrs, defaults: RunDefaults) {\n const fill = cssColorToDocxHex(m.highlight);\n return {\n text,\n bold: m.bold || defaults.bold,\n italics: m.italic || defaults.italics,\n underline: m.underline ? { type: UnderlineType.SINGLE } : undefined,\n strike: m.strike,\n color: cssColorToDocxHex(m.color),\n font: m.fontFamily ?? defaults.font,\n size: parseFontSizeToHalfPoints(m.fontSize) ?? defaults.size,\n shading: fill ? { type: ShadingType.CLEAR, color: \"auto\", fill } : undefined,\n };\n}\n\nfunction makeTextRun(\n text: string,\n marks: MarkAttrs | undefined,\n defaults: RunDefaults,\n): TextRun {\n const m = marks ?? {};\n // TextRun reads newlines via `break`; convert \\n into break runs.\n const segments = text.split(\"\\n\");\n if (segments.length === 1) {\n return new TextRun(textRunProps(text, m, defaults));\n }\n // Multi-line: rejoin via TextRun children — but TextRun expects a single text\n // string. Approximate with non-printing line breaks: produce a sequence of\n // TextRuns separated by `new TextRun({ break: 1 })` packed into the parent.\n // Simpler: collapse to a single TextRun with the string, treating \\n as a\n // soft-break placeholder. Word renders \\n inside a w:t as a literal space,\n // so we replace with a small symbol-friendly fallback.\n return new TextRun(textRunProps(text.replace(/\\n/g, \" \"), m, defaults));\n}\n\nfunction makeImageRun(\n embed: ImageEmbed,\n images: Map<string, ResolvedImage | null>,\n): ImageRun | null {\n const resolved = images.get(embed.src);\n if (!resolved) return null;\n if (resolved.type === \"svg\") {\n // O fallback vem do `resolved` (por SRC), NÃO de `embed.svgFallback` (por\n // OCORRÊNCIA). Dois embeds com o mesmo src, um com svgFallback e outro\n // sem — caso real: uma prova salva antes do campo existir, com a mesma\n // fórmula inserida de novo depois — têm que resolver para o MESMO\n // ImageRun. Ler `embed.svgFallback` aqui faria a ocorrência sem fallback\n // sumir do documento sem entrar em `skippedImages`, porque\n // `resolveAllImages` já decidiu \"não pulado\" (o `src` tem fallback em\n // ALGUMA ocorrência) — o `null` devolvido aqui não seria contado.\n // `resolveAllImages` só deixa `resolved.type === \"svg\"` quando já\n // decodificou um fallback; o guarda existe porque o campo é opcional.\n if (!resolved.svgFallback) return null;\n return new ImageRun({\n type: \"svg\",\n data: resolved.data,\n fallback: { type: resolved.svgFallback.type, data: resolved.svgFallback.data },\n transformation: {\n width: Math.max(1, Math.round(embed.width)),\n height: Math.max(1, Math.round(embed.height)),\n },\n } as ConstructorParameters<typeof ImageRun>[0]);\n }\n return new ImageRun({\n data: resolved.data,\n type: resolved.type,\n transformation: {\n width: Math.max(1, Math.round(embed.width)),\n height: Math.max(1, Math.round(embed.height)),\n },\n } as ConstructorParameters<typeof ImageRun>[0]);\n}\n\ninterface DecodedImage {\n bytes: Uint8Array;\n kind: \"png\" | \"jpg\" | \"gif\" | \"bmp\" | \"svg\";\n}\n\nfunction decodeDataUrl(src: string): DecodedImage | null {\n const m = /^data:image\\/(png|jpe?g|gif|bmp|svg\\+xml);base64,(.+)$/i.exec(src);\n if (!m) return null;\n const fmt = m[1].toLowerCase();\n const kind: DecodedImage[\"kind\"] =\n fmt === \"jpeg\" || fmt === \"jpg\"\n ? \"jpg\"\n : fmt === \"svg+xml\"\n ? \"svg\"\n : (fmt as \"png\" | \"gif\" | \"bmp\");\n const base64 = m[2];\n const bytes = base64ToBytes(base64);\n return { bytes, kind };\n}\n\n/**\n * Default `resolveImage`: decode data URLs locally, fetch http(s) URLs, and\n * return null for anything else (caller counts it in `skippedImages`).\n */\nasync function defaultResolveImage(src: string): Promise<ResolvedImage | null> {\n const decoded = decodeDataUrl(src);\n if (decoded) return { data: decoded.bytes, type: decoded.kind };\n if (/^https?:\\/\\//i.test(src) && typeof fetch === \"function\") {\n try {\n const res = await fetch(src);\n if (!res.ok) return null;\n const ct = (res.headers.get(\"content-type\") ?? \"\").toLowerCase();\n const matchedType: ResolvedImage[\"type\"] | null = ct.includes(\"png\")\n ? \"png\"\n : ct.includes(\"jpeg\") || ct.includes(\"jpg\")\n ? \"jpg\"\n : ct.includes(\"gif\")\n ? \"gif\"\n : ct.includes(\"bmp\")\n ? \"bmp\"\n : ct.includes(\"svg\")\n ? \"svg\"\n : null;\n // Unknown content-type (e.g. image/webp) with no recognizable extension\n // in the URL: skip rather than mislabeling bytes as PNG (would produce\n // a broken image in Word — contract is \"failure to resolve → skip\").\n const type = matchedType ?? typeFromExtension(src);\n if (!type) return null;\n return { data: new Uint8Array(await res.arrayBuffer()), type };\n } catch {\n return null;\n }\n }\n return null;\n}\n\nfunction typeFromExtension(src: string): ResolvedImage[\"type\"] | null {\n const m = /\\.(png|jpe?g|gif|bmp|svg)(\\?|#|$)/i.exec(src);\n if (!m) return null;\n const ext = m[1].toLowerCase();\n return ext === \"jpeg\" || ext === \"jpg\" ? \"jpg\" : (ext as ResolvedImage[\"type\"]);\n}\n\n/**\n * Async pre-pass: collect every image `src` referenced by the document\n * (block deltas and table cell deltas), resolve them in parallel via\n * `resolve`, and return a lookup map plus the count of embeds that failed to\n * resolve. The rest of the build pipeline stays synchronous and reads from\n * this map.\n */\nasync function resolveAllImages(\n doc: SerializedDocument,\n resolve: (src: string) => Promise<ResolvedImage | null>,\n): Promise<{ images: Map<string, ResolvedImage | null>; skipped: number }> {\n const srcs = new Set<string>();\n // svgFallback é campo do EMBED e o mapa de resolução é por SRC. Colher no\n // mesmo passo evita um segundo percurso do documento. Dois embeds com o\n // mesmo src e fallbacks diferentes é caso que não existe na prática (o src\n // é o próprio conteúdo em data URL); o primeiro ganha.\n const fallbacks = new Map<string, string>();\n const collect = (delta: DeltaOp[]) => {\n for (const op of delta) {\n if (!isImageEmbed(op.insert)) continue;\n srcs.add(op.insert.src);\n const fb = op.insert.svgFallback;\n if (fb && !fallbacks.has(op.insert.src)) fallbacks.set(op.insert.src, fb);\n }\n };\n for (const block of doc.blocks) {\n collect(block.delta);\n for (const cell of block.cells ?? []) collect(cell.delta);\n }\n const images = new Map<string, ResolvedImage | null>();\n await Promise.all(\n [...srcs].map(async (src) => {\n let resolved: ResolvedImage | null = null;\n try {\n resolved = await resolve(src);\n } catch {\n resolved = null;\n }\n // docx's ImageRun requires a `fallback` for type \"svg\" (RegularImageOptions);\n // without it the constructor throws synchronously inside buildDocument,\n // which is outside this try/catch and would abort the whole export. SVG\n // deixa de ser descartado: o ImageRun aceita `type: \"svg\"` desde que\n // receba um `fallback` raster. Quem tem `svgFallback` passa; quem não\n // tem continua sendo pulado AQUI, para que `skipped` conte certo — não\n // inventamos um raster no servidor. O fallback é decodificado AQUI (uma\n // vez por src, não por embed) e guardado dentro do próprio\n // `ResolvedImage` — é isso que faz o \"primeiro ganha\" valer para toda\n // ocorrência do mesmo src, mesmo a que não trouxe `svgFallback`.\n if (resolved?.type === \"svg\") {\n const fb = fallbacks.get(src);\n const decodedFb = fb ? decodeDataUrl(fb) : null;\n // Um fallback com `kind === \"svg\"` não é fallback nenhum — é o\n // mesmo SVG de novo (`ImageRun({ type: \"svg\", fallback: { type:\n // \"svg\" } })` não tem sentido pro docx, que exige um raster aqui).\n // Na prática `fb` sempre vem de `svgToPngDataUrl` (sempre PNG), mas\n // `decodeDataUrl` é genérico; tratamos esse caso como \"sem\n // fallback válido\" em vez de deixar o tipo mentir.\n resolved =\n decodedFb && decodedFb.kind !== \"svg\"\n ? { ...resolved, svgFallback: { data: decodedFb.bytes, type: decodedFb.kind } }\n : null;\n }\n images.set(src, resolved);\n }),\n );\n // skipped conta OCORRÊNCIAS de embed sem resolução (não srcs únicos).\n let skipped = 0;\n const count = (delta: DeltaOp[]) => {\n for (const op of delta)\n if (isImageEmbed(op.insert) && !images.get(op.insert.src)) skipped++;\n };\n for (const block of doc.blocks) {\n count(block.delta);\n for (const cell of block.cells ?? []) count(cell.delta);\n }\n return { images, skipped };\n}\n\nfunction base64ToBytes(b64: string): Uint8Array {\n if (typeof atob === \"function\") {\n const bin = atob(b64);\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\n return out;\n }\n // Node fallback.\n return new Uint8Array(Buffer.from(b64, \"base64\"));\n}\n\n// ---------- attribute mapping ----------\n\nconst HEADING_LEVELS = [\n HeadingLevel.HEADING_1,\n HeadingLevel.HEADING_2,\n HeadingLevel.HEADING_3,\n HeadingLevel.HEADING_4,\n HeadingLevel.HEADING_5,\n HeadingLevel.HEADING_6,\n];\n\nfunction clampHeadingLevel(l: unknown): 1 | 2 | 3 | 4 | 5 | 6 {\n if (typeof l !== \"number\") return 1;\n const n = Math.trunc(l);\n if (n < 1) return 1;\n if (n > 6) return 6;\n return n as 1 | 2 | 3 | 4 | 5 | 6;\n}\n\nfunction clampListLevel(l: unknown): number {\n if (typeof l !== \"number\" || !Number.isFinite(l)) return 0;\n return Math.max(0, Math.min(5, Math.trunc(l)));\n}\n\nfunction alignFor(a: AlignValue | undefined): (typeof AlignmentType)[keyof typeof AlignmentType] | undefined {\n switch (a) {\n case \"left\":\n return AlignmentType.LEFT;\n case \"center\":\n return AlignmentType.CENTER;\n case \"right\":\n return AlignmentType.RIGHT;\n case \"justify\":\n return AlignmentType.JUSTIFIED;\n default:\n return undefined;\n }\n}\n\nfunction cssColorToDocxHex(color: string | undefined): string | undefined {\n if (!color) return undefined;\n // docx expects RRGGBB without leading '#'.\n const c = color.trim();\n if (/^#[0-9a-f]{6}$/i.test(c)) return c.slice(1).toUpperCase();\n if (/^#[0-9a-f]{3}$/i.test(c)) {\n // expand short hex\n return c\n .slice(1)\n .split(\"\")\n .map((d) => d + d)\n .join(\"\")\n .toUpperCase();\n }\n const rgb = /^rgb\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)/i.exec(c);\n if (rgb) {\n const r = Number(rgb[1]);\n const g = Number(rgb[2]);\n const b = Number(rgb[3]);\n return [r, g, b].map((n) => Math.max(0, Math.min(255, n)).toString(16).padStart(2, \"0\")).join(\"\").toUpperCase();\n }\n // Named colors / other forms — let docx fall back to default.\n return undefined;\n}\n\n/**\n * docx sizes are in half-points (24 = 12pt). Parse common CSS sizes.\n * Returns `undefined` when not parseable so callers can pick a default.\n */\nfunction parseFontSizeToHalfPoints(size: string | undefined): number | undefined {\n if (!size) return undefined;\n const s = size.trim();\n const m = /^(-?\\d*\\.?\\d+)\\s*(pt|px|em|rem)?$/i.exec(s);\n if (!m) return undefined;\n const n = Number(m[1]);\n if (!Number.isFinite(n) || n <= 0) return undefined;\n const unit = (m[2] ?? \"pt\").toLowerCase();\n const pt =\n unit === \"pt\"\n ? n\n : unit === \"px\"\n ? n * 0.75 // CSS px → pt at 96dpi\n : n * 12;\n return Math.round(pt * 2);\n}\n\n// ---------- list numbering definitions ----------\n\nfunction buildBulletLevels(): Array<{\n level: number;\n format: (typeof LevelFormat)[keyof typeof LevelFormat];\n text: string;\n alignment: (typeof AlignmentType)[keyof typeof AlignmentType];\n style?: { paragraph?: { indent?: { left: number; hanging: number } } };\n}> {\n const symbols = [\"•\", \"◦\", \"▪\", \"•\", \"◦\", \"▪\"];\n return symbols.map((sym, i) => ({\n level: i,\n format: LevelFormat.BULLET,\n text: sym,\n alignment: AlignmentType.LEFT,\n style: {\n paragraph: { indent: { left: 360 + i * 360, hanging: 260 } },\n },\n }));\n}\n\nfunction buildOrderedLevels(): Array<{\n level: number;\n format: (typeof LevelFormat)[keyof typeof LevelFormat];\n text: string;\n alignment: (typeof AlignmentType)[keyof typeof AlignmentType];\n style?: { paragraph?: { indent?: { left: number; hanging: number } } };\n}> {\n const formats = [\n LevelFormat.DECIMAL,\n LevelFormat.LOWER_LETTER,\n LevelFormat.LOWER_ROMAN,\n LevelFormat.DECIMAL,\n LevelFormat.LOWER_LETTER,\n LevelFormat.LOWER_ROMAN,\n ];\n return formats.map((format, i) => ({\n level: i,\n format,\n text: `%${i + 1}.`,\n alignment: AlignmentType.LEFT,\n style: {\n paragraph: { indent: { left: 360 + i * 360, hanging: 260 } },\n },\n }));\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -3,6 +3,20 @@ import { SerializedDocument, LegacySerializedDocument } from '@sofereditor/core'
|
|
|
3
3
|
interface ResolvedImage {
|
|
4
4
|
data: Uint8Array;
|
|
5
5
|
type: "png" | "jpg" | "gif" | "bmp" | "svg";
|
|
6
|
+
/**
|
|
7
|
+
* Só presente quando `type === "svg"`: o fallback raster já decodificado,
|
|
8
|
+
* exigido pelo `ImageRun` do docx para `type: "svg"`. Preenchido
|
|
9
|
+
* internamente por `resolveAllImages` a partir do `svgFallback` do embed —
|
|
10
|
+
* nunca por um `resolveImage` customizado. Fica aqui (no valor resolvido
|
|
11
|
+
* por `src`, não num mapa paralelo por embed) porque é exatamente isso que
|
|
12
|
+
* "resolvido" significa para um svg: dois embeds com o mesmo `src` — um
|
|
13
|
+
* com `svgFallback`, outro sem — compartilham o mesmo `src` e portanto o
|
|
14
|
+
* mesmo SVG; o fallback de qualquer um dos dois serve para ambos.
|
|
15
|
+
*/
|
|
16
|
+
svgFallback?: {
|
|
17
|
+
data: Uint8Array;
|
|
18
|
+
type: Exclude<ResolvedImage["type"], "svg">;
|
|
19
|
+
};
|
|
6
20
|
}
|
|
7
21
|
interface DocumentToDocxOptions {
|
|
8
22
|
/** Document title; embedded in core properties. */
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,20 @@ import { SerializedDocument, LegacySerializedDocument } from '@sofereditor/core'
|
|
|
3
3
|
interface ResolvedImage {
|
|
4
4
|
data: Uint8Array;
|
|
5
5
|
type: "png" | "jpg" | "gif" | "bmp" | "svg";
|
|
6
|
+
/**
|
|
7
|
+
* Só presente quando `type === "svg"`: o fallback raster já decodificado,
|
|
8
|
+
* exigido pelo `ImageRun` do docx para `type: "svg"`. Preenchido
|
|
9
|
+
* internamente por `resolveAllImages` a partir do `svgFallback` do embed —
|
|
10
|
+
* nunca por um `resolveImage` customizado. Fica aqui (no valor resolvido
|
|
11
|
+
* por `src`, não num mapa paralelo por embed) porque é exatamente isso que
|
|
12
|
+
* "resolvido" significa para um svg: dois embeds com o mesmo `src` — um
|
|
13
|
+
* com `svgFallback`, outro sem — compartilham o mesmo `src` e portanto o
|
|
14
|
+
* mesmo SVG; o fallback de qualquer um dos dois serve para ambos.
|
|
15
|
+
*/
|
|
16
|
+
svgFallback?: {
|
|
17
|
+
data: Uint8Array;
|
|
18
|
+
type: Exclude<ResolvedImage["type"], "svg">;
|
|
19
|
+
};
|
|
6
20
|
}
|
|
7
21
|
interface DocumentToDocxOptions {
|
|
8
22
|
/** Document title; embedded in core properties. */
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
DEFAULT_PAGE_SETTINGS,
|
|
4
4
|
isImageEmbed,
|
|
5
5
|
isLegacySerializedDocument,
|
|
6
|
+
normalizarLarguras,
|
|
6
7
|
pxToMm
|
|
7
8
|
} from "@sofereditor/core";
|
|
8
9
|
import {
|
|
@@ -10,6 +11,7 @@ import {
|
|
|
10
11
|
BorderStyle,
|
|
11
12
|
Document,
|
|
12
13
|
HeadingLevel,
|
|
14
|
+
HeightRule,
|
|
13
15
|
ImageRun,
|
|
14
16
|
LevelFormat,
|
|
15
17
|
LineRuleType,
|
|
@@ -55,8 +57,8 @@ function normalize(doc) {
|
|
|
55
57
|
return isLegacySerializedDocument(doc) ? { blocks: doc } : doc;
|
|
56
58
|
}
|
|
57
59
|
function buildDocument(doc, options, images) {
|
|
58
|
-
const children = blocksToDocxChildren(doc, images);
|
|
59
60
|
const settings = doc.pageSettings ?? DEFAULT_PAGE_SETTINGS;
|
|
61
|
+
const children = blocksToDocxChildren(doc, images, settings);
|
|
60
62
|
return new Document({
|
|
61
63
|
creator: options.creator,
|
|
62
64
|
title: options.title,
|
|
@@ -97,7 +99,7 @@ function sectionPropertiesFor(settings) {
|
|
|
97
99
|
}
|
|
98
100
|
};
|
|
99
101
|
}
|
|
100
|
-
function blocksToDocxChildren(doc, images) {
|
|
102
|
+
function blocksToDocxChildren(doc, images, settings) {
|
|
101
103
|
const out = [];
|
|
102
104
|
const blocks = doc.blocks;
|
|
103
105
|
for (let i = 0; i < blocks.length; i++) {
|
|
@@ -119,7 +121,7 @@ function blocksToDocxChildren(doc, images) {
|
|
|
119
121
|
out.push(makeListItem(block, images));
|
|
120
122
|
break;
|
|
121
123
|
case "table":
|
|
122
|
-
out.push(makeTable(block, images));
|
|
124
|
+
out.push(makeTable(block, images, settings));
|
|
123
125
|
break;
|
|
124
126
|
default:
|
|
125
127
|
out.push(makeParagraph(block, images));
|
|
@@ -182,10 +184,11 @@ function makeListItem(block, images) {
|
|
|
182
184
|
children: deltaToRuns(block.delta, ARIAL, images)
|
|
183
185
|
});
|
|
184
186
|
}
|
|
185
|
-
function makeTable(block, images) {
|
|
187
|
+
function makeTable(block, images, settings) {
|
|
186
188
|
const rows = typeof block.attrs.rows === "number" ? block.attrs.rows : 0;
|
|
187
189
|
const cols = typeof block.attrs.cols === "number" ? block.attrs.cols : 0;
|
|
188
190
|
const cells = block.cells ?? [];
|
|
191
|
+
const alturas = block.attrs.rowHeights;
|
|
189
192
|
const rowsOut = [];
|
|
190
193
|
for (let r = 0; r < rows; r++) {
|
|
191
194
|
const cellsOut = [];
|
|
@@ -198,22 +201,36 @@ function makeTable(block, images) {
|
|
|
198
201
|
if (cell.attrs?.covered) continue;
|
|
199
202
|
cellsOut.push(makeCell(cell, images));
|
|
200
203
|
}
|
|
201
|
-
|
|
204
|
+
const raw = Array.isArray(alturas) && alturas.length === rows ? alturas[r] : void 0;
|
|
205
|
+
const h = typeof raw === "number" && isFinite(raw) ? Math.max(0, raw) : void 0;
|
|
206
|
+
rowsOut.push(
|
|
207
|
+
new TableRow({
|
|
208
|
+
children: cellsOut,
|
|
209
|
+
...h != null ? { height: { value: convertMillimetersToTwip(pxToMm(h)), rule: HeightRule.ATLEAST } } : {}
|
|
210
|
+
})
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
if (cols <= 0) {
|
|
214
|
+
return new Table({
|
|
215
|
+
rows: rowsOut,
|
|
216
|
+
borders: docxTableBorders(block.attrs.borderPreset, block.attrs.borderColor),
|
|
217
|
+
width: { size: 100, type: WidthType.PERCENTAGE }
|
|
218
|
+
});
|
|
202
219
|
}
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
220
|
+
const larguraUtilTwips = convertMillimetersToTwip(
|
|
221
|
+
pxToMm(settings.width - settings.marginLeft - settings.marginRight)
|
|
222
|
+
);
|
|
223
|
+
const tabelaTwips = Math.round(larguraUtilTwips * ((block.attrs.tableWidth ?? 100) / 100));
|
|
224
|
+
const pct = normalizarLarguras(block.attrs.colWidths, cols);
|
|
225
|
+
const columnWidths = pct.map((p) => Math.round(tabelaTwips * (p / 100)));
|
|
206
226
|
return new Table({
|
|
207
227
|
rows: rowsOut,
|
|
208
228
|
borders: docxTableBorders(block.attrs.borderPreset, block.attrs.borderColor),
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
layout: TableLayoutType.FIXED,
|
|
215
|
-
width: { size: columnWidths.reduce((a, b) => a + b, 0), type: WidthType.DXA }
|
|
216
|
-
} : { width: { size: 100, type: WidthType.PERCENTAGE } }
|
|
229
|
+
columnWidths,
|
|
230
|
+
// O `layout: FIXED` permanece pelo mesmo motivo de antes: sem ele o Word
|
|
231
|
+
// autoajusta ao conteúdo e trata `columnWidths` como mero palpite.
|
|
232
|
+
layout: TableLayoutType.FIXED,
|
|
233
|
+
width: { size: columnWidths.reduce((a, b) => a + b, 0), type: WidthType.DXA }
|
|
217
234
|
});
|
|
218
235
|
}
|
|
219
236
|
function docxTableBorders(preset, color) {
|
|
@@ -310,6 +327,18 @@ function makeTextRun(text, marks, defaults) {
|
|
|
310
327
|
function makeImageRun(embed, images) {
|
|
311
328
|
const resolved = images.get(embed.src);
|
|
312
329
|
if (!resolved) return null;
|
|
330
|
+
if (resolved.type === "svg") {
|
|
331
|
+
if (!resolved.svgFallback) return null;
|
|
332
|
+
return new ImageRun({
|
|
333
|
+
type: "svg",
|
|
334
|
+
data: resolved.data,
|
|
335
|
+
fallback: { type: resolved.svgFallback.type, data: resolved.svgFallback.data },
|
|
336
|
+
transformation: {
|
|
337
|
+
width: Math.max(1, Math.round(embed.width)),
|
|
338
|
+
height: Math.max(1, Math.round(embed.height))
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
}
|
|
313
342
|
return new ImageRun({
|
|
314
343
|
data: resolved.data,
|
|
315
344
|
type: resolved.type,
|
|
@@ -354,8 +383,14 @@ function typeFromExtension(src) {
|
|
|
354
383
|
}
|
|
355
384
|
async function resolveAllImages(doc, resolve) {
|
|
356
385
|
const srcs = /* @__PURE__ */ new Set();
|
|
386
|
+
const fallbacks = /* @__PURE__ */ new Map();
|
|
357
387
|
const collect = (delta) => {
|
|
358
|
-
for (const op of delta)
|
|
388
|
+
for (const op of delta) {
|
|
389
|
+
if (!isImageEmbed(op.insert)) continue;
|
|
390
|
+
srcs.add(op.insert.src);
|
|
391
|
+
const fb = op.insert.svgFallback;
|
|
392
|
+
if (fb && !fallbacks.has(op.insert.src)) fallbacks.set(op.insert.src, fb);
|
|
393
|
+
}
|
|
359
394
|
};
|
|
360
395
|
for (const block of doc.blocks) {
|
|
361
396
|
collect(block.delta);
|
|
@@ -370,7 +405,11 @@ async function resolveAllImages(doc, resolve) {
|
|
|
370
405
|
} catch {
|
|
371
406
|
resolved = null;
|
|
372
407
|
}
|
|
373
|
-
if (resolved?.type === "svg")
|
|
408
|
+
if (resolved?.type === "svg") {
|
|
409
|
+
const fb = fallbacks.get(src);
|
|
410
|
+
const decodedFb = fb ? decodeDataUrl(fb) : null;
|
|
411
|
+
resolved = decodedFb && decodedFb.kind !== "svg" ? { ...resolved, svgFallback: { data: decodedFb.bytes, type: decodedFb.kind } } : null;
|
|
412
|
+
}
|
|
374
413
|
images.set(src, resolved);
|
|
375
414
|
})
|
|
376
415
|
);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/docx.ts"],"sourcesContent":["import type {\n AlignValue,\n DeltaOp,\n ImageEmbed,\n LegacySerializedDocument,\n ListKind,\n MarkAttrs,\n SerializedBlock,\n SerializedCell,\n SerializedDocument,\n TableBorderPreset,\n} from \"@sofereditor/core\";\nimport {\n DEFAULT_PAGE_SETTINGS,\n isImageEmbed,\n isLegacySerializedDocument,\n pxToMm,\n type PageSettings,\n} from \"@sofereditor/core\";\nimport {\n AlignmentType,\n BorderStyle,\n Document,\n HeadingLevel,\n ImageRun,\n LevelFormat,\n LineRuleType,\n Packer,\n Paragraph,\n PageOrientation,\n ShadingType,\n Table,\n TableCell,\n TableLayoutType,\n TableRow,\n TextRun,\n UnderlineType,\n VerticalAlign,\n WidthType,\n convertMillimetersToTwip,\n} from \"docx\";\n\nconst BULLET_REF = \"ed-bullet\";\nconst ORDERED_REF = \"ed-ordered\";\n\nexport interface ResolvedImage {\n data: Uint8Array;\n type: \"png\" | \"jpg\" | \"gif\" | \"bmp\" | \"svg\";\n}\n\nexport interface DocumentToDocxOptions {\n /** Document title; embedded in core properties. */\n title?: string;\n /** Author for core properties. */\n creator?: string;\n /**\n * Resolve um `src` de imagem para bytes. Default: data URLs (decodificadas\n * localmente) e http(s) via fetch. Retornar null pula a imagem (contada em\n * `skippedImages`) sem abortar o export.\n */\n resolveImage?: (src: string) => Promise<ResolvedImage | null>;\n}\n\n/**\n * Build a docx `Document` from a `SerializedDocument`. Output is a Blob you can\n * download with `downloadBlob` from `@sofereditor/export-pdf`.\n *\n * Mappings:\n * - paragraph / heading / blockquote / codeBlock → Paragraph (with `heading`,\n * shading, monospace font for code)\n * - listItem → Paragraph with `numbering: { reference, level }`\n * - table → docx `Table`. `rowspan`/`colspan` map to TableCell's `rowSpan`/\n * `columnSpan`; \"covered\" cells are skipped (docx infers cover from spans)\n * - inline marks → TextRun props (bold, italics, underline, strike, color,\n * font, size in half-points)\n * - image embeds → ImageRun with bytes resolved via `resolveImage` (default:\n * data URLs decoded locally, http(s) fetched; unresolved images are\n * skipped and counted in `skippedImages` instead of aborting the export)\n */\nexport async function documentToDocxBlob(\n doc: SerializedDocument | LegacySerializedDocument,\n options: DocumentToDocxOptions = {},\n): Promise<{ blob: Blob; skippedImages: number }> {\n const normalized = normalize(doc);\n const { images, skipped } = await resolveAllImages(\n normalized,\n options.resolveImage ?? defaultResolveImage,\n );\n const built = buildDocument(normalized, options, images);\n return { blob: await Packer.toBlob(built), skippedImages: skipped };\n}\n\n/** Same as `documentToDocxBlob` but returns a Uint8Array (useful in Node/tests). */\nexport async function documentToDocxBuffer(\n doc: SerializedDocument | LegacySerializedDocument,\n options: DocumentToDocxOptions = {},\n): Promise<{ buffer: Uint8Array; skippedImages: number }> {\n const normalized = normalize(doc);\n const { images, skipped } = await resolveAllImages(\n normalized,\n options.resolveImage ?? defaultResolveImage,\n );\n const built = buildDocument(normalized, options, images);\n const buf = await Packer.toBuffer(built);\n // `Packer.toBuffer` returns a Node Buffer at runtime — coerce for consumers.\n return {\n buffer: buf instanceof Uint8Array ? buf : new Uint8Array(buf),\n skippedImages: skipped,\n };\n}\n\nfunction normalize(doc: SerializedDocument | LegacySerializedDocument): SerializedDocument {\n return isLegacySerializedDocument(doc) ? { blocks: doc } : doc;\n}\n\nfunction buildDocument(\n doc: SerializedDocument,\n options: DocumentToDocxOptions,\n images: Map<string, ResolvedImage | null>,\n): Document {\n const children = blocksToDocxChildren(doc, images);\n const settings = doc.pageSettings ?? DEFAULT_PAGE_SETTINGS;\n return new Document({\n creator: options.creator,\n title: options.title,\n numbering: {\n config: [\n {\n reference: BULLET_REF,\n levels: buildBulletLevels(),\n },\n {\n reference: ORDERED_REF,\n levels: buildOrderedLevels(),\n },\n ],\n },\n sections: [\n {\n properties: sectionPropertiesFor(settings),\n children,\n },\n ],\n });\n}\n\nfunction sectionPropertiesFor(settings: PageSettings) {\n return {\n page: {\n size: {\n width: convertMillimetersToTwip(pxToMm(settings.width)),\n height: convertMillimetersToTwip(pxToMm(settings.height)),\n orientation: PageOrientation.PORTRAIT,\n },\n margin: {\n top: convertMillimetersToTwip(pxToMm(settings.marginTop)),\n bottom: convertMillimetersToTwip(pxToMm(settings.marginBottom)),\n left: convertMillimetersToTwip(pxToMm(settings.marginLeft)),\n right: convertMillimetersToTwip(pxToMm(settings.marginRight)),\n },\n },\n };\n}\n\nfunction blocksToDocxChildren(\n doc: SerializedDocument,\n images: Map<string, ResolvedImage | null>,\n): Array<Paragraph | Table> {\n const out: Array<Paragraph | Table> = [];\n const blocks = doc.blocks;\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i];\n switch (block.type) {\n case \"paragraph\":\n out.push(makeParagraph(block, images));\n break;\n case \"heading\":\n out.push(makeHeading(block, images));\n break;\n case \"blockquote\":\n out.push(makeBlockquote(block, images));\n break;\n case \"codeBlock\":\n out.push(makeCodeBlock(block, images));\n break;\n case \"listItem\":\n out.push(makeListItem(block, images));\n break;\n case \"table\":\n out.push(makeTable(block, images));\n break;\n default:\n out.push(makeParagraph(block, images));\n }\n }\n return out;\n}\n\n// ---------- block builders ----------\n\n// School standard: Arial for all body text. Code blocks override with\n// Consolas (monospace is more legible for code). Italics on blockquote is\n// kept as a stylistic default.\nconst ARIAL: RunDefaults = { font: \"Arial\" };\n\nfunction makeParagraph(\n block: SerializedBlock,\n images: Map<string, ResolvedImage | null>,\n): Paragraph {\n return new Paragraph({\n alignment: alignFor(block.attrs.align),\n bidirectional: block.attrs.dir === \"rtl\" ? true : undefined,\n ...answerLineProps(block.attrs),\n children: deltaToRuns(block.delta, ARIAL, images),\n });\n}\n\n/**\n * Linha de resposta → borda inferior de parágrafo (`w:pBdr`) + entrelinha.\n * É como um documento profissional desenha uma pauta: a régua acompanha a\n * margem automaticamente, ao contrário de uma fileira de underlines.\n *\n * 240 twips = uma linha simples no OOXML.\n */\nfunction answerLineProps(attrs: SerializedBlock[\"attrs\"]) {\n if (attrs.answerLine !== true) return {};\n const spacing = attrs.answerLineSpacing ?? 1;\n return {\n border: {\n bottom: { style: BorderStyle.SINGLE, size: 6, color: \"000000\", space: 1 },\n },\n spacing: { line: Math.round(240 * spacing), lineRule: LineRuleType.AUTO },\n };\n}\n\nfunction makeHeading(\n block: SerializedBlock,\n images: Map<string, ResolvedImage | null>,\n): Paragraph {\n const level = clampHeadingLevel(block.attrs.level);\n return new Paragraph({\n heading: HEADING_LEVELS[level - 1],\n alignment: alignFor(block.attrs.align),\n children: deltaToRuns(block.delta, ARIAL, images),\n });\n}\n\nfunction makeBlockquote(\n block: SerializedBlock,\n images: Map<string, ResolvedImage | null>,\n): Paragraph {\n return new Paragraph({\n alignment: alignFor(block.attrs.align),\n indent: { left: 480 }, // ~0.25\"\n border: {\n left: { color: \"CBD5E1\", space: 12, style: BorderStyle.SINGLE, size: 12 },\n },\n children: deltaToRuns(block.delta, { ...ARIAL, italics: true }, images),\n });\n}\n\nfunction makeCodeBlock(\n block: SerializedBlock,\n images: Map<string, ResolvedImage | null>,\n): Paragraph {\n return new Paragraph({\n spacing: { before: 100, after: 100 },\n shading: { type: ShadingType.CLEAR, color: \"auto\", fill: \"F1F5F9\" },\n children: deltaToRuns(block.delta, { font: \"Consolas\", size: 20 }, images),\n });\n}\n\nfunction makeListItem(\n block: SerializedBlock,\n images: Map<string, ResolvedImage | null>,\n): Paragraph {\n const kind: ListKind = block.attrs.listKind === \"ordered\" ? \"ordered\" : \"bullet\";\n const reference = kind === \"ordered\" ? ORDERED_REF : BULLET_REF;\n const level = clampListLevel(block.attrs.listLevel);\n return new Paragraph({\n numbering: { reference, level },\n alignment: alignFor(block.attrs.align),\n children: deltaToRuns(block.delta, ARIAL, images),\n });\n}\n\nfunction makeTable(block: SerializedBlock, images: Map<string, ResolvedImage | null>): Table {\n const rows = typeof block.attrs.rows === \"number\" ? block.attrs.rows : 0;\n const cols = typeof block.attrs.cols === \"number\" ? block.attrs.cols : 0;\n const cells = block.cells ?? [];\n\n const rowsOut: TableRow[] = [];\n for (let r = 0; r < rows; r++) {\n const cellsOut: TableCell[] = [];\n for (let c = 0; c < cols; c++) {\n const cell = cells[r * cols + c];\n if (!cell) {\n cellsOut.push(emptyCell());\n continue;\n }\n if (cell.attrs?.covered) continue;\n cellsOut.push(makeCell(cell, images));\n }\n rowsOut.push(new TableRow({ children: cellsOut }));\n }\n\n // Validate the RAW array against `cols` — filtering invalid entries first\n // (e.g. dropping a negative width) would silently shift the remaining\n // widths onto the wrong columns while still passing a length check.\n const rawColWidths = block.attrs.colWidths;\n const isValidColWidths =\n Array.isArray(rawColWidths) &&\n cols > 0 &&\n rawColWidths.length === cols &&\n rawColWidths.every((w): w is number => typeof w === \"number\" && w > 0);\n const columnWidths = isValidColWidths\n ? rawColWidths.map((px) => convertMillimetersToTwip(pxToMm(px)))\n : undefined;\n\n return new Table({\n rows: rowsOut,\n borders: docxTableBorders(block.attrs.borderPreset, block.attrs.borderColor),\n ...(columnWidths\n ? {\n columnWidths,\n // Fix the layout so Word honors the column widths verbatim instead\n // of autofitting to content (the OOXML default when `tblLayout` is\n // absent, which would make `columnWidths` a mere hint).\n layout: TableLayoutType.FIXED,\n width: { size: columnWidths.reduce((a, b) => a + b, 0), type: WidthType.DXA },\n }\n : { width: { size: 100, type: WidthType.PERCENTAGE } }),\n });\n}\n\n/**\n * Traduz o preset para `w:tblBorders`. Lado desligado = `BorderStyle.NONE`.\n *\n * A tabela-verdade sai direto de `cellBorderColors`: o que aquele helper liga em\n * TODA célula vira o par externo MAIS o interno correspondente. Ex.: em\n * `vertical`, toda célula tem left/right ligados — logo as laterais externas\n * (left/right) E as internas (insideV) ficam ligadas, e topo/base\n * (top/bottom/insideH) desligados.\n *\n * A tabela é a especificação; a função sai dela, não o contrário.\n */\nfunction docxTableBorders(preset: TableBorderPreset | undefined, color?: string) {\n // Cor inválida ou ausente cai no padrão: `cssColorToDocxHex` devolve undefined\n // para o que não souber converter.\n const hex = cssColorToDocxHex(color) ?? \"CBD5E1\";\n const on = { style: BorderStyle.SINGLE, size: 6, color: hex };\n const off = { style: BorderStyle.NONE, size: 0, color: \"auto\" };\n const s = (visivel: boolean) => (visivel ? on : off);\n\n // [top/bottom, left/right, insideH, insideV]\n const TRUTH: Record<TableBorderPreset, [boolean, boolean, boolean, boolean]> = {\n all: [true, true, true, true],\n outer: [true, true, false, false],\n horizontal: [true, false, true, false],\n vertical: [false, true, false, true],\n none: [false, false, false, false],\n };\n const [tb, lr, iH, iV] = TRUTH[preset ?? \"all\"];\n return {\n top: s(tb),\n bottom: s(tb),\n left: s(lr),\n right: s(lr),\n insideHorizontal: s(iH),\n insideVertical: s(iV),\n };\n}\n\nfunction makeCell(cell: SerializedCell, images: Map<string, ResolvedImage | null>): TableCell {\n const span = cell.attrs?.colspan && cell.attrs.colspan > 1 ? cell.attrs.colspan : 1;\n const rowSpan = cell.attrs?.rowspan && cell.attrs.rowspan > 1 ? cell.attrs.rowspan : 1;\n const fill = cssColorToDocxHex(cell.attrs?.bgColor);\n return new TableCell({\n columnSpan: span,\n rowSpan,\n verticalAlign: VerticalAlign.TOP,\n shading: fill ? { type: ShadingType.CLEAR, color: \"auto\", fill } : undefined,\n children: [\n new Paragraph({\n alignment: alignFor(cell.attrs?.align),\n children: deltaToRuns(cell.delta, ARIAL, images),\n }),\n ],\n });\n}\n\nfunction emptyCell(): TableCell {\n return new TableCell({ children: [new Paragraph(\"\")] });\n}\n\n// ---------- inline ----------\n\ninterface RunDefaults {\n bold?: boolean;\n italics?: boolean;\n font?: string;\n size?: number;\n}\n\nfunction deltaToRuns(\n delta: DeltaOp[],\n defaults: RunDefaults = {},\n images: Map<string, ResolvedImage | null>,\n): Array<TextRun | ImageRun> {\n if (delta.length === 0) return [new TextRun(\"\")];\n const out: Array<TextRun | ImageRun> = [];\n for (const op of delta) {\n if (typeof op.insert === \"string\") {\n if (op.insert.length === 0) continue;\n out.push(makeTextRun(op.insert, op.attributes, defaults));\n } else if (isImageEmbed(op.insert)) {\n const embed = op.insert;\n const img = makeImageRun(embed, images);\n if (img) out.push(img);\n // Captions are emitted as italic-smaller text on a new line right after\n // the image. Word-style \"Caption\" paragraph would need a paragraph\n // break, which we can't do mid-delta — visually correct but loses the\n // semantic \"Caption\" style.\n if (embed.caption && embed.caption.length > 0) {\n out.push(\n new TextRun({\n text: embed.caption,\n italics: true,\n size: 18, // 9pt — typical caption size\n break: 1,\n }),\n );\n }\n }\n }\n if (out.length === 0) out.push(new TextRun(\"\"));\n return out;\n}\n\n/**\n * Props de um `TextRun` a partir das marks. Fica numa função só porque\n * `makeTextRun` tem dois caminhos (linha única e multi-linha) que antes\n * duplicavam esta lista inteira — uma mark acrescentada em apenas um dos dois\n * se perdia silenciosamente em texto com quebra de linha.\n *\n * `highlight` sai como `w:shd` e NÃO como `w:highlight`: este último só aceita\n * ~15 valores nomeados e não sobreviveria a uma cor arbitrária do picker.\n */\nfunction textRunProps(text: string, m: MarkAttrs, defaults: RunDefaults) {\n const fill = cssColorToDocxHex(m.highlight);\n return {\n text,\n bold: m.bold || defaults.bold,\n italics: m.italic || defaults.italics,\n underline: m.underline ? { type: UnderlineType.SINGLE } : undefined,\n strike: m.strike,\n color: cssColorToDocxHex(m.color),\n font: m.fontFamily ?? defaults.font,\n size: parseFontSizeToHalfPoints(m.fontSize) ?? defaults.size,\n shading: fill ? { type: ShadingType.CLEAR, color: \"auto\", fill } : undefined,\n };\n}\n\nfunction makeTextRun(\n text: string,\n marks: MarkAttrs | undefined,\n defaults: RunDefaults,\n): TextRun {\n const m = marks ?? {};\n // TextRun reads newlines via `break`; convert \\n into break runs.\n const segments = text.split(\"\\n\");\n if (segments.length === 1) {\n return new TextRun(textRunProps(text, m, defaults));\n }\n // Multi-line: rejoin via TextRun children — but TextRun expects a single text\n // string. Approximate with non-printing line breaks: produce a sequence of\n // TextRuns separated by `new TextRun({ break: 1 })` packed into the parent.\n // Simpler: collapse to a single TextRun with the string, treating \\n as a\n // soft-break placeholder. Word renders \\n inside a w:t as a literal space,\n // so we replace with a small symbol-friendly fallback.\n return new TextRun(textRunProps(text.replace(/\\n/g, \" \"), m, defaults));\n}\n\nfunction makeImageRun(\n embed: ImageEmbed,\n images: Map<string, ResolvedImage | null>,\n): ImageRun | null {\n const resolved = images.get(embed.src);\n if (!resolved) return null;\n return new ImageRun({\n data: resolved.data,\n type: resolved.type,\n transformation: {\n width: Math.max(1, Math.round(embed.width)),\n height: Math.max(1, Math.round(embed.height)),\n },\n } as ConstructorParameters<typeof ImageRun>[0]);\n}\n\ninterface DecodedImage {\n bytes: Uint8Array;\n kind: \"png\" | \"jpg\" | \"gif\" | \"bmp\" | \"svg\";\n}\n\nfunction decodeDataUrl(src: string): DecodedImage | null {\n const m = /^data:image\\/(png|jpe?g|gif|bmp|svg\\+xml);base64,(.+)$/i.exec(src);\n if (!m) return null;\n const fmt = m[1].toLowerCase();\n const kind: DecodedImage[\"kind\"] =\n fmt === \"jpeg\" || fmt === \"jpg\"\n ? \"jpg\"\n : fmt === \"svg+xml\"\n ? \"svg\"\n : (fmt as \"png\" | \"gif\" | \"bmp\");\n const base64 = m[2];\n const bytes = base64ToBytes(base64);\n return { bytes, kind };\n}\n\n/**\n * Default `resolveImage`: decode data URLs locally, fetch http(s) URLs, and\n * return null for anything else (caller counts it in `skippedImages`).\n */\nasync function defaultResolveImage(src: string): Promise<ResolvedImage | null> {\n const decoded = decodeDataUrl(src);\n if (decoded) return { data: decoded.bytes, type: decoded.kind };\n if (/^https?:\\/\\//i.test(src) && typeof fetch === \"function\") {\n try {\n const res = await fetch(src);\n if (!res.ok) return null;\n const ct = (res.headers.get(\"content-type\") ?? \"\").toLowerCase();\n const matchedType: ResolvedImage[\"type\"] | null = ct.includes(\"png\")\n ? \"png\"\n : ct.includes(\"jpeg\") || ct.includes(\"jpg\")\n ? \"jpg\"\n : ct.includes(\"gif\")\n ? \"gif\"\n : ct.includes(\"bmp\")\n ? \"bmp\"\n : ct.includes(\"svg\")\n ? \"svg\"\n : null;\n // Unknown content-type (e.g. image/webp) with no recognizable extension\n // in the URL: skip rather than mislabeling bytes as PNG (would produce\n // a broken image in Word — contract is \"failure to resolve → skip\").\n const type = matchedType ?? typeFromExtension(src);\n if (!type) return null;\n return { data: new Uint8Array(await res.arrayBuffer()), type };\n } catch {\n return null;\n }\n }\n return null;\n}\n\nfunction typeFromExtension(src: string): ResolvedImage[\"type\"] | null {\n const m = /\\.(png|jpe?g|gif|bmp|svg)(\\?|#|$)/i.exec(src);\n if (!m) return null;\n const ext = m[1].toLowerCase();\n return ext === \"jpeg\" || ext === \"jpg\" ? \"jpg\" : (ext as ResolvedImage[\"type\"]);\n}\n\n/**\n * Async pre-pass: collect every image `src` referenced by the document\n * (block deltas and table cell deltas), resolve them in parallel via\n * `resolve`, and return a lookup map plus the count of embeds that failed to\n * resolve. The rest of the build pipeline stays synchronous and reads from\n * this map.\n */\nasync function resolveAllImages(\n doc: SerializedDocument,\n resolve: (src: string) => Promise<ResolvedImage | null>,\n): Promise<{ images: Map<string, ResolvedImage | null>; skipped: number }> {\n const srcs = new Set<string>();\n const collect = (delta: DeltaOp[]) => {\n for (const op of delta) if (isImageEmbed(op.insert)) srcs.add(op.insert.src);\n };\n for (const block of doc.blocks) {\n collect(block.delta);\n for (const cell of block.cells ?? []) collect(cell.delta);\n }\n const images = new Map<string, ResolvedImage | null>();\n await Promise.all(\n [...srcs].map(async (src) => {\n let resolved: ResolvedImage | null = null;\n try {\n resolved = await resolve(src);\n } catch {\n resolved = null;\n }\n // docx's ImageRun requires a `fallback` for type \"svg\" (RegularImageOptions);\n // without it the constructor throws synchronously inside buildDocument,\n // which is outside this try/catch and would abort the whole export. Treat\n // svg as unresolved (skip) until we add fallback support.\n if (resolved?.type === \"svg\") resolved = null;\n images.set(src, resolved);\n }),\n );\n // skipped conta OCORRÊNCIAS de embed sem resolução (não srcs únicos).\n let skipped = 0;\n const count = (delta: DeltaOp[]) => {\n for (const op of delta)\n if (isImageEmbed(op.insert) && !images.get(op.insert.src)) skipped++;\n };\n for (const block of doc.blocks) {\n count(block.delta);\n for (const cell of block.cells ?? []) count(cell.delta);\n }\n return { images, skipped };\n}\n\nfunction base64ToBytes(b64: string): Uint8Array {\n if (typeof atob === \"function\") {\n const bin = atob(b64);\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\n return out;\n }\n // Node fallback.\n return new Uint8Array(Buffer.from(b64, \"base64\"));\n}\n\n// ---------- attribute mapping ----------\n\nconst HEADING_LEVELS = [\n HeadingLevel.HEADING_1,\n HeadingLevel.HEADING_2,\n HeadingLevel.HEADING_3,\n HeadingLevel.HEADING_4,\n HeadingLevel.HEADING_5,\n HeadingLevel.HEADING_6,\n];\n\nfunction clampHeadingLevel(l: unknown): 1 | 2 | 3 | 4 | 5 | 6 {\n if (typeof l !== \"number\") return 1;\n const n = Math.trunc(l);\n if (n < 1) return 1;\n if (n > 6) return 6;\n return n as 1 | 2 | 3 | 4 | 5 | 6;\n}\n\nfunction clampListLevel(l: unknown): number {\n if (typeof l !== \"number\" || !Number.isFinite(l)) return 0;\n return Math.max(0, Math.min(5, Math.trunc(l)));\n}\n\nfunction alignFor(a: AlignValue | undefined): (typeof AlignmentType)[keyof typeof AlignmentType] | undefined {\n switch (a) {\n case \"left\":\n return AlignmentType.LEFT;\n case \"center\":\n return AlignmentType.CENTER;\n case \"right\":\n return AlignmentType.RIGHT;\n case \"justify\":\n return AlignmentType.JUSTIFIED;\n default:\n return undefined;\n }\n}\n\nfunction cssColorToDocxHex(color: string | undefined): string | undefined {\n if (!color) return undefined;\n // docx expects RRGGBB without leading '#'.\n const c = color.trim();\n if (/^#[0-9a-f]{6}$/i.test(c)) return c.slice(1).toUpperCase();\n if (/^#[0-9a-f]{3}$/i.test(c)) {\n // expand short hex\n return c\n .slice(1)\n .split(\"\")\n .map((d) => d + d)\n .join(\"\")\n .toUpperCase();\n }\n const rgb = /^rgb\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)/i.exec(c);\n if (rgb) {\n const r = Number(rgb[1]);\n const g = Number(rgb[2]);\n const b = Number(rgb[3]);\n return [r, g, b].map((n) => Math.max(0, Math.min(255, n)).toString(16).padStart(2, \"0\")).join(\"\").toUpperCase();\n }\n // Named colors / other forms — let docx fall back to default.\n return undefined;\n}\n\n/**\n * docx sizes are in half-points (24 = 12pt). Parse common CSS sizes.\n * Returns `undefined` when not parseable so callers can pick a default.\n */\nfunction parseFontSizeToHalfPoints(size: string | undefined): number | undefined {\n if (!size) return undefined;\n const s = size.trim();\n const m = /^(-?\\d*\\.?\\d+)\\s*(pt|px|em|rem)?$/i.exec(s);\n if (!m) return undefined;\n const n = Number(m[1]);\n if (!Number.isFinite(n) || n <= 0) return undefined;\n const unit = (m[2] ?? \"pt\").toLowerCase();\n const pt =\n unit === \"pt\"\n ? n\n : unit === \"px\"\n ? n * 0.75 // CSS px → pt at 96dpi\n : n * 12;\n return Math.round(pt * 2);\n}\n\n// ---------- list numbering definitions ----------\n\nfunction buildBulletLevels(): Array<{\n level: number;\n format: (typeof LevelFormat)[keyof typeof LevelFormat];\n text: string;\n alignment: (typeof AlignmentType)[keyof typeof AlignmentType];\n style?: { paragraph?: { indent?: { left: number; hanging: number } } };\n}> {\n const symbols = [\"•\", \"◦\", \"▪\", \"•\", \"◦\", \"▪\"];\n return symbols.map((sym, i) => ({\n level: i,\n format: LevelFormat.BULLET,\n text: sym,\n alignment: AlignmentType.LEFT,\n style: {\n paragraph: { indent: { left: 360 + i * 360, hanging: 260 } },\n },\n }));\n}\n\nfunction buildOrderedLevels(): Array<{\n level: number;\n format: (typeof LevelFormat)[keyof typeof LevelFormat];\n text: string;\n alignment: (typeof AlignmentType)[keyof typeof AlignmentType];\n style?: { paragraph?: { indent?: { left: number; hanging: number } } };\n}> {\n const formats = [\n LevelFormat.DECIMAL,\n LevelFormat.LOWER_LETTER,\n LevelFormat.LOWER_ROMAN,\n LevelFormat.DECIMAL,\n LevelFormat.LOWER_LETTER,\n LevelFormat.LOWER_ROMAN,\n ];\n return formats.map((format, i) => ({\n level: i,\n format,\n text: `%${i + 1}.`,\n alignment: AlignmentType.LEFT,\n style: {\n paragraph: { indent: { left: 360 + i * 360, hanging: 260 } },\n },\n }));\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/docx.ts"],"sourcesContent":["import type {\n AlignValue,\n DeltaOp,\n ImageEmbed,\n LegacySerializedDocument,\n ListKind,\n MarkAttrs,\n SerializedBlock,\n SerializedCell,\n SerializedDocument,\n TableBorderPreset,\n} from \"@sofereditor/core\";\nimport {\n DEFAULT_PAGE_SETTINGS,\n isImageEmbed,\n isLegacySerializedDocument,\n normalizarLarguras,\n pxToMm,\n type PageSettings,\n} from \"@sofereditor/core\";\nimport {\n AlignmentType,\n BorderStyle,\n Document,\n HeadingLevel,\n HeightRule,\n ImageRun,\n LevelFormat,\n LineRuleType,\n Packer,\n Paragraph,\n PageOrientation,\n ShadingType,\n Table,\n TableCell,\n TableLayoutType,\n TableRow,\n TextRun,\n UnderlineType,\n VerticalAlign,\n WidthType,\n convertMillimetersToTwip,\n} from \"docx\";\n\nconst BULLET_REF = \"ed-bullet\";\nconst ORDERED_REF = \"ed-ordered\";\n\nexport interface ResolvedImage {\n data: Uint8Array;\n type: \"png\" | \"jpg\" | \"gif\" | \"bmp\" | \"svg\";\n /**\n * Só presente quando `type === \"svg\"`: o fallback raster já decodificado,\n * exigido pelo `ImageRun` do docx para `type: \"svg\"`. Preenchido\n * internamente por `resolveAllImages` a partir do `svgFallback` do embed —\n * nunca por um `resolveImage` customizado. Fica aqui (no valor resolvido\n * por `src`, não num mapa paralelo por embed) porque é exatamente isso que\n * \"resolvido\" significa para um svg: dois embeds com o mesmo `src` — um\n * com `svgFallback`, outro sem — compartilham o mesmo `src` e portanto o\n * mesmo SVG; o fallback de qualquer um dos dois serve para ambos.\n */\n svgFallback?: { data: Uint8Array; type: Exclude<ResolvedImage[\"type\"], \"svg\"> };\n}\n\nexport interface DocumentToDocxOptions {\n /** Document title; embedded in core properties. */\n title?: string;\n /** Author for core properties. */\n creator?: string;\n /**\n * Resolve um `src` de imagem para bytes. Default: data URLs (decodificadas\n * localmente) e http(s) via fetch. Retornar null pula a imagem (contada em\n * `skippedImages`) sem abortar o export.\n */\n resolveImage?: (src: string) => Promise<ResolvedImage | null>;\n}\n\n/**\n * Build a docx `Document` from a `SerializedDocument`. Output is a Blob you can\n * download with `downloadBlob` from `@sofereditor/export-pdf`.\n *\n * Mappings:\n * - paragraph / heading / blockquote / codeBlock → Paragraph (with `heading`,\n * shading, monospace font for code)\n * - listItem → Paragraph with `numbering: { reference, level }`\n * - table → docx `Table`. `rowspan`/`colspan` map to TableCell's `rowSpan`/\n * `columnSpan`; \"covered\" cells are skipped (docx infers cover from spans)\n * - inline marks → TextRun props (bold, italics, underline, strike, color,\n * font, size in half-points)\n * - image embeds → ImageRun with bytes resolved via `resolveImage` (default:\n * data URLs decoded locally, http(s) fetched; unresolved images are\n * skipped and counted in `skippedImages` instead of aborting the export)\n */\nexport async function documentToDocxBlob(\n doc: SerializedDocument | LegacySerializedDocument,\n options: DocumentToDocxOptions = {},\n): Promise<{ blob: Blob; skippedImages: number }> {\n const normalized = normalize(doc);\n const { images, skipped } = await resolveAllImages(\n normalized,\n options.resolveImage ?? defaultResolveImage,\n );\n const built = buildDocument(normalized, options, images);\n return { blob: await Packer.toBlob(built), skippedImages: skipped };\n}\n\n/** Same as `documentToDocxBlob` but returns a Uint8Array (useful in Node/tests). */\nexport async function documentToDocxBuffer(\n doc: SerializedDocument | LegacySerializedDocument,\n options: DocumentToDocxOptions = {},\n): Promise<{ buffer: Uint8Array; skippedImages: number }> {\n const normalized = normalize(doc);\n const { images, skipped } = await resolveAllImages(\n normalized,\n options.resolveImage ?? defaultResolveImage,\n );\n const built = buildDocument(normalized, options, images);\n const buf = await Packer.toBuffer(built);\n // `Packer.toBuffer` returns a Node Buffer at runtime — coerce for consumers.\n return {\n buffer: buf instanceof Uint8Array ? buf : new Uint8Array(buf),\n skippedImages: skipped,\n };\n}\n\nfunction normalize(doc: SerializedDocument | LegacySerializedDocument): SerializedDocument {\n return isLegacySerializedDocument(doc) ? { blocks: doc } : doc;\n}\n\nfunction buildDocument(\n doc: SerializedDocument,\n options: DocumentToDocxOptions,\n images: Map<string, ResolvedImage | null>,\n): Document {\n const settings = doc.pageSettings ?? DEFAULT_PAGE_SETTINGS;\n const children = blocksToDocxChildren(doc, images, settings);\n return new Document({\n creator: options.creator,\n title: options.title,\n numbering: {\n config: [\n {\n reference: BULLET_REF,\n levels: buildBulletLevels(),\n },\n {\n reference: ORDERED_REF,\n levels: buildOrderedLevels(),\n },\n ],\n },\n sections: [\n {\n properties: sectionPropertiesFor(settings),\n children,\n },\n ],\n });\n}\n\nfunction sectionPropertiesFor(settings: PageSettings) {\n return {\n page: {\n size: {\n width: convertMillimetersToTwip(pxToMm(settings.width)),\n height: convertMillimetersToTwip(pxToMm(settings.height)),\n orientation: PageOrientation.PORTRAIT,\n },\n margin: {\n top: convertMillimetersToTwip(pxToMm(settings.marginTop)),\n bottom: convertMillimetersToTwip(pxToMm(settings.marginBottom)),\n left: convertMillimetersToTwip(pxToMm(settings.marginLeft)),\n right: convertMillimetersToTwip(pxToMm(settings.marginRight)),\n },\n },\n };\n}\n\nfunction blocksToDocxChildren(\n doc: SerializedDocument,\n images: Map<string, ResolvedImage | null>,\n settings: PageSettings,\n): Array<Paragraph | Table> {\n const out: Array<Paragraph | Table> = [];\n const blocks = doc.blocks;\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i];\n switch (block.type) {\n case \"paragraph\":\n out.push(makeParagraph(block, images));\n break;\n case \"heading\":\n out.push(makeHeading(block, images));\n break;\n case \"blockquote\":\n out.push(makeBlockquote(block, images));\n break;\n case \"codeBlock\":\n out.push(makeCodeBlock(block, images));\n break;\n case \"listItem\":\n out.push(makeListItem(block, images));\n break;\n case \"table\":\n out.push(makeTable(block, images, settings));\n break;\n default:\n out.push(makeParagraph(block, images));\n }\n }\n return out;\n}\n\n// ---------- block builders ----------\n\n// School standard: Arial for all body text. Code blocks override with\n// Consolas (monospace is more legible for code). Italics on blockquote is\n// kept as a stylistic default.\nconst ARIAL: RunDefaults = { font: \"Arial\" };\n\nfunction makeParagraph(\n block: SerializedBlock,\n images: Map<string, ResolvedImage | null>,\n): Paragraph {\n return new Paragraph({\n alignment: alignFor(block.attrs.align),\n bidirectional: block.attrs.dir === \"rtl\" ? true : undefined,\n ...answerLineProps(block.attrs),\n children: deltaToRuns(block.delta, ARIAL, images),\n });\n}\n\n/**\n * Linha de resposta → borda inferior de parágrafo (`w:pBdr`) + entrelinha.\n * É como um documento profissional desenha uma pauta: a régua acompanha a\n * margem automaticamente, ao contrário de uma fileira de underlines.\n *\n * 240 twips = uma linha simples no OOXML.\n */\nfunction answerLineProps(attrs: SerializedBlock[\"attrs\"]) {\n if (attrs.answerLine !== true) return {};\n const spacing = attrs.answerLineSpacing ?? 1;\n return {\n border: {\n bottom: { style: BorderStyle.SINGLE, size: 6, color: \"000000\", space: 1 },\n },\n spacing: { line: Math.round(240 * spacing), lineRule: LineRuleType.AUTO },\n };\n}\n\nfunction makeHeading(\n block: SerializedBlock,\n images: Map<string, ResolvedImage | null>,\n): Paragraph {\n const level = clampHeadingLevel(block.attrs.level);\n return new Paragraph({\n heading: HEADING_LEVELS[level - 1],\n alignment: alignFor(block.attrs.align),\n children: deltaToRuns(block.delta, ARIAL, images),\n });\n}\n\nfunction makeBlockquote(\n block: SerializedBlock,\n images: Map<string, ResolvedImage | null>,\n): Paragraph {\n return new Paragraph({\n alignment: alignFor(block.attrs.align),\n indent: { left: 480 }, // ~0.25\"\n border: {\n left: { color: \"CBD5E1\", space: 12, style: BorderStyle.SINGLE, size: 12 },\n },\n children: deltaToRuns(block.delta, { ...ARIAL, italics: true }, images),\n });\n}\n\nfunction makeCodeBlock(\n block: SerializedBlock,\n images: Map<string, ResolvedImage | null>,\n): Paragraph {\n return new Paragraph({\n spacing: { before: 100, after: 100 },\n shading: { type: ShadingType.CLEAR, color: \"auto\", fill: \"F1F5F9\" },\n children: deltaToRuns(block.delta, { font: \"Consolas\", size: 20 }, images),\n });\n}\n\nfunction makeListItem(\n block: SerializedBlock,\n images: Map<string, ResolvedImage | null>,\n): Paragraph {\n const kind: ListKind = block.attrs.listKind === \"ordered\" ? \"ordered\" : \"bullet\";\n const reference = kind === \"ordered\" ? ORDERED_REF : BULLET_REF;\n const level = clampListLevel(block.attrs.listLevel);\n return new Paragraph({\n numbering: { reference, level },\n alignment: alignFor(block.attrs.align),\n children: deltaToRuns(block.delta, ARIAL, images),\n });\n}\n\nfunction makeTable(\n block: SerializedBlock,\n images: Map<string, ResolvedImage | null>,\n settings: PageSettings,\n): Table {\n const rows = typeof block.attrs.rows === \"number\" ? block.attrs.rows : 0;\n const cols = typeof block.attrs.cols === \"number\" ? block.attrs.cols : 0;\n const cells = block.cells ?? [];\n const alturas = block.attrs.rowHeights;\n\n const rowsOut: TableRow[] = [];\n for (let r = 0; r < rows; r++) {\n const cellsOut: TableCell[] = [];\n for (let c = 0; c < cols; c++) {\n const cell = cells[r * cols + c];\n if (!cell) {\n cellsOut.push(emptyCell());\n continue;\n }\n if (cell.attrs?.covered) continue;\n cellsOut.push(makeCell(cell, images));\n }\n // `atLeast` e NÃO `exact`: é a mesma semântica de mínimo do editor. Com\n // `exact` o Word cortaria o conteúdo, e texto sumindo da prova é o pior\n // desfecho possível — pior que uma linha mais alta do que o pedido.\n // `Math.max(0, h)`: um documento antigo/malformado poderia trazer uma\n // entrada negativa em `rowHeights`; sem o piso, isso viraria um\n // `w:val` negativo no XML, que o Word rejeita.\n const raw = Array.isArray(alturas) && alturas.length === rows ? alturas[r] : undefined;\n const h = typeof raw === \"number\" && isFinite(raw) ? Math.max(0, raw) : undefined;\n rowsOut.push(\n new TableRow({\n children: cellsOut,\n ...(h != null\n ? { height: { value: convertMillimetersToTwip(pxToMm(h)), rule: HeightRule.ATLEAST } }\n : {}),\n }),\n );\n }\n\n // cols<=0 é uma tabela malformada (rows/cols ausentes no bloco) — sem coluna\n // nenhuma para distribuir largura, cai no fallback percentual histórico em\n // vez de produzir um `<w:gridCol w:w=\"0\"/>`.\n if (cols <= 0) {\n return new Table({\n rows: rowsOut,\n borders: docxTableBorders(block.attrs.borderPreset, block.attrs.borderColor),\n width: { size: 100, type: WidthType.PERCENTAGE },\n });\n }\n\n // Proporção contra a largura útil REAL da página — é isto que faz a tabela\n // no Word ter a mesma largura do editor. Antes convertia a soma dos px do\n // modelo (513 px numa tabela que o professor via com 600). `pageSettings`\n // vem do documento (A4/Carta/Ofício/custom) e nunca de uma constante\n // cravada, senão qualquer tamanho de página que não A4 quebraria calado.\n const larguraUtilTwips = convertMillimetersToTwip(\n pxToMm(settings.width - settings.marginLeft - settings.marginRight),\n );\n const tabelaTwips = Math.round(larguraUtilTwips * ((block.attrs.tableWidth ?? 100) / 100));\n const pct = normalizarLarguras(block.attrs.colWidths, cols);\n const columnWidths = pct.map((p) => Math.round(tabelaTwips * (p / 100)));\n\n return new Table({\n rows: rowsOut,\n borders: docxTableBorders(block.attrs.borderPreset, block.attrs.borderColor),\n columnWidths,\n // O `layout: FIXED` permanece pelo mesmo motivo de antes: sem ele o Word\n // autoajusta ao conteúdo e trata `columnWidths` como mero palpite.\n layout: TableLayoutType.FIXED,\n width: { size: columnWidths.reduce((a, b) => a + b, 0), type: WidthType.DXA },\n });\n}\n\n/**\n * Traduz o preset para `w:tblBorders`. Lado desligado = `BorderStyle.NONE`.\n *\n * A tabela-verdade sai direto de `cellBorderColors`: o que aquele helper liga em\n * TODA célula vira o par externo MAIS o interno correspondente. Ex.: em\n * `vertical`, toda célula tem left/right ligados — logo as laterais externas\n * (left/right) E as internas (insideV) ficam ligadas, e topo/base\n * (top/bottom/insideH) desligados.\n *\n * A tabela é a especificação; a função sai dela, não o contrário.\n */\nfunction docxTableBorders(preset: TableBorderPreset | undefined, color?: string) {\n // Cor inválida ou ausente cai no padrão: `cssColorToDocxHex` devolve undefined\n // para o que não souber converter.\n const hex = cssColorToDocxHex(color) ?? \"CBD5E1\";\n const on = { style: BorderStyle.SINGLE, size: 6, color: hex };\n const off = { style: BorderStyle.NONE, size: 0, color: \"auto\" };\n const s = (visivel: boolean) => (visivel ? on : off);\n\n // [top/bottom, left/right, insideH, insideV]\n const TRUTH: Record<TableBorderPreset, [boolean, boolean, boolean, boolean]> = {\n all: [true, true, true, true],\n outer: [true, true, false, false],\n horizontal: [true, false, true, false],\n vertical: [false, true, false, true],\n none: [false, false, false, false],\n };\n const [tb, lr, iH, iV] = TRUTH[preset ?? \"all\"];\n return {\n top: s(tb),\n bottom: s(tb),\n left: s(lr),\n right: s(lr),\n insideHorizontal: s(iH),\n insideVertical: s(iV),\n };\n}\n\nfunction makeCell(cell: SerializedCell, images: Map<string, ResolvedImage | null>): TableCell {\n const span = cell.attrs?.colspan && cell.attrs.colspan > 1 ? cell.attrs.colspan : 1;\n const rowSpan = cell.attrs?.rowspan && cell.attrs.rowspan > 1 ? cell.attrs.rowspan : 1;\n const fill = cssColorToDocxHex(cell.attrs?.bgColor);\n return new TableCell({\n columnSpan: span,\n rowSpan,\n verticalAlign: VerticalAlign.TOP,\n shading: fill ? { type: ShadingType.CLEAR, color: \"auto\", fill } : undefined,\n children: [\n new Paragraph({\n alignment: alignFor(cell.attrs?.align),\n children: deltaToRuns(cell.delta, ARIAL, images),\n }),\n ],\n });\n}\n\nfunction emptyCell(): TableCell {\n return new TableCell({ children: [new Paragraph(\"\")] });\n}\n\n// ---------- inline ----------\n\ninterface RunDefaults {\n bold?: boolean;\n italics?: boolean;\n font?: string;\n size?: number;\n}\n\nfunction deltaToRuns(\n delta: DeltaOp[],\n defaults: RunDefaults = {},\n images: Map<string, ResolvedImage | null>,\n): Array<TextRun | ImageRun> {\n if (delta.length === 0) return [new TextRun(\"\")];\n const out: Array<TextRun | ImageRun> = [];\n for (const op of delta) {\n if (typeof op.insert === \"string\") {\n if (op.insert.length === 0) continue;\n out.push(makeTextRun(op.insert, op.attributes, defaults));\n } else if (isImageEmbed(op.insert)) {\n const embed = op.insert;\n const img = makeImageRun(embed, images);\n if (img) out.push(img);\n // Captions are emitted as italic-smaller text on a new line right after\n // the image. Word-style \"Caption\" paragraph would need a paragraph\n // break, which we can't do mid-delta — visually correct but loses the\n // semantic \"Caption\" style.\n if (embed.caption && embed.caption.length > 0) {\n out.push(\n new TextRun({\n text: embed.caption,\n italics: true,\n size: 18, // 9pt — typical caption size\n break: 1,\n }),\n );\n }\n }\n }\n if (out.length === 0) out.push(new TextRun(\"\"));\n return out;\n}\n\n/**\n * Props de um `TextRun` a partir das marks. Fica numa função só porque\n * `makeTextRun` tem dois caminhos (linha única e multi-linha) que antes\n * duplicavam esta lista inteira — uma mark acrescentada em apenas um dos dois\n * se perdia silenciosamente em texto com quebra de linha.\n *\n * `highlight` sai como `w:shd` e NÃO como `w:highlight`: este último só aceita\n * ~15 valores nomeados e não sobreviveria a uma cor arbitrária do picker.\n */\nfunction textRunProps(text: string, m: MarkAttrs, defaults: RunDefaults) {\n const fill = cssColorToDocxHex(m.highlight);\n return {\n text,\n bold: m.bold || defaults.bold,\n italics: m.italic || defaults.italics,\n underline: m.underline ? { type: UnderlineType.SINGLE } : undefined,\n strike: m.strike,\n color: cssColorToDocxHex(m.color),\n font: m.fontFamily ?? defaults.font,\n size: parseFontSizeToHalfPoints(m.fontSize) ?? defaults.size,\n shading: fill ? { type: ShadingType.CLEAR, color: \"auto\", fill } : undefined,\n };\n}\n\nfunction makeTextRun(\n text: string,\n marks: MarkAttrs | undefined,\n defaults: RunDefaults,\n): TextRun {\n const m = marks ?? {};\n // TextRun reads newlines via `break`; convert \\n into break runs.\n const segments = text.split(\"\\n\");\n if (segments.length === 1) {\n return new TextRun(textRunProps(text, m, defaults));\n }\n // Multi-line: rejoin via TextRun children — but TextRun expects a single text\n // string. Approximate with non-printing line breaks: produce a sequence of\n // TextRuns separated by `new TextRun({ break: 1 })` packed into the parent.\n // Simpler: collapse to a single TextRun with the string, treating \\n as a\n // soft-break placeholder. Word renders \\n inside a w:t as a literal space,\n // so we replace with a small symbol-friendly fallback.\n return new TextRun(textRunProps(text.replace(/\\n/g, \" \"), m, defaults));\n}\n\nfunction makeImageRun(\n embed: ImageEmbed,\n images: Map<string, ResolvedImage | null>,\n): ImageRun | null {\n const resolved = images.get(embed.src);\n if (!resolved) return null;\n if (resolved.type === \"svg\") {\n // O fallback vem do `resolved` (por SRC), NÃO de `embed.svgFallback` (por\n // OCORRÊNCIA). Dois embeds com o mesmo src, um com svgFallback e outro\n // sem — caso real: uma prova salva antes do campo existir, com a mesma\n // fórmula inserida de novo depois — têm que resolver para o MESMO\n // ImageRun. Ler `embed.svgFallback` aqui faria a ocorrência sem fallback\n // sumir do documento sem entrar em `skippedImages`, porque\n // `resolveAllImages` já decidiu \"não pulado\" (o `src` tem fallback em\n // ALGUMA ocorrência) — o `null` devolvido aqui não seria contado.\n // `resolveAllImages` só deixa `resolved.type === \"svg\"` quando já\n // decodificou um fallback; o guarda existe porque o campo é opcional.\n if (!resolved.svgFallback) return null;\n return new ImageRun({\n type: \"svg\",\n data: resolved.data,\n fallback: { type: resolved.svgFallback.type, data: resolved.svgFallback.data },\n transformation: {\n width: Math.max(1, Math.round(embed.width)),\n height: Math.max(1, Math.round(embed.height)),\n },\n } as ConstructorParameters<typeof ImageRun>[0]);\n }\n return new ImageRun({\n data: resolved.data,\n type: resolved.type,\n transformation: {\n width: Math.max(1, Math.round(embed.width)),\n height: Math.max(1, Math.round(embed.height)),\n },\n } as ConstructorParameters<typeof ImageRun>[0]);\n}\n\ninterface DecodedImage {\n bytes: Uint8Array;\n kind: \"png\" | \"jpg\" | \"gif\" | \"bmp\" | \"svg\";\n}\n\nfunction decodeDataUrl(src: string): DecodedImage | null {\n const m = /^data:image\\/(png|jpe?g|gif|bmp|svg\\+xml);base64,(.+)$/i.exec(src);\n if (!m) return null;\n const fmt = m[1].toLowerCase();\n const kind: DecodedImage[\"kind\"] =\n fmt === \"jpeg\" || fmt === \"jpg\"\n ? \"jpg\"\n : fmt === \"svg+xml\"\n ? \"svg\"\n : (fmt as \"png\" | \"gif\" | \"bmp\");\n const base64 = m[2];\n const bytes = base64ToBytes(base64);\n return { bytes, kind };\n}\n\n/**\n * Default `resolveImage`: decode data URLs locally, fetch http(s) URLs, and\n * return null for anything else (caller counts it in `skippedImages`).\n */\nasync function defaultResolveImage(src: string): Promise<ResolvedImage | null> {\n const decoded = decodeDataUrl(src);\n if (decoded) return { data: decoded.bytes, type: decoded.kind };\n if (/^https?:\\/\\//i.test(src) && typeof fetch === \"function\") {\n try {\n const res = await fetch(src);\n if (!res.ok) return null;\n const ct = (res.headers.get(\"content-type\") ?? \"\").toLowerCase();\n const matchedType: ResolvedImage[\"type\"] | null = ct.includes(\"png\")\n ? \"png\"\n : ct.includes(\"jpeg\") || ct.includes(\"jpg\")\n ? \"jpg\"\n : ct.includes(\"gif\")\n ? \"gif\"\n : ct.includes(\"bmp\")\n ? \"bmp\"\n : ct.includes(\"svg\")\n ? \"svg\"\n : null;\n // Unknown content-type (e.g. image/webp) with no recognizable extension\n // in the URL: skip rather than mislabeling bytes as PNG (would produce\n // a broken image in Word — contract is \"failure to resolve → skip\").\n const type = matchedType ?? typeFromExtension(src);\n if (!type) return null;\n return { data: new Uint8Array(await res.arrayBuffer()), type };\n } catch {\n return null;\n }\n }\n return null;\n}\n\nfunction typeFromExtension(src: string): ResolvedImage[\"type\"] | null {\n const m = /\\.(png|jpe?g|gif|bmp|svg)(\\?|#|$)/i.exec(src);\n if (!m) return null;\n const ext = m[1].toLowerCase();\n return ext === \"jpeg\" || ext === \"jpg\" ? \"jpg\" : (ext as ResolvedImage[\"type\"]);\n}\n\n/**\n * Async pre-pass: collect every image `src` referenced by the document\n * (block deltas and table cell deltas), resolve them in parallel via\n * `resolve`, and return a lookup map plus the count of embeds that failed to\n * resolve. The rest of the build pipeline stays synchronous and reads from\n * this map.\n */\nasync function resolveAllImages(\n doc: SerializedDocument,\n resolve: (src: string) => Promise<ResolvedImage | null>,\n): Promise<{ images: Map<string, ResolvedImage | null>; skipped: number }> {\n const srcs = new Set<string>();\n // svgFallback é campo do EMBED e o mapa de resolução é por SRC. Colher no\n // mesmo passo evita um segundo percurso do documento. Dois embeds com o\n // mesmo src e fallbacks diferentes é caso que não existe na prática (o src\n // é o próprio conteúdo em data URL); o primeiro ganha.\n const fallbacks = new Map<string, string>();\n const collect = (delta: DeltaOp[]) => {\n for (const op of delta) {\n if (!isImageEmbed(op.insert)) continue;\n srcs.add(op.insert.src);\n const fb = op.insert.svgFallback;\n if (fb && !fallbacks.has(op.insert.src)) fallbacks.set(op.insert.src, fb);\n }\n };\n for (const block of doc.blocks) {\n collect(block.delta);\n for (const cell of block.cells ?? []) collect(cell.delta);\n }\n const images = new Map<string, ResolvedImage | null>();\n await Promise.all(\n [...srcs].map(async (src) => {\n let resolved: ResolvedImage | null = null;\n try {\n resolved = await resolve(src);\n } catch {\n resolved = null;\n }\n // docx's ImageRun requires a `fallback` for type \"svg\" (RegularImageOptions);\n // without it the constructor throws synchronously inside buildDocument,\n // which is outside this try/catch and would abort the whole export. SVG\n // deixa de ser descartado: o ImageRun aceita `type: \"svg\"` desde que\n // receba um `fallback` raster. Quem tem `svgFallback` passa; quem não\n // tem continua sendo pulado AQUI, para que `skipped` conte certo — não\n // inventamos um raster no servidor. O fallback é decodificado AQUI (uma\n // vez por src, não por embed) e guardado dentro do próprio\n // `ResolvedImage` — é isso que faz o \"primeiro ganha\" valer para toda\n // ocorrência do mesmo src, mesmo a que não trouxe `svgFallback`.\n if (resolved?.type === \"svg\") {\n const fb = fallbacks.get(src);\n const decodedFb = fb ? decodeDataUrl(fb) : null;\n // Um fallback com `kind === \"svg\"` não é fallback nenhum — é o\n // mesmo SVG de novo (`ImageRun({ type: \"svg\", fallback: { type:\n // \"svg\" } })` não tem sentido pro docx, que exige um raster aqui).\n // Na prática `fb` sempre vem de `svgToPngDataUrl` (sempre PNG), mas\n // `decodeDataUrl` é genérico; tratamos esse caso como \"sem\n // fallback válido\" em vez de deixar o tipo mentir.\n resolved =\n decodedFb && decodedFb.kind !== \"svg\"\n ? { ...resolved, svgFallback: { data: decodedFb.bytes, type: decodedFb.kind } }\n : null;\n }\n images.set(src, resolved);\n }),\n );\n // skipped conta OCORRÊNCIAS de embed sem resolução (não srcs únicos).\n let skipped = 0;\n const count = (delta: DeltaOp[]) => {\n for (const op of delta)\n if (isImageEmbed(op.insert) && !images.get(op.insert.src)) skipped++;\n };\n for (const block of doc.blocks) {\n count(block.delta);\n for (const cell of block.cells ?? []) count(cell.delta);\n }\n return { images, skipped };\n}\n\nfunction base64ToBytes(b64: string): Uint8Array {\n if (typeof atob === \"function\") {\n const bin = atob(b64);\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\n return out;\n }\n // Node fallback.\n return new Uint8Array(Buffer.from(b64, \"base64\"));\n}\n\n// ---------- attribute mapping ----------\n\nconst HEADING_LEVELS = [\n HeadingLevel.HEADING_1,\n HeadingLevel.HEADING_2,\n HeadingLevel.HEADING_3,\n HeadingLevel.HEADING_4,\n HeadingLevel.HEADING_5,\n HeadingLevel.HEADING_6,\n];\n\nfunction clampHeadingLevel(l: unknown): 1 | 2 | 3 | 4 | 5 | 6 {\n if (typeof l !== \"number\") return 1;\n const n = Math.trunc(l);\n if (n < 1) return 1;\n if (n > 6) return 6;\n return n as 1 | 2 | 3 | 4 | 5 | 6;\n}\n\nfunction clampListLevel(l: unknown): number {\n if (typeof l !== \"number\" || !Number.isFinite(l)) return 0;\n return Math.max(0, Math.min(5, Math.trunc(l)));\n}\n\nfunction alignFor(a: AlignValue | undefined): (typeof AlignmentType)[keyof typeof AlignmentType] | undefined {\n switch (a) {\n case \"left\":\n return AlignmentType.LEFT;\n case \"center\":\n return AlignmentType.CENTER;\n case \"right\":\n return AlignmentType.RIGHT;\n case \"justify\":\n return AlignmentType.JUSTIFIED;\n default:\n return undefined;\n }\n}\n\nfunction cssColorToDocxHex(color: string | undefined): string | undefined {\n if (!color) return undefined;\n // docx expects RRGGBB without leading '#'.\n const c = color.trim();\n if (/^#[0-9a-f]{6}$/i.test(c)) return c.slice(1).toUpperCase();\n if (/^#[0-9a-f]{3}$/i.test(c)) {\n // expand short hex\n return c\n .slice(1)\n .split(\"\")\n .map((d) => d + d)\n .join(\"\")\n .toUpperCase();\n }\n const rgb = /^rgb\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)/i.exec(c);\n if (rgb) {\n const r = Number(rgb[1]);\n const g = Number(rgb[2]);\n const b = Number(rgb[3]);\n return [r, g, b].map((n) => Math.max(0, Math.min(255, n)).toString(16).padStart(2, \"0\")).join(\"\").toUpperCase();\n }\n // Named colors / other forms — let docx fall back to default.\n return undefined;\n}\n\n/**\n * docx sizes are in half-points (24 = 12pt). Parse common CSS sizes.\n * Returns `undefined` when not parseable so callers can pick a default.\n */\nfunction parseFontSizeToHalfPoints(size: string | undefined): number | undefined {\n if (!size) return undefined;\n const s = size.trim();\n const m = /^(-?\\d*\\.?\\d+)\\s*(pt|px|em|rem)?$/i.exec(s);\n if (!m) return undefined;\n const n = Number(m[1]);\n if (!Number.isFinite(n) || n <= 0) return undefined;\n const unit = (m[2] ?? \"pt\").toLowerCase();\n const pt =\n unit === \"pt\"\n ? n\n : unit === \"px\"\n ? n * 0.75 // CSS px → pt at 96dpi\n : n * 12;\n return Math.round(pt * 2);\n}\n\n// ---------- list numbering definitions ----------\n\nfunction buildBulletLevels(): Array<{\n level: number;\n format: (typeof LevelFormat)[keyof typeof LevelFormat];\n text: string;\n alignment: (typeof AlignmentType)[keyof typeof AlignmentType];\n style?: { paragraph?: { indent?: { left: number; hanging: number } } };\n}> {\n const symbols = [\"•\", \"◦\", \"▪\", \"•\", \"◦\", \"▪\"];\n return symbols.map((sym, i) => ({\n level: i,\n format: LevelFormat.BULLET,\n text: sym,\n alignment: AlignmentType.LEFT,\n style: {\n paragraph: { indent: { left: 360 + i * 360, hanging: 260 } },\n },\n }));\n}\n\nfunction buildOrderedLevels(): Array<{\n level: number;\n format: (typeof LevelFormat)[keyof typeof LevelFormat];\n text: string;\n alignment: (typeof AlignmentType)[keyof typeof AlignmentType];\n style?: { paragraph?: { indent?: { left: number; hanging: number } } };\n}> {\n const formats = [\n LevelFormat.DECIMAL,\n LevelFormat.LOWER_LETTER,\n LevelFormat.LOWER_ROMAN,\n LevelFormat.DECIMAL,\n LevelFormat.LOWER_LETTER,\n LevelFormat.LOWER_ROMAN,\n ];\n return formats.map((format, i) => ({\n level: i,\n format,\n text: `%${i + 1}.`,\n alignment: AlignmentType.LEFT,\n style: {\n paragraph: { indent: { left: 360 + i * 360, hanging: 260 } },\n },\n }));\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sofereditor/export-docx",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "@sofereditor/export-docx — Emit .docx from a Sofer SerializedDocument. Round-trip with @sofereditor/import-docx.",
|
|
5
5
|
"license": "AGPL-3.0-or-later",
|
|
6
6
|
"author": "Rafael Marreca",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"test": "vitest run"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@sofereditor/core": "^0.
|
|
56
|
+
"@sofereditor/core": "^0.9.0",
|
|
57
57
|
"docx": "^9.6.1"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|