@sofereditor/export-docx 0.3.3 → 0.3.4
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 +3 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -308,7 +308,9 @@ async function defaultResolveImage(src) {
|
|
|
308
308
|
const res = await fetch(src);
|
|
309
309
|
if (!res.ok) return null;
|
|
310
310
|
const ct = (res.headers.get("content-type") ?? "").toLowerCase();
|
|
311
|
-
const
|
|
311
|
+
const matchedType = ct.includes("png") ? "png" : ct.includes("jpeg") || ct.includes("jpg") ? "jpg" : ct.includes("gif") ? "gif" : ct.includes("bmp") ? "bmp" : ct.includes("svg") ? "svg" : null;
|
|
312
|
+
const type = matchedType ?? typeFromExtension(src);
|
|
313
|
+
if (!type) return null;
|
|
312
314
|
return { data: new Uint8Array(await res.arrayBuffer()), type };
|
|
313
315
|
} catch {
|
|
314
316
|
return null;
|
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} 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 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 children: deltaToRuns(block.delta, ARIAL, images),\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 ...(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\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\nfunction makeTextRun(\n text: string,\n marks: MarkAttrs | undefined,\n defaults: RunDefaults,\n): TextRun {\n const m = marks ?? {};\n const fontSize = parseFontSizeToHalfPoints(m.fontSize);\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({\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: fontSize ?? defaults.size,\n });\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({\n text: text.replace(/\\n/g, \" \"),\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: fontSize ?? defaults.size,\n });\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 type: ResolvedImage[\"type\"] = 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 : (typeFromExtension(src) ?? \"png\");\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} 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 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 children: deltaToRuns(block.delta, ARIAL, images),\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 ...(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\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\nfunction makeTextRun(\n text: string,\n marks: MarkAttrs | undefined,\n defaults: RunDefaults,\n): TextRun {\n const m = marks ?? {};\n const fontSize = parseFontSizeToHalfPoints(m.fontSize);\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({\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: fontSize ?? defaults.size,\n });\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({\n text: text.replace(/\\n/g, \" \"),\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: fontSize ?? defaults.size,\n });\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":[]}
|
package/dist/index.js
CHANGED
|
@@ -306,7 +306,9 @@ async function defaultResolveImage(src) {
|
|
|
306
306
|
const res = await fetch(src);
|
|
307
307
|
if (!res.ok) return null;
|
|
308
308
|
const ct = (res.headers.get("content-type") ?? "").toLowerCase();
|
|
309
|
-
const
|
|
309
|
+
const matchedType = ct.includes("png") ? "png" : ct.includes("jpeg") || ct.includes("jpg") ? "jpg" : ct.includes("gif") ? "gif" : ct.includes("bmp") ? "bmp" : ct.includes("svg") ? "svg" : null;
|
|
310
|
+
const type = matchedType ?? typeFromExtension(src);
|
|
311
|
+
if (!type) return null;
|
|
310
312
|
return { data: new Uint8Array(await res.arrayBuffer()), type };
|
|
311
313
|
} catch {
|
|
312
314
|
return null;
|
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} 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 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 children: deltaToRuns(block.delta, ARIAL, images),\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 ...(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\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\nfunction makeTextRun(\n text: string,\n marks: MarkAttrs | undefined,\n defaults: RunDefaults,\n): TextRun {\n const m = marks ?? {};\n const fontSize = parseFontSizeToHalfPoints(m.fontSize);\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({\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: fontSize ?? defaults.size,\n });\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({\n text: text.replace(/\\n/g, \" \"),\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: fontSize ?? defaults.size,\n });\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 type: ResolvedImage[\"type\"] = 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 : (typeFromExtension(src) ?? \"png\");\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} 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 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 children: deltaToRuns(block.delta, ARIAL, images),\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 ...(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\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\nfunction makeTextRun(\n text: string,\n marks: MarkAttrs | undefined,\n defaults: RunDefaults,\n): TextRun {\n const m = marks ?? {};\n const fontSize = parseFontSizeToHalfPoints(m.fontSize);\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({\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: fontSize ?? defaults.size,\n });\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({\n text: text.replace(/\\n/g, \" \"),\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: fontSize ?? defaults.size,\n });\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":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sofereditor/export-docx",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
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",
|