@sofereditor/import-docx 0.3.2 → 0.3.3
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 +74 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +74 -4
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -378,6 +378,10 @@ function paragraphToBlock(p, ctx, numbering) {
|
|
|
378
378
|
listKind: resolved?.listKind ?? "bullet",
|
|
379
379
|
listLevel: resolved?.listLevel ?? 0
|
|
380
380
|
};
|
|
381
|
+
if (resolved?.listKind === "ordered") {
|
|
382
|
+
if (resolved.ordinal != null) attrs2.listStart = resolved.ordinal;
|
|
383
|
+
if (resolved.listStyle) attrs2.listStyle = resolved.listStyle;
|
|
384
|
+
}
|
|
381
385
|
if (align) attrs2.align = align;
|
|
382
386
|
if (isRtl) attrs2.dir = "rtl";
|
|
383
387
|
return { type: "listItem", text, delta, attrs: attrs2 };
|
|
@@ -533,9 +537,19 @@ function emptyCell() {
|
|
|
533
537
|
}
|
|
534
538
|
|
|
535
539
|
// src/numbering.ts
|
|
540
|
+
var FMT_TO_LIST_STYLE = {
|
|
541
|
+
decimal: "decimal",
|
|
542
|
+
lowerLetter: "lower-alpha",
|
|
543
|
+
upperLetter: "upper-alpha",
|
|
544
|
+
lowerRoman: "lower-roman",
|
|
545
|
+
upperRoman: "upper-roman"
|
|
546
|
+
};
|
|
536
547
|
var NumberingResolver = class {
|
|
537
548
|
numIdToAbstract = /* @__PURE__ */ new Map();
|
|
538
549
|
abstractLevelFmt = /* @__PURE__ */ new Map();
|
|
550
|
+
abstractLevelStart = /* @__PURE__ */ new Map();
|
|
551
|
+
/** Contadores vivos por instância de lista (numId), indexados por nível. */
|
|
552
|
+
counters = /* @__PURE__ */ new Map();
|
|
539
553
|
constructor(numberingXml) {
|
|
540
554
|
if (!numberingXml) return;
|
|
541
555
|
for (const top of numberingXml) {
|
|
@@ -546,12 +560,16 @@ var NumberingResolver = class {
|
|
|
546
560
|
const abstractId = attr(child, "w:abstractNumId");
|
|
547
561
|
if (!abstractId) continue;
|
|
548
562
|
const levels = /* @__PURE__ */ new Map();
|
|
563
|
+
const starts = /* @__PURE__ */ new Map();
|
|
549
564
|
for (const lvl of findChildren(child, "w:lvl")) {
|
|
550
565
|
const ilvl = parseIntAttr(attr(lvl, "w:ilvl"), 0);
|
|
551
566
|
const fmt = attr(findChild(lvl, "w:numFmt") ?? {}, "w:val");
|
|
552
567
|
if (fmt) levels.set(ilvl, fmt);
|
|
568
|
+
const start = findChild(lvl, "w:start");
|
|
569
|
+
if (start) starts.set(ilvl, parseIntAttr(attr(start, "w:val"), 1));
|
|
553
570
|
}
|
|
554
571
|
this.abstractLevelFmt.set(abstractId, levels);
|
|
572
|
+
this.abstractLevelStart.set(abstractId, starts);
|
|
555
573
|
} else if (tag === "w:num") {
|
|
556
574
|
const numId = attr(child, "w:numId");
|
|
557
575
|
const abstractRef = findChild(child, "w:abstractNumId");
|
|
@@ -561,7 +579,12 @@ var NumberingResolver = class {
|
|
|
561
579
|
}
|
|
562
580
|
}
|
|
563
581
|
}
|
|
564
|
-
/**
|
|
582
|
+
/**
|
|
583
|
+
* Resolves a paragraph's `<w:numPr>` into `{listKind, listLevel, ordinal?,
|
|
584
|
+
* listStyle?}`, or null. STATEFUL for ordered lists: each call advances the
|
|
585
|
+
* per-`numId` counter (Word instance semantics) — call exactly once per
|
|
586
|
+
* numbered paragraph, in document order.
|
|
587
|
+
*/
|
|
565
588
|
resolve(numPr) {
|
|
566
589
|
if (!numPr) return null;
|
|
567
590
|
const ilvlRef = findChild(numPr, "w:ilvl");
|
|
@@ -575,9 +598,21 @@ var NumberingResolver = class {
|
|
|
575
598
|
return { listKind: "bullet", listLevel };
|
|
576
599
|
}
|
|
577
600
|
const levels = this.abstractLevelFmt.get(abstractId);
|
|
578
|
-
const fmt =
|
|
579
|
-
const
|
|
580
|
-
|
|
601
|
+
const fmt = levels?.get(listLevel) ?? "bullet";
|
|
602
|
+
const fmtLower = fmt.toLowerCase();
|
|
603
|
+
const listKind = fmtLower === "bullet" || fmtLower === "none" ? "bullet" : "ordered";
|
|
604
|
+
if (listKind === "bullet") return { listKind, listLevel };
|
|
605
|
+
const start = this.abstractLevelStart.get(abstractId)?.get(listLevel) ?? 1;
|
|
606
|
+
const c = this.counters.get(numId) ?? [];
|
|
607
|
+
c[listLevel] = c[listLevel] == null ? start : c[listLevel] + 1;
|
|
608
|
+
c.length = listLevel + 1;
|
|
609
|
+
this.counters.set(numId, c);
|
|
610
|
+
return {
|
|
611
|
+
listKind,
|
|
612
|
+
listLevel,
|
|
613
|
+
ordinal: c[listLevel],
|
|
614
|
+
listStyle: FMT_TO_LIST_STYLE[fmt] ?? "decimal"
|
|
615
|
+
};
|
|
581
616
|
}
|
|
582
617
|
};
|
|
583
618
|
function clampLevel(n) {
|
|
@@ -641,9 +676,44 @@ async function docxBlobToDocument(input) {
|
|
|
641
676
|
if (blocks.length === 0) {
|
|
642
677
|
blocks.push({ type: "paragraph", text: "", delta: [], attrs: {} });
|
|
643
678
|
}
|
|
679
|
+
pruneNonLeaderListStarts(blocks);
|
|
644
680
|
const pageSettings = sectPrToPageSettings(findChild(body, "w:sectPr"));
|
|
645
681
|
return pageSettings ? { blocks, pageSettings } : { blocks };
|
|
646
682
|
}
|
|
683
|
+
function pruneNonLeaderListStarts(blocks) {
|
|
684
|
+
let grupoAtivo = false;
|
|
685
|
+
let grupoStyle;
|
|
686
|
+
let ordinais = [];
|
|
687
|
+
const resetGrupo = () => {
|
|
688
|
+
grupoAtivo = false;
|
|
689
|
+
grupoStyle = void 0;
|
|
690
|
+
ordinais = [];
|
|
691
|
+
};
|
|
692
|
+
for (const block of blocks) {
|
|
693
|
+
if (block.type !== "listItem") {
|
|
694
|
+
resetGrupo();
|
|
695
|
+
continue;
|
|
696
|
+
}
|
|
697
|
+
if ((block.attrs.listKind ?? "bullet") !== "ordered") {
|
|
698
|
+
resetGrupo();
|
|
699
|
+
continue;
|
|
700
|
+
}
|
|
701
|
+
const level = block.attrs.listLevel ?? 0;
|
|
702
|
+
const ordinal = typeof block.attrs.listStart === "number" ? block.attrs.listStart : 1;
|
|
703
|
+
const mesmoNivelSequencial = ordinais[level] != null && ordinal === ordinais[level] + 1;
|
|
704
|
+
const entrandoEmNivelNovo = ordinais[level] == null && level > 0 && ordinal === 1;
|
|
705
|
+
const continuaGrupo = grupoAtivo && block.attrs.listStyle === grupoStyle && (mesmoNivelSequencial || entrandoEmNivelNovo);
|
|
706
|
+
if (continuaGrupo) {
|
|
707
|
+
delete block.attrs.listStart;
|
|
708
|
+
} else {
|
|
709
|
+
grupoAtivo = true;
|
|
710
|
+
grupoStyle = block.attrs.listStyle;
|
|
711
|
+
ordinais = [];
|
|
712
|
+
}
|
|
713
|
+
ordinais[level] = ordinal;
|
|
714
|
+
ordinais.length = level + 1;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
647
717
|
async function docxBlobToEditorDocument(input) {
|
|
648
718
|
const serialized = await docxBlobToDocument(input);
|
|
649
719
|
return import_core2.EditorDocument.fromJSON(serialized);
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/docx.ts","../src/parse-xml.ts","../src/units.ts","../src/images.ts","../src/runs.ts","../src/paragraphs.ts","../src/tables.ts","../src/numbering.ts","../src/page-settings.ts"],"sourcesContent":["export { docxBlobToDocument, docxBlobToEditorDocument } from \"./docx\";\n","import { EditorDocument, type SerializedBlock, type SerializedDocument } from \"@sofereditor/core\";\nimport { readDocx, childrenOf, tagOf, findChild, type OoxmlNode } from \"./parse-xml\";\nimport { paragraphToBlock } from \"./paragraphs\";\nimport { tableToBlock } from \"./tables\";\nimport { NumberingResolver } from \"./numbering\";\nimport { sectPrToPageSettings } from \"./page-settings\";\nimport type { RunContext } from \"./runs\";\n\n/**\n * Read a `.docx` (OOXML) Blob/ArrayBuffer/Uint8Array and produce a\n * `SerializedDocument` ready to feed `EditorDocument.fromJSON` (or\n * `loadFromJSON` on an existing instance).\n *\n * The mapping is the inverse of `@sofereditor/export-docx`. Round-trip is exact for\n * documents the editor produced; documents authored externally (Word, Google\n * Docs export) load with marks/lists/tables/images recognized and unsupported\n * features dropped silently.\n */\nexport async function docxBlobToDocument(\n input: Blob | ArrayBuffer | Uint8Array,\n): Promise<SerializedDocument> {\n const file = await readDocx(input);\n const numbering = new NumberingResolver(file.numberingXml);\n const ctx: RunContext = {\n relationships: file.relationships,\n mediaBytes: file.mediaBytes,\n };\n\n const body = findBody(file.documentXml);\n if (!body) return { blocks: [{ type: \"paragraph\", text: \"\", delta: [], attrs: {} }] };\n\n const blocks: SerializedBlock[] = [];\n for (const child of childrenOf(body)) {\n const tag = tagOf(child);\n if (tag === \"w:p\") {\n blocks.push(paragraphToBlock(child, ctx, numbering));\n } else if (tag === \"w:tbl\") {\n blocks.push(tableToBlock(child, ctx));\n }\n // w:sectPr is parsed below (page settings); other body-level metadata ignored.\n }\n\n if (blocks.length === 0) {\n blocks.push({ type: \"paragraph\", text: \"\", delta: [], attrs: {} });\n }\n\n const pageSettings = sectPrToPageSettings(findChild(body, \"w:sectPr\"));\n return pageSettings ? { blocks, pageSettings } : { blocks };\n}\n\n/** Convenience: parse → instantiate a fresh `EditorDocument`. */\nexport async function docxBlobToEditorDocument(\n input: Blob | ArrayBuffer | Uint8Array,\n): Promise<EditorDocument> {\n const serialized = await docxBlobToDocument(input);\n return EditorDocument.fromJSON(serialized);\n}\n\nfunction findBody(documentXml: OoxmlNode[]): OoxmlNode | undefined {\n for (const top of documentXml) {\n if (tagOf(top) === \"w:document\") {\n const body = findChild(top, \"w:body\");\n if (body) return body;\n }\n }\n return undefined;\n}\n","import JSZip from \"jszip\";\nimport { XMLParser } from \"fast-xml-parser\";\n\n/**\n * fast-xml-parser with `preserveOrder: true` produces a list of single-key\n * objects per element. Each element is either:\n *\n * - A tag node: `{ \"<tagName>\": <children-array>, \":@\"?: <attrs> }`\n * - A text node: `{ \"#text\": <string> }`\n *\n * Attributes are prefixed with `@_`. The `:@` key holds attributes for the\n * surrounding tag. Children preserve original document order, which matters\n * for paragraph runs (bold word followed by italic word).\n */\nexport type OoxmlNode = Record<string, unknown>;\n\nconst parser = new XMLParser({\n ignoreAttributes: false,\n attributeNamePrefix: \"@_\",\n preserveOrder: true,\n trimValues: false, // keep whitespace inside <w:t>\n parseAttributeValue: false,\n parseTagValue: false,\n});\n\nexport interface DocxFile {\n documentXml: OoxmlNode[];\n numberingXml?: OoxmlNode[];\n /** rId → target path (inside the zip), e.g. \"media/image1.png\". */\n relationships: Map<string, string>;\n /** zip path (without leading \"word/\") → bytes for embedded media. */\n mediaBytes: Map<string, Uint8Array>;\n}\n\nexport async function readDocx(input: Blob | ArrayBuffer | Uint8Array): Promise<DocxFile> {\n const data =\n input instanceof Uint8Array\n ? input\n : input instanceof ArrayBuffer\n ? new Uint8Array(input)\n : new Uint8Array(await (input as Blob).arrayBuffer());\n\n const zip = await JSZip.loadAsync(data);\n const documentXml = await readXml(zip, \"word/document.xml\");\n if (!documentXml) throw new Error(\"Invalid .docx: missing word/document.xml\");\n\n const numberingXml = await readXml(zip, \"word/numbering.xml\");\n const relsXml = await readXml(zip, \"word/_rels/document.xml.rels\");\n const relationships = parseRelationships(relsXml);\n\n const mediaBytes = new Map<string, Uint8Array>();\n const mediaFolder = zip.folder(\"word/media\");\n if (mediaFolder) {\n const promises: Promise<void>[] = [];\n mediaFolder.forEach((relativePath, file) => {\n if (file.dir) return;\n promises.push(\n file.async(\"uint8array\").then((bytes) => {\n mediaBytes.set(`media/${relativePath}`, bytes);\n }),\n );\n });\n await Promise.all(promises);\n }\n\n return { documentXml, numberingXml, relationships, mediaBytes };\n}\n\nasync function readXml(zip: JSZip, path: string): Promise<OoxmlNode[] | undefined> {\n const entry = zip.file(path);\n if (!entry) return undefined;\n const text = await entry.async(\"string\");\n return parser.parse(text) as OoxmlNode[];\n}\n\nfunction parseRelationships(nodes: OoxmlNode[] | undefined): Map<string, string> {\n const out = new Map<string, string>();\n if (!nodes) return out;\n // <Relationships><Relationship Id=\"rId1\" Type=\"...\" Target=\"media/image1.png\"/>...\n for (const top of nodes) {\n const children = top[\"Relationships\"];\n if (!Array.isArray(children)) continue;\n for (const child of children as OoxmlNode[]) {\n if (!(\"Relationship\" in child)) continue;\n const attrs = (child[\":@\"] ?? {}) as Record<string, unknown>;\n const id = attrs[\"@_Id\"];\n const target = attrs[\"@_Target\"];\n if (typeof id === \"string\" && typeof target === \"string\") {\n out.set(id, target);\n }\n }\n }\n return out;\n}\n\n// ---------- generic walkers over preserveOrder shape ----------\n\n/** Returns the tag name (e.g. \"w:p\") of a preserveOrder element, or null for text. */\nexport function tagOf(node: OoxmlNode): string | null {\n for (const key of Object.keys(node)) {\n if (key === \":@\") continue;\n return key;\n }\n return null;\n}\n\n/** Returns the children array of an element, or [] when none. */\nexport function childrenOf(node: OoxmlNode): OoxmlNode[] {\n const tag = tagOf(node);\n if (!tag) return [];\n const v = node[tag];\n return Array.isArray(v) ? (v as OoxmlNode[]) : [];\n}\n\n/** Returns the attribute bag (already with `@_` prefix) for an element. */\nexport function attrsOf(node: OoxmlNode): Record<string, unknown> {\n return ((node[\":@\"] ?? {}) as Record<string, unknown>) ?? {};\n}\n\n/** Read a single `@_key` attribute as a string. */\nexport function attr(node: OoxmlNode, key: string): string | undefined {\n const v = attrsOf(node)[`@_${key}`];\n return typeof v === \"string\" ? v : undefined;\n}\n\n/** Find the first direct child with the given tag name. */\nexport function findChild(node: OoxmlNode, tag: string): OoxmlNode | undefined {\n for (const child of childrenOf(node)) {\n if (tagOf(child) === tag) return child;\n }\n return undefined;\n}\n\n/** Find all direct children with the given tag name. */\nexport function findChildren(node: OoxmlNode, tag: string): OoxmlNode[] {\n const out: OoxmlNode[] = [];\n for (const child of childrenOf(node)) {\n if (tagOf(child) === tag) out.push(child);\n }\n return out;\n}\n\n/** Recursively collect text nodes' concatenated content. */\nexport function textOf(node: OoxmlNode): string {\n let out = \"\";\n for (const child of childrenOf(node)) {\n if (\"#text\" in child) {\n const t = child[\"#text\"];\n if (typeof t === \"string\") out += t;\n } else {\n out += textOf(child);\n }\n }\n return out;\n}\n","/**\n * Unit conversions between OOXML and the editor's serialized format.\n * These are the inverses of the helpers in `@sofereditor/export-docx/src/docx.ts`.\n */\n\n/** docx half-points → CSS pt string. 24 (half-pt) → \"12pt\". */\nexport function halfPointsToCssPt(halfPoints: number): string | undefined {\n if (!Number.isFinite(halfPoints) || halfPoints <= 0) return undefined;\n const pt = halfPoints / 2;\n return `${stripTrailingZeros(pt)}pt`;\n}\n\n/** OOXML RRGGBB (no '#') → CSS hex with leading '#'. */\nexport function docxHexToCssColor(hex: string | undefined): string | undefined {\n if (!hex) return undefined;\n const m = /^[0-9a-f]{6}$/i.exec(hex.trim());\n if (!m) return undefined;\n return `#${hex.toLowerCase()}`;\n}\n\n/** OOXML alignment value → editor AlignValue. */\nexport function parseAlign(val: string | undefined): \"left\" | \"center\" | \"right\" | \"justify\" | undefined {\n if (!val) return undefined;\n switch (val.toLowerCase()) {\n case \"left\":\n case \"start\":\n return \"left\";\n case \"center\":\n return \"center\";\n case \"right\":\n case \"end\":\n return \"right\";\n case \"both\":\n case \"distribute\":\n case \"justify\":\n return \"justify\";\n default:\n return undefined;\n }\n}\n\n/** Parse XML attribute that should be a positive integer. */\nexport function parseIntAttr(val: unknown, fallback = 0): number {\n if (typeof val === \"number\" && Number.isFinite(val)) return Math.trunc(val);\n if (typeof val !== \"string\") return fallback;\n const n = Number.parseInt(val, 10);\n return Number.isFinite(n) ? n : fallback;\n}\n\nfunction stripTrailingZeros(n: number): string {\n // 12 → \"12\", 12.5 → \"12.5\"\n return Number.isInteger(n) ? n.toString() : n.toFixed(2).replace(/\\.?0+$/, \"\");\n}\n","import type { ImageEmbed } from \"@sofereditor/core\";\nimport { attr, childrenOf, tagOf, type OoxmlNode } from \"./parse-xml\";\nimport { parseIntAttr } from \"./units\";\n\n/** 1 inch = 914400 EMU = 96 px → 1 px = 9525 EMU. */\nconst EMU_PER_PX = 9525;\n\nconst MIME_BY_EXT: Record<string, string> = {\n png: \"image/png\",\n jpg: \"image/jpeg\",\n jpeg: \"image/jpeg\",\n gif: \"image/gif\",\n bmp: \"image/bmp\",\n svg: \"image/svg+xml\",\n};\n\nexport interface ImageContext {\n relationships: Map<string, string>;\n mediaBytes: Map<string, Uint8Array>;\n}\n\n/**\n * Walk a `<w:drawing>` node and return an `ImageEmbed` if it contains a\n * recognized inline picture. Returns null for unsupported drawings (shapes,\n * charts, etc.).\n */\nexport function extractImageFromDrawing(\n drawing: OoxmlNode,\n ctx: ImageContext,\n): ImageEmbed | null {\n // The interesting bits live deep inside: a:blip carries `r:embed`, and\n // wp:extent carries cx/cy. We do a generic walk because the wrapping nodes\n // differ between inline (`wp:inline`) and anchored (`wp:anchor`) drawings.\n let embedId: string | undefined;\n let cx: number | undefined;\n let cy: number | undefined;\n\n walk(drawing, (n) => {\n const tag = tagOf(n);\n if (!tag) return;\n if (tag === \"a:blip\") {\n const id = attr(n, \"r:embed\") ?? attr(n, \"r:link\");\n if (id) embedId = id;\n } else if (tag === \"wp:extent\") {\n cx = parseIntAttr(attr(n, \"cx\"));\n cy = parseIntAttr(attr(n, \"cy\"));\n }\n });\n\n if (!embedId) return null;\n const target = ctx.relationships.get(embedId);\n if (!target) return null;\n // Relationship targets are typically \"media/image1.png\"; the zip lookup uses\n // the same path (we stored bytes keyed under \"media/<file>\").\n const bytes = ctx.mediaBytes.get(target);\n if (!bytes) return null;\n\n const ext = extensionOf(target);\n const mime = MIME_BY_EXT[ext] ?? \"image/png\";\n const src = `data:${mime};base64,${bytesToBase64(bytes)}`;\n const widthPx = cx != null ? Math.max(1, Math.round(cx / EMU_PER_PX)) : 100;\n const heightPx = cy != null ? Math.max(1, Math.round(cy / EMU_PER_PX)) : 100;\n\n return { type: \"image\", src, width: widthPx, height: heightPx };\n}\n\nfunction walk(node: OoxmlNode, visit: (n: OoxmlNode) => void): void {\n visit(node);\n for (const child of childrenOf(node)) {\n if (\"#text\" in child) continue;\n walk(child, visit);\n }\n}\n\nfunction extensionOf(path: string): string {\n const m = /\\.([a-z0-9]+)$/i.exec(path);\n return m ? m[1].toLowerCase() : \"\";\n}\n\nfunction bytesToBase64(bytes: Uint8Array): string {\n // Browser path.\n if (typeof btoa === \"function\") {\n let bin = \"\";\n const CHUNK = 0x8000;\n for (let i = 0; i < bytes.length; i += CHUNK) {\n bin += String.fromCharCode.apply(null, Array.from(bytes.subarray(i, i + CHUNK)));\n }\n return btoa(bin);\n }\n // Node fallback.\n return Buffer.from(bytes).toString(\"base64\");\n}\n","import type { DeltaOp, MarkAttrs } from \"@sofereditor/core\";\nimport {\n attr,\n childrenOf,\n findChild,\n tagOf,\n type OoxmlNode,\n} from \"./parse-xml\";\nimport { docxHexToCssColor, halfPointsToCssPt } from \"./units\";\nimport { extractImageFromDrawing, type ImageContext } from \"./images\";\n\nexport interface RunContext extends ImageContext {}\n\n/**\n * Walk a paragraph's children (post `<w:pPr>`) and emit a `DeltaOp[]`. Combines\n * adjacent runs that share the same mark set into a single op for parity with\n * the export — Y.Text.applyDelta would merge them anyway, but pre-merging keeps\n * round-trip output stable.\n */\nexport function paragraphChildrenToDelta(children: OoxmlNode[], ctx: RunContext): DeltaOp[] {\n const ops: DeltaOp[] = [];\n for (const child of children) {\n const tag = tagOf(child);\n if (!tag) continue;\n if (tag === \"w:pPr\") continue;\n if (tag === \"w:r\") {\n collectRun(child, ctx, undefined, ops);\n } else if (tag === \"w:hyperlink\") {\n // hyperlinks carry an r:id that maps via relationships to the href.\n const rId = attr(child, \"r:id\");\n const href = rId ? ctx.relationships.get(rId) : undefined;\n const linkMark: MarkAttrs | undefined = href ? { link: { href } } : undefined;\n for (const sub of childrenOf(child)) {\n if (tagOf(sub) === \"w:r\") collectRun(sub, ctx, linkMark, ops);\n }\n }\n }\n return mergeAdjacent(ops);\n}\n\nfunction collectRun(\n run: OoxmlNode,\n ctx: RunContext,\n wrappingMarks: MarkAttrs | undefined,\n out: DeltaOp[],\n): void {\n const marks = mergeMarks(wrappingMarks, runMarks(findChild(run, \"w:rPr\")));\n for (const child of childrenOf(run)) {\n const tag = tagOf(child);\n if (!tag) continue;\n if (tag === \"w:t\") {\n const text = textContent(child);\n if (text.length > 0) push(out, text, marks);\n } else if (tag === \"w:tab\") {\n push(out, \"\\t\", marks);\n } else if (tag === \"w:br\") {\n // Treat w:br type=\"page\" as also a soft break for the model — we have no\n // explicit page-break node in the schema; pagination is computed live.\n push(out, \"\\n\", marks);\n } else if (tag === \"w:drawing\") {\n const embed = extractImageFromDrawing(child, ctx);\n if (embed) out.push({ insert: embed });\n }\n // Other run children (w:sym, w:fldChar, etc.) are silently dropped.\n }\n}\n\nfunction runMarks(rPr: OoxmlNode | undefined): MarkAttrs {\n const m: MarkAttrs = {};\n if (!rPr) return m;\n for (const child of childrenOf(rPr)) {\n const tag = tagOf(child);\n if (!tag) continue;\n switch (tag) {\n case \"w:b\":\n if (!isFalse(attr(child, \"w:val\"))) m.bold = true;\n break;\n case \"w:i\":\n if (!isFalse(attr(child, \"w:val\"))) m.italic = true;\n break;\n case \"w:u\": {\n const val = attr(child, \"w:val\");\n if (val && val.toLowerCase() !== \"none\") m.underline = true;\n break;\n }\n case \"w:strike\":\n if (!isFalse(attr(child, \"w:val\"))) m.strike = true;\n break;\n case \"w:color\": {\n const hex = attr(child, \"w:val\");\n const css = docxHexToCssColor(hex);\n if (css) m.color = css;\n break;\n }\n // w:rFonts intentionally ignored: school standard is Arial for all\n // exams. Any font declared in the .docx is dropped on import so the\n // imported doc inherits Arial from `.ed-root` / PDF base stylesheet.\n case \"w:sz\": {\n const halfPts = Number.parseFloat(attr(child, \"w:val\") ?? \"\");\n const css = halfPointsToCssPt(halfPts);\n if (css) m.fontSize = css;\n break;\n }\n }\n }\n return m;\n}\n\nfunction mergeMarks(a: MarkAttrs | undefined, b: MarkAttrs): MarkAttrs {\n if (!a) return b;\n return { ...a, ...b };\n}\n\nfunction textContent(node: OoxmlNode): string {\n let out = \"\";\n for (const child of childrenOf(node)) {\n if (\"#text\" in child) {\n const t = child[\"#text\"];\n if (typeof t === \"string\") out += t;\n }\n }\n return out;\n}\n\nfunction isFalse(val: string | undefined): boolean {\n if (val == null) return false;\n const v = val.toLowerCase();\n return v === \"0\" || v === \"false\" || v === \"none\";\n}\n\nfunction push(out: DeltaOp[], text: string, marks: MarkAttrs): void {\n const op: DeltaOp =\n Object.keys(marks).length === 0 ? { insert: text } : { insert: text, attributes: { ...marks } };\n out.push(op);\n}\n\nfunction mergeAdjacent(ops: DeltaOp[]): DeltaOp[] {\n const out: DeltaOp[] = [];\n for (const op of ops) {\n const prev = out[out.length - 1];\n if (\n prev &&\n typeof prev.insert === \"string\" &&\n typeof op.insert === \"string\" &&\n sameMarks(prev.attributes, op.attributes)\n ) {\n prev.insert = prev.insert + op.insert;\n continue;\n }\n out.push(op);\n }\n return out;\n}\n\nfunction sameMarks(a: MarkAttrs | undefined, b: MarkAttrs | undefined): boolean {\n const ak = a ? Object.keys(a).sort() : [];\n const bk = b ? Object.keys(b).sort() : [];\n if (ak.length !== bk.length) return false;\n for (let i = 0; i < ak.length; i++) {\n if (ak[i] !== bk[i]) return false;\n const av = (a as Record<string, unknown>)[ak[i]];\n const bv = (b as Record<string, unknown>)[bk[i]];\n if (typeof av === \"object\" && av !== null && typeof bv === \"object\" && bv !== null) {\n if (JSON.stringify(av) !== JSON.stringify(bv)) return false;\n } else if (av !== bv) {\n return false;\n }\n }\n return true;\n}\n","import type { AlignValue, BlockAttrs, BlockType, DeltaOp, SerializedBlock } from \"@sofereditor/core\";\nimport {\n attr,\n childrenOf,\n findChild,\n tagOf,\n type OoxmlNode,\n} from \"./parse-xml\";\nimport { paragraphChildrenToDelta, type RunContext } from \"./runs\";\nimport { NumberingResolver } from \"./numbering\";\nimport { parseAlign } from \"./units\";\n\n/**\n * Map a `<w:p>` element to a SerializedBlock. Decides between\n * `paragraph / heading / blockquote / codeBlock / listItem` based on the\n * paragraph style + `w:pPr` properties — mirrors the heuristics encoded in\n * `@sofereditor/export-docx/src/docx.ts`.\n */\nexport function paragraphToBlock(\n p: OoxmlNode,\n ctx: RunContext,\n numbering: NumberingResolver,\n): SerializedBlock {\n const pPr = findChild(p, \"w:pPr\");\n const numPr = pPr ? findChild(pPr, \"w:numPr\") : undefined;\n const styleId = pPr ? attr(findChild(pPr, \"w:pStyle\") ?? {}, \"w:val\") : undefined;\n\n const delta = paragraphChildrenToDelta(childrenOf(p), ctx);\n const text = collectText(delta);\n const align = parseAlign(pPr ? attr(findChild(pPr, \"w:jc\") ?? {}, \"w:val\") : undefined);\n const isRtl = pPr ? !!findChild(pPr, \"w:bidi\") : false;\n\n // List? — numPr is the strongest signal.\n if (numPr) {\n const resolved = numbering.resolve(numPr);\n const attrs: BlockAttrs = {\n listKind: resolved?.listKind ?? \"bullet\",\n listLevel: resolved?.listLevel ?? 0,\n };\n if (align) attrs.align = align;\n if (isRtl) attrs.dir = \"rtl\";\n return { type: \"listItem\", text, delta, attrs };\n }\n\n // Heading?\n const headingLevel = styleId ? headingFromStyleId(styleId) : null;\n if (headingLevel != null) {\n const attrs: BlockAttrs = { level: headingLevel };\n if (align) attrs.align = align;\n if (isRtl) attrs.dir = \"rtl\";\n return { type: \"heading\", text, delta, attrs };\n }\n\n // Blockquote (export uses left border + 480 twip indent).\n if (pPr && hasLeftBorder(pPr)) {\n const attrs: BlockAttrs = {};\n if (align) attrs.align = align;\n if (isRtl) attrs.dir = \"rtl\";\n return { type: \"blockquote\", text, delta, attrs };\n }\n\n // Code block (export uses Consolas + light-gray shading).\n if (pPr && hasCodeBlockShading(pPr)) {\n const attrs: BlockAttrs = {};\n if (align) attrs.align = align;\n if (isRtl) attrs.dir = \"rtl\";\n return { type: \"codeBlock\", text, delta, attrs };\n }\n\n const attrs: BlockAttrs = {};\n if (align) attrs.align = align;\n if (isRtl) attrs.dir = \"rtl\";\n return { type: \"paragraph\", text, delta, attrs };\n}\n\nfunction collectText(delta: DeltaOp[]): string {\n let out = \"\";\n for (const op of delta) {\n if (typeof op.insert === \"string\") out += op.insert;\n }\n return out;\n}\n\nfunction headingFromStyleId(id: string): 1 | 2 | 3 | 4 | 5 | 6 | null {\n const m = /^Heading\\s*([1-6])$/i.exec(id);\n if (!m) return null;\n const n = Number.parseInt(m[1], 10);\n return (n as 1 | 2 | 3 | 4 | 5 | 6) ?? null;\n}\n\nfunction hasLeftBorder(pPr: OoxmlNode): boolean {\n const pBdr = findChild(pPr, \"w:pBdr\");\n if (!pBdr) return false;\n return !!findChild(pBdr, \"w:left\");\n}\n\nfunction hasCodeBlockShading(pPr: OoxmlNode): boolean {\n const shd = findChild(pPr, \"w:shd\");\n if (!shd) return false;\n const fill = attr(shd, \"w:fill\");\n if (!fill) return false;\n return fill.toLowerCase() === \"f1f5f9\";\n}\n\n/** Whitelist the block types this module produces (used by callers for typing). */\nexport type ParagraphBlockType = Exclude<BlockType, \"table\">;\n/** Whitelist the align values this module produces (used by callers for typing). */\nexport type ParagraphAlign = AlignValue;\n","import type { BlockAttrs, CellAttrs, DeltaOp, SerializedBlock, SerializedCell } from \"@sofereditor/core\";\nimport {\n attr,\n childrenOf,\n findChild,\n findChildren,\n tagOf,\n type OoxmlNode,\n} from \"./parse-xml\";\nimport { paragraphChildrenToDelta, type RunContext } from \"./runs\";\nimport { parseIntAttr } from \"./units\";\n\n/**\n * Map a `<w:tbl>` element to a SerializedBlock(table). The output `cells` array\n * is row-major with `rows * cols` entries — covered slots are filled with\n * `{attrs: {covered: true}}` placeholders so it matches the invariant required\n * by `@sofereditor/core`'s `EditorDocument`.\n */\nexport function tableToBlock(tbl: OoxmlNode, ctx: RunContext): SerializedBlock {\n const tblGrid = findChild(tbl, \"w:tblGrid\");\n const gridCols = tblGrid ? findChildren(tblGrid, \"w:gridCol\") : [];\n const trs = findChildren(tbl, \"w:tr\");\n\n // The docx writer (and Word itself) may emit fewer `<w:gridCol>` entries than\n // the table's logical column count when a row has merged cells. Take the max\n // of (declared gridCols, widest row's total gridSpan) to stay robust.\n let cols = gridCols.length;\n for (const tr of trs) {\n const tcs = findChildren(tr, \"w:tc\");\n let count = 0;\n for (const tc of tcs) count += gridSpanOf(tc);\n if (count > cols) cols = count;\n }\n if (cols < 1) cols = 1;\n const rows = trs.length;\n\n // Build a row-major grid of slots. Each slot is either a real cell or marked\n // as covered. We track which (row, col) is the anchor for vMerge groups.\n const slots: Array<SerializedCell | null> = new Array(rows * cols).fill(null);\n // Anchor of the active vMerge per column index; resets when a non-merge cell\n // is placed in the same column.\n const vMergeAnchorByCol = new Map<number, { row: number; col: number }>();\n\n for (let r = 0; r < rows; r++) {\n const tr = trs[r];\n let cursor = 0;\n for (const tc of findChildren(tr, \"w:tc\")) {\n // Advance the cursor past already-occupied (covered-from-above) slots.\n while (cursor < cols && slots[r * cols + cursor] !== null) cursor++;\n if (cursor >= cols) break;\n\n const tcPr = findChild(tc, \"w:tcPr\");\n const gridSpan = gridSpanOf(tc);\n const vMergeNode = tcPr ? findChild(tcPr, \"w:vMerge\") : undefined;\n const vMergeVal = vMergeNode ? (attr(vMergeNode, \"w:val\") ?? \"continue\") : null;\n\n if (vMergeNode && vMergeVal !== \"restart\") {\n // Continuation of a vertical merge. Cover this row, and bump the anchor's\n // rowspan if we can find it.\n const anchor = vMergeAnchorByCol.get(cursor);\n if (anchor) {\n const anchorIdx = anchor.row * cols + anchor.col;\n const a = slots[anchorIdx];\n if (a) {\n a.attrs = { ...(a.attrs ?? {}), rowspan: (a.attrs?.rowspan ?? 1) + 1 };\n }\n }\n for (let c = 0; c < gridSpan && cursor + c < cols; c++) {\n slots[r * cols + cursor + c] = coveredCell();\n }\n cursor += gridSpan;\n continue;\n }\n\n // Real cell: build its delta + attrs.\n const delta = cellChildrenToDelta(tc, ctx);\n const text = textOfDelta(delta);\n const cellAttrs: CellAttrs = {};\n if (gridSpan > 1) cellAttrs.colspan = gridSpan;\n // rowspan starts at 1 — vMerge continuations bump it.\n\n const realCell: SerializedCell = { text, delta, attrs: cellAttrs };\n slots[r * cols + cursor] = realCell;\n\n // Mark horizontally-covered slots from gridSpan.\n for (let c = 1; c < gridSpan && cursor + c < cols; c++) {\n slots[r * cols + cursor + c] = coveredCell();\n }\n\n if (vMergeVal === \"restart\") {\n vMergeAnchorByCol.set(cursor, { row: r, col: cursor });\n } else {\n vMergeAnchorByCol.delete(cursor);\n }\n cursor += gridSpan;\n }\n\n // Fill any trailing un-touched slots in this row with empty placeholders so\n // the row-major invariant holds (length = rows * cols).\n for (let c = 0; c < cols; c++) {\n if (slots[r * cols + c] === null) {\n slots[r * cols + c] = emptyCell();\n }\n }\n }\n\n const cells: SerializedCell[] = slots.map((s) => s ?? emptyCell());\n\n const attrs: BlockAttrs = { rows, cols };\n return { type: \"table\", text: \"\", delta: [], attrs, cells };\n}\n\nfunction gridSpanOf(tc: OoxmlNode): number {\n const tcPr = findChild(tc, \"w:tcPr\");\n if (!tcPr) return 1;\n const gs = findChild(tcPr, \"w:gridSpan\");\n if (!gs) return 1;\n const n = parseIntAttr(attr(gs, \"w:val\"), 1);\n return Math.max(1, n);\n}\n\nfunction cellChildrenToDelta(tc: OoxmlNode, ctx: RunContext): DeltaOp[] {\n // A cell can contain multiple paragraphs; we concat their deltas with a\n // newline between adjacent ones to preserve visual separation. The cell\n // model in @sofereditor/core is a single Y.Text, so we flatten.\n const out: DeltaOp[] = [];\n let first = true;\n for (const child of childrenOf(tc)) {\n if (tagOf(child) !== \"w:p\") continue;\n if (!first) out.push({ insert: \"\\n\" });\n first = false;\n out.push(...paragraphChildrenToDelta(childrenOf(child), ctx));\n }\n return out;\n}\n\nfunction textOfDelta(delta: DeltaOp[]): string {\n let out = \"\";\n for (const op of delta) {\n if (typeof op.insert === \"string\") out += op.insert;\n }\n return out;\n}\n\nfunction coveredCell(): SerializedCell {\n return { text: \"\", delta: [], attrs: { covered: true } };\n}\n\nfunction emptyCell(): SerializedCell {\n return { text: \"\", delta: [], attrs: {} };\n}\n","import type { ListKind } from \"@sofereditor/core\";\nimport {\n attr,\n childrenOf,\n findChild,\n findChildren,\n tagOf,\n type OoxmlNode,\n} from \"./parse-xml\";\nimport { parseIntAttr } from \"./units\";\n\n/**\n * Resolves per-paragraph `<w:numPr>` into the editor's `{listKind, listLevel}`.\n *\n * docx numbering is two-step:\n * 1. paragraphs reference a `numId` and an `ilvl`\n * 2. each `<w:num numId=\"...\">` points to a `<w:abstractNum>` via `<w:abstractNumId>`\n * 3. each `<w:lvl ilvl=\"...\">` declares a `<w:numFmt val=\"bullet|decimal|...\">`\n *\n * The export side uses two hardcoded reference names (\"ed-bullet\" / \"ed-ordered\"),\n * but Word-authored documents use arbitrary `numId`s — we resolve by reading the\n * `numFmt` of the target level.\n */\nexport class NumberingResolver {\n private numIdToAbstract = new Map<string, string>();\n private abstractLevelFmt = new Map<string, Map<number, string>>();\n\n constructor(numberingXml: OoxmlNode[] | undefined) {\n if (!numberingXml) return;\n for (const top of numberingXml) {\n if (tagOf(top) !== \"w:numbering\") continue;\n for (const child of childrenOf(top)) {\n const tag = tagOf(child);\n if (tag === \"w:abstractNum\") {\n const abstractId = attr(child, \"w:abstractNumId\");\n if (!abstractId) continue;\n const levels = new Map<number, string>();\n for (const lvl of findChildren(child, \"w:lvl\")) {\n const ilvl = parseIntAttr(attr(lvl, \"w:ilvl\"), 0);\n const fmt = attr(findChild(lvl, \"w:numFmt\") ?? {}, \"w:val\");\n if (fmt) levels.set(ilvl, fmt);\n }\n this.abstractLevelFmt.set(abstractId, levels);\n } else if (tag === \"w:num\") {\n const numId = attr(child, \"w:numId\");\n const abstractRef = findChild(child, \"w:abstractNumId\");\n const abstractId = abstractRef ? attr(abstractRef, \"w:val\") : undefined;\n if (numId && abstractId) this.numIdToAbstract.set(numId, abstractId);\n }\n }\n }\n }\n\n /** Returns `{listKind, listLevel}` for a given paragraph's `<w:numPr>` node, or null. */\n resolve(numPr: OoxmlNode | undefined): { listKind: ListKind; listLevel: number } | null {\n if (!numPr) return null;\n const ilvlRef = findChild(numPr, \"w:ilvl\");\n const numIdRef = findChild(numPr, \"w:numId\");\n if (!numIdRef) return null;\n const numId = attr(numIdRef, \"w:val\");\n if (!numId) return null;\n const listLevel = clampLevel(parseIntAttr(ilvlRef ? attr(ilvlRef, \"w:val\") : undefined, 0));\n const abstractId = this.numIdToAbstract.get(numId);\n if (abstractId == null) {\n // Numbering refs the export side defines without a numbering.xml entry visible\n // to us (the export-docx pipeline generates them dynamically via the docx lib).\n // Fall back by inspecting the numId itself when it is a known sentinel.\n return { listKind: \"bullet\", listLevel };\n }\n const levels = this.abstractLevelFmt.get(abstractId);\n const fmt = (levels?.get(listLevel) ?? \"bullet\").toLowerCase();\n const listKind: ListKind = fmt === \"bullet\" || fmt === \"none\" ? \"bullet\" : \"ordered\";\n return { listKind, listLevel };\n }\n}\n\nfunction clampLevel(n: number): number {\n if (!Number.isFinite(n)) return 0;\n return Math.max(0, Math.min(5, Math.trunc(n)));\n}\n","import { detectPreset, mmToPx, type PageSettings } from \"@sofereditor/core\";\nimport { attr, findChild, type OoxmlNode } from \"./parse-xml\";\nimport { parseIntAttr } from \"./units\";\n\n/**\n * 1 inch = 1440 twips = 25.4 mm. So 1 twip = 25.4/1440 mm.\n *\n * Page size lives in `<w:sectPr><w:pgSz w:w=\"...\" w:h=\"...\"/></w:sectPr>` and\n * margins in `<w:pgMar w:top=\"...\" w:bottom=\"...\" w:left=\"...\" w:right=\"...\"/>`,\n * all in twips. This is the inverse of `sectionPropertiesFor` in\n * `@sofereditor/export-docx`.\n */\nconst MM_PER_TWIP = 25.4 / 1440;\n\nfunction twipsToPx(twips: number): number {\n return mmToPx(twips * MM_PER_TWIP);\n}\n\nexport function sectPrToPageSettings(\n sectPr: OoxmlNode | undefined,\n): PageSettings | undefined {\n if (!sectPr) return undefined;\n const pgSz = findChild(sectPr, \"w:pgSz\");\n const pgMar = findChild(sectPr, \"w:pgMar\");\n if (!pgSz && !pgMar) return undefined;\n\n const widthTwips = pgSz ? parseIntAttr(attr(pgSz, \"w:w\"), 0) : 0;\n const heightTwips = pgSz ? parseIntAttr(attr(pgSz, \"w:h\"), 0) : 0;\n const topTwips = pgMar ? parseIntAttr(attr(pgMar, \"w:top\"), 0) : 0;\n const bottomTwips = pgMar ? parseIntAttr(attr(pgMar, \"w:bottom\"), 0) : 0;\n const leftTwips = pgMar ? parseIntAttr(attr(pgMar, \"w:left\"), 0) : 0;\n const rightTwips = pgMar ? parseIntAttr(attr(pgMar, \"w:right\"), 0) : 0;\n\n if (widthTwips <= 0 && heightTwips <= 0 && topTwips <= 0 && leftTwips <= 0) {\n return undefined;\n }\n\n const width = widthTwips > 0 ? twipsToPx(widthTwips) : 794;\n const height = heightTwips > 0 ? twipsToPx(heightTwips) : 1123;\n const settings: PageSettings = {\n width,\n height,\n marginTop: twipsToPx(topTwips || 0),\n marginBottom: twipsToPx(bottomTwips || 0),\n marginLeft: twipsToPx(leftTwips || 0),\n marginRight: twipsToPx(rightTwips || 0),\n };\n settings.preset = detectPreset(settings.width, settings.height);\n return settings;\n}\n"],"mappings":"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","names":["import_core","JSZip","attrs"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/docx.ts","../src/parse-xml.ts","../src/units.ts","../src/images.ts","../src/runs.ts","../src/paragraphs.ts","../src/tables.ts","../src/numbering.ts","../src/page-settings.ts"],"sourcesContent":["export { docxBlobToDocument, docxBlobToEditorDocument } from \"./docx\";\n","import { EditorDocument, type SerializedBlock, type SerializedDocument } from \"@sofereditor/core\";\nimport { readDocx, childrenOf, tagOf, findChild, type OoxmlNode } from \"./parse-xml\";\nimport { paragraphToBlock } from \"./paragraphs\";\nimport { tableToBlock } from \"./tables\";\nimport { NumberingResolver } from \"./numbering\";\nimport { sectPrToPageSettings } from \"./page-settings\";\nimport type { RunContext } from \"./runs\";\n\n/**\n * Read a `.docx` (OOXML) Blob/ArrayBuffer/Uint8Array and produce a\n * `SerializedDocument` ready to feed `EditorDocument.fromJSON` (or\n * `loadFromJSON` on an existing instance).\n *\n * The mapping is the inverse of `@sofereditor/export-docx`. Round-trip is exact for\n * documents the editor produced; documents authored externally (Word, Google\n * Docs export) load with marks/lists/tables/images recognized and unsupported\n * features dropped silently.\n */\nexport async function docxBlobToDocument(\n input: Blob | ArrayBuffer | Uint8Array,\n): Promise<SerializedDocument> {\n const file = await readDocx(input);\n const numbering = new NumberingResolver(file.numberingXml);\n const ctx: RunContext = {\n relationships: file.relationships,\n mediaBytes: file.mediaBytes,\n };\n\n const body = findBody(file.documentXml);\n if (!body) return { blocks: [{ type: \"paragraph\", text: \"\", delta: [], attrs: {} }] };\n\n const blocks: SerializedBlock[] = [];\n for (const child of childrenOf(body)) {\n const tag = tagOf(child);\n if (tag === \"w:p\") {\n blocks.push(paragraphToBlock(child, ctx, numbering));\n } else if (tag === \"w:tbl\") {\n blocks.push(tableToBlock(child, ctx));\n }\n // w:sectPr is parsed below (page settings); other body-level metadata ignored.\n }\n\n if (blocks.length === 0) {\n blocks.push({ type: \"paragraph\", text: \"\", delta: [], attrs: {} });\n }\n\n pruneNonLeaderListStarts(blocks);\n\n const pageSettings = sectPrToPageSettings(findChild(body, \"w:sectPr\"));\n return pageSettings ? { blocks, pageSettings } : { blocks };\n}\n\n/**\n * O Word numera por INSTÂNCIA (`numId`): parágrafos comuns entre itens não\n * resetam a contagem. O editor numera por ADJACÊNCIA: o renderer agrupa\n * `listItem`s consecutivos do mesmo `listKind`/`listStyle`, e um `listStart`\n * em item de CONTINUAÇÃO quebra o grupo ali. O parse gravou o ordinal Word em\n * `listStart` de TODOS os itens ordenados; este pós-passe o mantém apenas nos\n * LÍDERES de grupo (primeiro item, item após bloco comum, ou após item de\n * kind/estilo diferente) — assim o editor renderiza exatamente os números do\n * Word (\"3.\" depois de uma linha de resposta, \"b.\" em subitens) sem fragmentar\n * os grupos.\n */\nexport function pruneNonLeaderListStarts(blocks: SerializedBlock[]): void {\n // Estado do grupo de adjacência corrente: estilo do líder e último ordinal\n // visto por nível (para exigir sequência contígua — duas listas Word\n // independentes coladas, \"1,2,3\" + \"1,2\", NÃO podem fundir num 1..5).\n let grupoAtivo = false;\n let grupoStyle: unknown;\n let ordinais: number[] = [];\n\n const resetGrupo = () => {\n grupoAtivo = false;\n grupoStyle = undefined;\n ordinais = [];\n };\n\n for (const block of blocks) {\n if (block.type !== \"listItem\") {\n resetGrupo();\n continue;\n }\n if ((block.attrs.listKind ?? \"bullet\") !== \"ordered\") {\n // Bullet entre ordenados: mantém o grupo do renderer? Não — kind\n // diferente quebra o grupo lá também.\n resetGrupo();\n continue;\n }\n const level = block.attrs.listLevel ?? 0;\n const ordinal = typeof block.attrs.listStart === \"number\" ? block.attrs.listStart : 1;\n\n const mesmoNivelSequencial = ordinais[level] != null && ordinal === ordinais[level] + 1;\n const entrandoEmNivelNovo = ordinais[level] == null && level > 0 && ordinal === 1;\n const continuaGrupo =\n grupoAtivo &&\n block.attrs.listStyle === grupoStyle &&\n (mesmoNivelSequencial || entrandoEmNivelNovo);\n\n if (continuaGrupo) {\n delete block.attrs.listStart;\n } else {\n // Este item lidera um grupo novo no renderer (listStart preservado).\n grupoAtivo = true;\n grupoStyle = block.attrs.listStyle;\n ordinais = [];\n }\n ordinais[level] = ordinal;\n ordinais.length = level + 1;\n }\n}\n\n/** Convenience: parse → instantiate a fresh `EditorDocument`. */\nexport async function docxBlobToEditorDocument(\n input: Blob | ArrayBuffer | Uint8Array,\n): Promise<EditorDocument> {\n const serialized = await docxBlobToDocument(input);\n return EditorDocument.fromJSON(serialized);\n}\n\nfunction findBody(documentXml: OoxmlNode[]): OoxmlNode | undefined {\n for (const top of documentXml) {\n if (tagOf(top) === \"w:document\") {\n const body = findChild(top, \"w:body\");\n if (body) return body;\n }\n }\n return undefined;\n}\n","import JSZip from \"jszip\";\nimport { XMLParser } from \"fast-xml-parser\";\n\n/**\n * fast-xml-parser with `preserveOrder: true` produces a list of single-key\n * objects per element. Each element is either:\n *\n * - A tag node: `{ \"<tagName>\": <children-array>, \":@\"?: <attrs> }`\n * - A text node: `{ \"#text\": <string> }`\n *\n * Attributes are prefixed with `@_`. The `:@` key holds attributes for the\n * surrounding tag. Children preserve original document order, which matters\n * for paragraph runs (bold word followed by italic word).\n */\nexport type OoxmlNode = Record<string, unknown>;\n\nconst parser = new XMLParser({\n ignoreAttributes: false,\n attributeNamePrefix: \"@_\",\n preserveOrder: true,\n trimValues: false, // keep whitespace inside <w:t>\n parseAttributeValue: false,\n parseTagValue: false,\n});\n\nexport interface DocxFile {\n documentXml: OoxmlNode[];\n numberingXml?: OoxmlNode[];\n /** rId → target path (inside the zip), e.g. \"media/image1.png\". */\n relationships: Map<string, string>;\n /** zip path (without leading \"word/\") → bytes for embedded media. */\n mediaBytes: Map<string, Uint8Array>;\n}\n\nexport async function readDocx(input: Blob | ArrayBuffer | Uint8Array): Promise<DocxFile> {\n const data =\n input instanceof Uint8Array\n ? input\n : input instanceof ArrayBuffer\n ? new Uint8Array(input)\n : new Uint8Array(await (input as Blob).arrayBuffer());\n\n const zip = await JSZip.loadAsync(data);\n const documentXml = await readXml(zip, \"word/document.xml\");\n if (!documentXml) throw new Error(\"Invalid .docx: missing word/document.xml\");\n\n const numberingXml = await readXml(zip, \"word/numbering.xml\");\n const relsXml = await readXml(zip, \"word/_rels/document.xml.rels\");\n const relationships = parseRelationships(relsXml);\n\n const mediaBytes = new Map<string, Uint8Array>();\n const mediaFolder = zip.folder(\"word/media\");\n if (mediaFolder) {\n const promises: Promise<void>[] = [];\n mediaFolder.forEach((relativePath, file) => {\n if (file.dir) return;\n promises.push(\n file.async(\"uint8array\").then((bytes) => {\n mediaBytes.set(`media/${relativePath}`, bytes);\n }),\n );\n });\n await Promise.all(promises);\n }\n\n return { documentXml, numberingXml, relationships, mediaBytes };\n}\n\nasync function readXml(zip: JSZip, path: string): Promise<OoxmlNode[] | undefined> {\n const entry = zip.file(path);\n if (!entry) return undefined;\n const text = await entry.async(\"string\");\n return parser.parse(text) as OoxmlNode[];\n}\n\nfunction parseRelationships(nodes: OoxmlNode[] | undefined): Map<string, string> {\n const out = new Map<string, string>();\n if (!nodes) return out;\n // <Relationships><Relationship Id=\"rId1\" Type=\"...\" Target=\"media/image1.png\"/>...\n for (const top of nodes) {\n const children = top[\"Relationships\"];\n if (!Array.isArray(children)) continue;\n for (const child of children as OoxmlNode[]) {\n if (!(\"Relationship\" in child)) continue;\n const attrs = (child[\":@\"] ?? {}) as Record<string, unknown>;\n const id = attrs[\"@_Id\"];\n const target = attrs[\"@_Target\"];\n if (typeof id === \"string\" && typeof target === \"string\") {\n out.set(id, target);\n }\n }\n }\n return out;\n}\n\n// ---------- generic walkers over preserveOrder shape ----------\n\n/** Returns the tag name (e.g. \"w:p\") of a preserveOrder element, or null for text. */\nexport function tagOf(node: OoxmlNode): string | null {\n for (const key of Object.keys(node)) {\n if (key === \":@\") continue;\n return key;\n }\n return null;\n}\n\n/** Returns the children array of an element, or [] when none. */\nexport function childrenOf(node: OoxmlNode): OoxmlNode[] {\n const tag = tagOf(node);\n if (!tag) return [];\n const v = node[tag];\n return Array.isArray(v) ? (v as OoxmlNode[]) : [];\n}\n\n/** Returns the attribute bag (already with `@_` prefix) for an element. */\nexport function attrsOf(node: OoxmlNode): Record<string, unknown> {\n return ((node[\":@\"] ?? {}) as Record<string, unknown>) ?? {};\n}\n\n/** Read a single `@_key` attribute as a string. */\nexport function attr(node: OoxmlNode, key: string): string | undefined {\n const v = attrsOf(node)[`@_${key}`];\n return typeof v === \"string\" ? v : undefined;\n}\n\n/** Find the first direct child with the given tag name. */\nexport function findChild(node: OoxmlNode, tag: string): OoxmlNode | undefined {\n for (const child of childrenOf(node)) {\n if (tagOf(child) === tag) return child;\n }\n return undefined;\n}\n\n/** Find all direct children with the given tag name. */\nexport function findChildren(node: OoxmlNode, tag: string): OoxmlNode[] {\n const out: OoxmlNode[] = [];\n for (const child of childrenOf(node)) {\n if (tagOf(child) === tag) out.push(child);\n }\n return out;\n}\n\n/** Recursively collect text nodes' concatenated content. */\nexport function textOf(node: OoxmlNode): string {\n let out = \"\";\n for (const child of childrenOf(node)) {\n if (\"#text\" in child) {\n const t = child[\"#text\"];\n if (typeof t === \"string\") out += t;\n } else {\n out += textOf(child);\n }\n }\n return out;\n}\n","/**\n * Unit conversions between OOXML and the editor's serialized format.\n * These are the inverses of the helpers in `@sofereditor/export-docx/src/docx.ts`.\n */\n\n/** docx half-points → CSS pt string. 24 (half-pt) → \"12pt\". */\nexport function halfPointsToCssPt(halfPoints: number): string | undefined {\n if (!Number.isFinite(halfPoints) || halfPoints <= 0) return undefined;\n const pt = halfPoints / 2;\n return `${stripTrailingZeros(pt)}pt`;\n}\n\n/** OOXML RRGGBB (no '#') → CSS hex with leading '#'. */\nexport function docxHexToCssColor(hex: string | undefined): string | undefined {\n if (!hex) return undefined;\n const m = /^[0-9a-f]{6}$/i.exec(hex.trim());\n if (!m) return undefined;\n return `#${hex.toLowerCase()}`;\n}\n\n/** OOXML alignment value → editor AlignValue. */\nexport function parseAlign(val: string | undefined): \"left\" | \"center\" | \"right\" | \"justify\" | undefined {\n if (!val) return undefined;\n switch (val.toLowerCase()) {\n case \"left\":\n case \"start\":\n return \"left\";\n case \"center\":\n return \"center\";\n case \"right\":\n case \"end\":\n return \"right\";\n case \"both\":\n case \"distribute\":\n case \"justify\":\n return \"justify\";\n default:\n return undefined;\n }\n}\n\n/** Parse XML attribute that should be a positive integer. */\nexport function parseIntAttr(val: unknown, fallback = 0): number {\n if (typeof val === \"number\" && Number.isFinite(val)) return Math.trunc(val);\n if (typeof val !== \"string\") return fallback;\n const n = Number.parseInt(val, 10);\n return Number.isFinite(n) ? n : fallback;\n}\n\nfunction stripTrailingZeros(n: number): string {\n // 12 → \"12\", 12.5 → \"12.5\"\n return Number.isInteger(n) ? n.toString() : n.toFixed(2).replace(/\\.?0+$/, \"\");\n}\n","import type { ImageEmbed } from \"@sofereditor/core\";\nimport { attr, childrenOf, tagOf, type OoxmlNode } from \"./parse-xml\";\nimport { parseIntAttr } from \"./units\";\n\n/** 1 inch = 914400 EMU = 96 px → 1 px = 9525 EMU. */\nconst EMU_PER_PX = 9525;\n\nconst MIME_BY_EXT: Record<string, string> = {\n png: \"image/png\",\n jpg: \"image/jpeg\",\n jpeg: \"image/jpeg\",\n gif: \"image/gif\",\n bmp: \"image/bmp\",\n svg: \"image/svg+xml\",\n};\n\nexport interface ImageContext {\n relationships: Map<string, string>;\n mediaBytes: Map<string, Uint8Array>;\n}\n\n/**\n * Walk a `<w:drawing>` node and return an `ImageEmbed` if it contains a\n * recognized inline picture. Returns null for unsupported drawings (shapes,\n * charts, etc.).\n */\nexport function extractImageFromDrawing(\n drawing: OoxmlNode,\n ctx: ImageContext,\n): ImageEmbed | null {\n // The interesting bits live deep inside: a:blip carries `r:embed`, and\n // wp:extent carries cx/cy. We do a generic walk because the wrapping nodes\n // differ between inline (`wp:inline`) and anchored (`wp:anchor`) drawings.\n let embedId: string | undefined;\n let cx: number | undefined;\n let cy: number | undefined;\n\n walk(drawing, (n) => {\n const tag = tagOf(n);\n if (!tag) return;\n if (tag === \"a:blip\") {\n const id = attr(n, \"r:embed\") ?? attr(n, \"r:link\");\n if (id) embedId = id;\n } else if (tag === \"wp:extent\") {\n cx = parseIntAttr(attr(n, \"cx\"));\n cy = parseIntAttr(attr(n, \"cy\"));\n }\n });\n\n if (!embedId) return null;\n const target = ctx.relationships.get(embedId);\n if (!target) return null;\n // Relationship targets are typically \"media/image1.png\"; the zip lookup uses\n // the same path (we stored bytes keyed under \"media/<file>\").\n const bytes = ctx.mediaBytes.get(target);\n if (!bytes) return null;\n\n const ext = extensionOf(target);\n const mime = MIME_BY_EXT[ext] ?? \"image/png\";\n const src = `data:${mime};base64,${bytesToBase64(bytes)}`;\n const widthPx = cx != null ? Math.max(1, Math.round(cx / EMU_PER_PX)) : 100;\n const heightPx = cy != null ? Math.max(1, Math.round(cy / EMU_PER_PX)) : 100;\n\n return { type: \"image\", src, width: widthPx, height: heightPx };\n}\n\nfunction walk(node: OoxmlNode, visit: (n: OoxmlNode) => void): void {\n visit(node);\n for (const child of childrenOf(node)) {\n if (\"#text\" in child) continue;\n walk(child, visit);\n }\n}\n\nfunction extensionOf(path: string): string {\n const m = /\\.([a-z0-9]+)$/i.exec(path);\n return m ? m[1].toLowerCase() : \"\";\n}\n\nfunction bytesToBase64(bytes: Uint8Array): string {\n // Browser path.\n if (typeof btoa === \"function\") {\n let bin = \"\";\n const CHUNK = 0x8000;\n for (let i = 0; i < bytes.length; i += CHUNK) {\n bin += String.fromCharCode.apply(null, Array.from(bytes.subarray(i, i + CHUNK)));\n }\n return btoa(bin);\n }\n // Node fallback.\n return Buffer.from(bytes).toString(\"base64\");\n}\n","import type { DeltaOp, MarkAttrs } from \"@sofereditor/core\";\nimport {\n attr,\n childrenOf,\n findChild,\n tagOf,\n type OoxmlNode,\n} from \"./parse-xml\";\nimport { docxHexToCssColor, halfPointsToCssPt } from \"./units\";\nimport { extractImageFromDrawing, type ImageContext } from \"./images\";\n\nexport interface RunContext extends ImageContext {}\n\n/**\n * Walk a paragraph's children (post `<w:pPr>`) and emit a `DeltaOp[]`. Combines\n * adjacent runs that share the same mark set into a single op for parity with\n * the export — Y.Text.applyDelta would merge them anyway, but pre-merging keeps\n * round-trip output stable.\n */\nexport function paragraphChildrenToDelta(children: OoxmlNode[], ctx: RunContext): DeltaOp[] {\n const ops: DeltaOp[] = [];\n for (const child of children) {\n const tag = tagOf(child);\n if (!tag) continue;\n if (tag === \"w:pPr\") continue;\n if (tag === \"w:r\") {\n collectRun(child, ctx, undefined, ops);\n } else if (tag === \"w:hyperlink\") {\n // hyperlinks carry an r:id that maps via relationships to the href.\n const rId = attr(child, \"r:id\");\n const href = rId ? ctx.relationships.get(rId) : undefined;\n const linkMark: MarkAttrs | undefined = href ? { link: { href } } : undefined;\n for (const sub of childrenOf(child)) {\n if (tagOf(sub) === \"w:r\") collectRun(sub, ctx, linkMark, ops);\n }\n }\n }\n return mergeAdjacent(ops);\n}\n\nfunction collectRun(\n run: OoxmlNode,\n ctx: RunContext,\n wrappingMarks: MarkAttrs | undefined,\n out: DeltaOp[],\n): void {\n const marks = mergeMarks(wrappingMarks, runMarks(findChild(run, \"w:rPr\")));\n for (const child of childrenOf(run)) {\n const tag = tagOf(child);\n if (!tag) continue;\n if (tag === \"w:t\") {\n const text = textContent(child);\n if (text.length > 0) push(out, text, marks);\n } else if (tag === \"w:tab\") {\n push(out, \"\\t\", marks);\n } else if (tag === \"w:br\") {\n // Treat w:br type=\"page\" as also a soft break for the model — we have no\n // explicit page-break node in the schema; pagination is computed live.\n push(out, \"\\n\", marks);\n } else if (tag === \"w:drawing\") {\n const embed = extractImageFromDrawing(child, ctx);\n if (embed) out.push({ insert: embed });\n }\n // Other run children (w:sym, w:fldChar, etc.) are silently dropped.\n }\n}\n\nfunction runMarks(rPr: OoxmlNode | undefined): MarkAttrs {\n const m: MarkAttrs = {};\n if (!rPr) return m;\n for (const child of childrenOf(rPr)) {\n const tag = tagOf(child);\n if (!tag) continue;\n switch (tag) {\n case \"w:b\":\n if (!isFalse(attr(child, \"w:val\"))) m.bold = true;\n break;\n case \"w:i\":\n if (!isFalse(attr(child, \"w:val\"))) m.italic = true;\n break;\n case \"w:u\": {\n const val = attr(child, \"w:val\");\n if (val && val.toLowerCase() !== \"none\") m.underline = true;\n break;\n }\n case \"w:strike\":\n if (!isFalse(attr(child, \"w:val\"))) m.strike = true;\n break;\n case \"w:color\": {\n const hex = attr(child, \"w:val\");\n const css = docxHexToCssColor(hex);\n if (css) m.color = css;\n break;\n }\n // w:rFonts intentionally ignored: school standard is Arial for all\n // exams. Any font declared in the .docx is dropped on import so the\n // imported doc inherits Arial from `.ed-root` / PDF base stylesheet.\n case \"w:sz\": {\n const halfPts = Number.parseFloat(attr(child, \"w:val\") ?? \"\");\n const css = halfPointsToCssPt(halfPts);\n if (css) m.fontSize = css;\n break;\n }\n }\n }\n return m;\n}\n\nfunction mergeMarks(a: MarkAttrs | undefined, b: MarkAttrs): MarkAttrs {\n if (!a) return b;\n return { ...a, ...b };\n}\n\nfunction textContent(node: OoxmlNode): string {\n let out = \"\";\n for (const child of childrenOf(node)) {\n if (\"#text\" in child) {\n const t = child[\"#text\"];\n if (typeof t === \"string\") out += t;\n }\n }\n return out;\n}\n\nfunction isFalse(val: string | undefined): boolean {\n if (val == null) return false;\n const v = val.toLowerCase();\n return v === \"0\" || v === \"false\" || v === \"none\";\n}\n\nfunction push(out: DeltaOp[], text: string, marks: MarkAttrs): void {\n const op: DeltaOp =\n Object.keys(marks).length === 0 ? { insert: text } : { insert: text, attributes: { ...marks } };\n out.push(op);\n}\n\nfunction mergeAdjacent(ops: DeltaOp[]): DeltaOp[] {\n const out: DeltaOp[] = [];\n for (const op of ops) {\n const prev = out[out.length - 1];\n if (\n prev &&\n typeof prev.insert === \"string\" &&\n typeof op.insert === \"string\" &&\n sameMarks(prev.attributes, op.attributes)\n ) {\n prev.insert = prev.insert + op.insert;\n continue;\n }\n out.push(op);\n }\n return out;\n}\n\nfunction sameMarks(a: MarkAttrs | undefined, b: MarkAttrs | undefined): boolean {\n const ak = a ? Object.keys(a).sort() : [];\n const bk = b ? Object.keys(b).sort() : [];\n if (ak.length !== bk.length) return false;\n for (let i = 0; i < ak.length; i++) {\n if (ak[i] !== bk[i]) return false;\n const av = (a as Record<string, unknown>)[ak[i]];\n const bv = (b as Record<string, unknown>)[bk[i]];\n if (typeof av === \"object\" && av !== null && typeof bv === \"object\" && bv !== null) {\n if (JSON.stringify(av) !== JSON.stringify(bv)) return false;\n } else if (av !== bv) {\n return false;\n }\n }\n return true;\n}\n","import type { AlignValue, BlockAttrs, BlockType, DeltaOp, SerializedBlock } from \"@sofereditor/core\";\nimport {\n attr,\n childrenOf,\n findChild,\n tagOf,\n type OoxmlNode,\n} from \"./parse-xml\";\nimport { paragraphChildrenToDelta, type RunContext } from \"./runs\";\nimport { NumberingResolver } from \"./numbering\";\nimport { parseAlign } from \"./units\";\n\n/**\n * Map a `<w:p>` element to a SerializedBlock. Decides between\n * `paragraph / heading / blockquote / codeBlock / listItem` based on the\n * paragraph style + `w:pPr` properties — mirrors the heuristics encoded in\n * `@sofereditor/export-docx/src/docx.ts`.\n */\nexport function paragraphToBlock(\n p: OoxmlNode,\n ctx: RunContext,\n numbering: NumberingResolver,\n): SerializedBlock {\n const pPr = findChild(p, \"w:pPr\");\n const numPr = pPr ? findChild(pPr, \"w:numPr\") : undefined;\n const styleId = pPr ? attr(findChild(pPr, \"w:pStyle\") ?? {}, \"w:val\") : undefined;\n\n const delta = paragraphChildrenToDelta(childrenOf(p), ctx);\n const text = collectText(delta);\n const align = parseAlign(pPr ? attr(findChild(pPr, \"w:jc\") ?? {}, \"w:val\") : undefined);\n const isRtl = pPr ? !!findChild(pPr, \"w:bidi\") : false;\n\n // List? — numPr is the strongest signal.\n if (numPr) {\n const resolved = numbering.resolve(numPr);\n const attrs: BlockAttrs = {\n listKind: resolved?.listKind ?? \"bullet\",\n listLevel: resolved?.listLevel ?? 0,\n };\n if (resolved?.listKind === \"ordered\") {\n // O ordinal Word vai TEMPORARIAMENTE em listStart de todos os itens; o\n // pós-passe em docx.ts remove dos não-líderes (um listStart em item de\n // continuação quebraria o grupo no renderer). listStyle fica em todos —\n // itens do mesmo estilo agrupam; estilo diferente (ex.: a/b/c entre\n // questões decimais) quebra o grupo exatamente como no Word.\n if (resolved.ordinal != null) attrs.listStart = resolved.ordinal;\n if (resolved.listStyle) attrs.listStyle = resolved.listStyle;\n }\n if (align) attrs.align = align;\n if (isRtl) attrs.dir = \"rtl\";\n return { type: \"listItem\", text, delta, attrs };\n }\n\n // Heading?\n const headingLevel = styleId ? headingFromStyleId(styleId) : null;\n if (headingLevel != null) {\n const attrs: BlockAttrs = { level: headingLevel };\n if (align) attrs.align = align;\n if (isRtl) attrs.dir = \"rtl\";\n return { type: \"heading\", text, delta, attrs };\n }\n\n // Blockquote (export uses left border + 480 twip indent).\n if (pPr && hasLeftBorder(pPr)) {\n const attrs: BlockAttrs = {};\n if (align) attrs.align = align;\n if (isRtl) attrs.dir = \"rtl\";\n return { type: \"blockquote\", text, delta, attrs };\n }\n\n // Code block (export uses Consolas + light-gray shading).\n if (pPr && hasCodeBlockShading(pPr)) {\n const attrs: BlockAttrs = {};\n if (align) attrs.align = align;\n if (isRtl) attrs.dir = \"rtl\";\n return { type: \"codeBlock\", text, delta, attrs };\n }\n\n const attrs: BlockAttrs = {};\n if (align) attrs.align = align;\n if (isRtl) attrs.dir = \"rtl\";\n return { type: \"paragraph\", text, delta, attrs };\n}\n\nfunction collectText(delta: DeltaOp[]): string {\n let out = \"\";\n for (const op of delta) {\n if (typeof op.insert === \"string\") out += op.insert;\n }\n return out;\n}\n\nfunction headingFromStyleId(id: string): 1 | 2 | 3 | 4 | 5 | 6 | null {\n const m = /^Heading\\s*([1-6])$/i.exec(id);\n if (!m) return null;\n const n = Number.parseInt(m[1], 10);\n return (n as 1 | 2 | 3 | 4 | 5 | 6) ?? null;\n}\n\nfunction hasLeftBorder(pPr: OoxmlNode): boolean {\n const pBdr = findChild(pPr, \"w:pBdr\");\n if (!pBdr) return false;\n return !!findChild(pBdr, \"w:left\");\n}\n\nfunction hasCodeBlockShading(pPr: OoxmlNode): boolean {\n const shd = findChild(pPr, \"w:shd\");\n if (!shd) return false;\n const fill = attr(shd, \"w:fill\");\n if (!fill) return false;\n return fill.toLowerCase() === \"f1f5f9\";\n}\n\n/** Whitelist the block types this module produces (used by callers for typing). */\nexport type ParagraphBlockType = Exclude<BlockType, \"table\">;\n/** Whitelist the align values this module produces (used by callers for typing). */\nexport type ParagraphAlign = AlignValue;\n","import type { BlockAttrs, CellAttrs, DeltaOp, SerializedBlock, SerializedCell } from \"@sofereditor/core\";\nimport {\n attr,\n childrenOf,\n findChild,\n findChildren,\n tagOf,\n type OoxmlNode,\n} from \"./parse-xml\";\nimport { paragraphChildrenToDelta, type RunContext } from \"./runs\";\nimport { parseIntAttr } from \"./units\";\n\n/**\n * Map a `<w:tbl>` element to a SerializedBlock(table). The output `cells` array\n * is row-major with `rows * cols` entries — covered slots are filled with\n * `{attrs: {covered: true}}` placeholders so it matches the invariant required\n * by `@sofereditor/core`'s `EditorDocument`.\n */\nexport function tableToBlock(tbl: OoxmlNode, ctx: RunContext): SerializedBlock {\n const tblGrid = findChild(tbl, \"w:tblGrid\");\n const gridCols = tblGrid ? findChildren(tblGrid, \"w:gridCol\") : [];\n const trs = findChildren(tbl, \"w:tr\");\n\n // The docx writer (and Word itself) may emit fewer `<w:gridCol>` entries than\n // the table's logical column count when a row has merged cells. Take the max\n // of (declared gridCols, widest row's total gridSpan) to stay robust.\n let cols = gridCols.length;\n for (const tr of trs) {\n const tcs = findChildren(tr, \"w:tc\");\n let count = 0;\n for (const tc of tcs) count += gridSpanOf(tc);\n if (count > cols) cols = count;\n }\n if (cols < 1) cols = 1;\n const rows = trs.length;\n\n // Build a row-major grid of slots. Each slot is either a real cell or marked\n // as covered. We track which (row, col) is the anchor for vMerge groups.\n const slots: Array<SerializedCell | null> = new Array(rows * cols).fill(null);\n // Anchor of the active vMerge per column index; resets when a non-merge cell\n // is placed in the same column.\n const vMergeAnchorByCol = new Map<number, { row: number; col: number }>();\n\n for (let r = 0; r < rows; r++) {\n const tr = trs[r];\n let cursor = 0;\n for (const tc of findChildren(tr, \"w:tc\")) {\n // Advance the cursor past already-occupied (covered-from-above) slots.\n while (cursor < cols && slots[r * cols + cursor] !== null) cursor++;\n if (cursor >= cols) break;\n\n const tcPr = findChild(tc, \"w:tcPr\");\n const gridSpan = gridSpanOf(tc);\n const vMergeNode = tcPr ? findChild(tcPr, \"w:vMerge\") : undefined;\n const vMergeVal = vMergeNode ? (attr(vMergeNode, \"w:val\") ?? \"continue\") : null;\n\n if (vMergeNode && vMergeVal !== \"restart\") {\n // Continuation of a vertical merge. Cover this row, and bump the anchor's\n // rowspan if we can find it.\n const anchor = vMergeAnchorByCol.get(cursor);\n if (anchor) {\n const anchorIdx = anchor.row * cols + anchor.col;\n const a = slots[anchorIdx];\n if (a) {\n a.attrs = { ...(a.attrs ?? {}), rowspan: (a.attrs?.rowspan ?? 1) + 1 };\n }\n }\n for (let c = 0; c < gridSpan && cursor + c < cols; c++) {\n slots[r * cols + cursor + c] = coveredCell();\n }\n cursor += gridSpan;\n continue;\n }\n\n // Real cell: build its delta + attrs.\n const delta = cellChildrenToDelta(tc, ctx);\n const text = textOfDelta(delta);\n const cellAttrs: CellAttrs = {};\n if (gridSpan > 1) cellAttrs.colspan = gridSpan;\n // rowspan starts at 1 — vMerge continuations bump it.\n\n const realCell: SerializedCell = { text, delta, attrs: cellAttrs };\n slots[r * cols + cursor] = realCell;\n\n // Mark horizontally-covered slots from gridSpan.\n for (let c = 1; c < gridSpan && cursor + c < cols; c++) {\n slots[r * cols + cursor + c] = coveredCell();\n }\n\n if (vMergeVal === \"restart\") {\n vMergeAnchorByCol.set(cursor, { row: r, col: cursor });\n } else {\n vMergeAnchorByCol.delete(cursor);\n }\n cursor += gridSpan;\n }\n\n // Fill any trailing un-touched slots in this row with empty placeholders so\n // the row-major invariant holds (length = rows * cols).\n for (let c = 0; c < cols; c++) {\n if (slots[r * cols + c] === null) {\n slots[r * cols + c] = emptyCell();\n }\n }\n }\n\n const cells: SerializedCell[] = slots.map((s) => s ?? emptyCell());\n\n const attrs: BlockAttrs = { rows, cols };\n return { type: \"table\", text: \"\", delta: [], attrs, cells };\n}\n\nfunction gridSpanOf(tc: OoxmlNode): number {\n const tcPr = findChild(tc, \"w:tcPr\");\n if (!tcPr) return 1;\n const gs = findChild(tcPr, \"w:gridSpan\");\n if (!gs) return 1;\n const n = parseIntAttr(attr(gs, \"w:val\"), 1);\n return Math.max(1, n);\n}\n\nfunction cellChildrenToDelta(tc: OoxmlNode, ctx: RunContext): DeltaOp[] {\n // A cell can contain multiple paragraphs; we concat their deltas with a\n // newline between adjacent ones to preserve visual separation. The cell\n // model in @sofereditor/core is a single Y.Text, so we flatten.\n const out: DeltaOp[] = [];\n let first = true;\n for (const child of childrenOf(tc)) {\n if (tagOf(child) !== \"w:p\") continue;\n if (!first) out.push({ insert: \"\\n\" });\n first = false;\n out.push(...paragraphChildrenToDelta(childrenOf(child), ctx));\n }\n return out;\n}\n\nfunction textOfDelta(delta: DeltaOp[]): string {\n let out = \"\";\n for (const op of delta) {\n if (typeof op.insert === \"string\") out += op.insert;\n }\n return out;\n}\n\nfunction coveredCell(): SerializedCell {\n return { text: \"\", delta: [], attrs: { covered: true } };\n}\n\nfunction emptyCell(): SerializedCell {\n return { text: \"\", delta: [], attrs: {} };\n}\n","import type { ListKind, ListStyleType } from \"@sofereditor/core\";\nimport {\n attr,\n childrenOf,\n findChild,\n findChildren,\n tagOf,\n type OoxmlNode,\n} from \"./parse-xml\";\nimport { parseIntAttr } from \"./units\";\n\n/**\n * Resolves per-paragraph `<w:numPr>` into the editor's `{listKind, listLevel}`.\n *\n * docx numbering is two-step:\n * 1. paragraphs reference a `numId` and an `ilvl`\n * 2. each `<w:num numId=\"...\">` points to a `<w:abstractNum>` via `<w:abstractNumId>`\n * 3. each `<w:lvl ilvl=\"...\">` declares a `<w:numFmt val=\"bullet|decimal|...\">`\n *\n * The export side uses two hardcoded reference names (\"ed-bullet\" / \"ed-ordered\"),\n * but Word-authored documents use arbitrary `numId`s — we resolve by reading the\n * `numFmt` of the target level.\n */\n/** `w:numFmt` → CSS `list-style-type` do editor. Não listados caem em \"decimal\". */\nconst FMT_TO_LIST_STYLE: Record<string, ListStyleType> = {\n decimal: \"decimal\",\n lowerLetter: \"lower-alpha\",\n upperLetter: \"upper-alpha\",\n lowerRoman: \"lower-roman\",\n upperRoman: \"upper-roman\",\n};\n\nexport interface ResolvedNumbering {\n listKind: ListKind;\n listLevel: number;\n /**\n * Número Word desta entrada (contador por instância `numId`+nível, honrando\n * `w:start` e resetando níveis mais profundos). Só para `ordered`. O Word\n * numera por INSTÂNCIA — parágrafos comuns entre itens não resetam a\n * contagem — enquanto o editor numera por adjacência; o importador usa este\n * ordinal para semear `listStart` nos líderes de grupo (ver docx.ts).\n */\n ordinal?: number;\n /** Estilo do nível (`w:numFmt` mapeado). Só para `ordered`. */\n listStyle?: ListStyleType;\n}\n\nexport class NumberingResolver {\n private numIdToAbstract = new Map<string, string>();\n private abstractLevelFmt = new Map<string, Map<number, string>>();\n private abstractLevelStart = new Map<string, Map<number, number>>();\n /** Contadores vivos por instância de lista (numId), indexados por nível. */\n private counters = new Map<string, number[]>();\n\n constructor(numberingXml: OoxmlNode[] | undefined) {\n if (!numberingXml) return;\n for (const top of numberingXml) {\n if (tagOf(top) !== \"w:numbering\") continue;\n for (const child of childrenOf(top)) {\n const tag = tagOf(child);\n if (tag === \"w:abstractNum\") {\n const abstractId = attr(child, \"w:abstractNumId\");\n if (!abstractId) continue;\n const levels = new Map<number, string>();\n const starts = new Map<number, number>();\n for (const lvl of findChildren(child, \"w:lvl\")) {\n const ilvl = parseIntAttr(attr(lvl, \"w:ilvl\"), 0);\n const fmt = attr(findChild(lvl, \"w:numFmt\") ?? {}, \"w:val\");\n if (fmt) levels.set(ilvl, fmt);\n const start = findChild(lvl, \"w:start\");\n if (start) starts.set(ilvl, parseIntAttr(attr(start, \"w:val\"), 1));\n }\n this.abstractLevelFmt.set(abstractId, levels);\n this.abstractLevelStart.set(abstractId, starts);\n } else if (tag === \"w:num\") {\n const numId = attr(child, \"w:numId\");\n const abstractRef = findChild(child, \"w:abstractNumId\");\n const abstractId = abstractRef ? attr(abstractRef, \"w:val\") : undefined;\n if (numId && abstractId) this.numIdToAbstract.set(numId, abstractId);\n }\n }\n }\n }\n\n /**\n * Resolves a paragraph's `<w:numPr>` into `{listKind, listLevel, ordinal?,\n * listStyle?}`, or null. STATEFUL for ordered lists: each call advances the\n * per-`numId` counter (Word instance semantics) — call exactly once per\n * numbered paragraph, in document order.\n */\n resolve(numPr: OoxmlNode | undefined): ResolvedNumbering | null {\n if (!numPr) return null;\n const ilvlRef = findChild(numPr, \"w:ilvl\");\n const numIdRef = findChild(numPr, \"w:numId\");\n if (!numIdRef) return null;\n const numId = attr(numIdRef, \"w:val\");\n if (!numId) return null;\n const listLevel = clampLevel(parseIntAttr(ilvlRef ? attr(ilvlRef, \"w:val\") : undefined, 0));\n const abstractId = this.numIdToAbstract.get(numId);\n if (abstractId == null) {\n // Numbering refs the export side defines without a numbering.xml entry visible\n // to us (the export-docx pipeline generates them dynamically via the docx lib).\n // Fall back by inspecting the numId itself when it is a known sentinel.\n return { listKind: \"bullet\", listLevel };\n }\n const levels = this.abstractLevelFmt.get(abstractId);\n const fmt = levels?.get(listLevel) ?? \"bullet\";\n const fmtLower = fmt.toLowerCase();\n const listKind: ListKind = fmtLower === \"bullet\" || fmtLower === \"none\" ? \"bullet\" : \"ordered\";\n if (listKind === \"bullet\") return { listKind, listLevel };\n\n // Ordinal Word: contador por numId; nível avança, níveis mais profundos resetam.\n const start = this.abstractLevelStart.get(abstractId)?.get(listLevel) ?? 1;\n const c = this.counters.get(numId) ?? [];\n c[listLevel] = c[listLevel] == null ? start : c[listLevel] + 1;\n c.length = listLevel + 1;\n this.counters.set(numId, c);\n\n return {\n listKind,\n listLevel,\n ordinal: c[listLevel],\n listStyle: FMT_TO_LIST_STYLE[fmt] ?? \"decimal\",\n };\n }\n}\n\nfunction clampLevel(n: number): number {\n if (!Number.isFinite(n)) return 0;\n return Math.max(0, Math.min(5, Math.trunc(n)));\n}\n","import { detectPreset, mmToPx, type PageSettings } from \"@sofereditor/core\";\nimport { attr, findChild, type OoxmlNode } from \"./parse-xml\";\nimport { parseIntAttr } from \"./units\";\n\n/**\n * 1 inch = 1440 twips = 25.4 mm. So 1 twip = 25.4/1440 mm.\n *\n * Page size lives in `<w:sectPr><w:pgSz w:w=\"...\" w:h=\"...\"/></w:sectPr>` and\n * margins in `<w:pgMar w:top=\"...\" w:bottom=\"...\" w:left=\"...\" w:right=\"...\"/>`,\n * all in twips. This is the inverse of `sectionPropertiesFor` in\n * `@sofereditor/export-docx`.\n */\nconst MM_PER_TWIP = 25.4 / 1440;\n\nfunction twipsToPx(twips: number): number {\n return mmToPx(twips * MM_PER_TWIP);\n}\n\nexport function sectPrToPageSettings(\n sectPr: OoxmlNode | undefined,\n): PageSettings | undefined {\n if (!sectPr) return undefined;\n const pgSz = findChild(sectPr, \"w:pgSz\");\n const pgMar = findChild(sectPr, \"w:pgMar\");\n if (!pgSz && !pgMar) return undefined;\n\n const widthTwips = pgSz ? parseIntAttr(attr(pgSz, \"w:w\"), 0) : 0;\n const heightTwips = pgSz ? parseIntAttr(attr(pgSz, \"w:h\"), 0) : 0;\n const topTwips = pgMar ? parseIntAttr(attr(pgMar, \"w:top\"), 0) : 0;\n const bottomTwips = pgMar ? parseIntAttr(attr(pgMar, \"w:bottom\"), 0) : 0;\n const leftTwips = pgMar ? parseIntAttr(attr(pgMar, \"w:left\"), 0) : 0;\n const rightTwips = pgMar ? parseIntAttr(attr(pgMar, \"w:right\"), 0) : 0;\n\n if (widthTwips <= 0 && heightTwips <= 0 && topTwips <= 0 && leftTwips <= 0) {\n return undefined;\n }\n\n const width = widthTwips > 0 ? twipsToPx(widthTwips) : 794;\n const height = heightTwips > 0 ? twipsToPx(heightTwips) : 1123;\n const settings: PageSettings = {\n width,\n height,\n marginTop: twipsToPx(topTwips || 0),\n marginBottom: twipsToPx(bottomTwips || 0),\n marginLeft: twipsToPx(leftTwips || 0),\n marginRight: twipsToPx(rightTwips || 0),\n };\n settings.preset = detectPreset(settings.width, settings.height);\n return settings;\n}\n"],"mappings":"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","names":["import_core","JSZip","attrs"]}
|
package/dist/index.js
CHANGED
|
@@ -341,6 +341,10 @@ function paragraphToBlock(p, ctx, numbering) {
|
|
|
341
341
|
listKind: resolved?.listKind ?? "bullet",
|
|
342
342
|
listLevel: resolved?.listLevel ?? 0
|
|
343
343
|
};
|
|
344
|
+
if (resolved?.listKind === "ordered") {
|
|
345
|
+
if (resolved.ordinal != null) attrs2.listStart = resolved.ordinal;
|
|
346
|
+
if (resolved.listStyle) attrs2.listStyle = resolved.listStyle;
|
|
347
|
+
}
|
|
344
348
|
if (align) attrs2.align = align;
|
|
345
349
|
if (isRtl) attrs2.dir = "rtl";
|
|
346
350
|
return { type: "listItem", text, delta, attrs: attrs2 };
|
|
@@ -496,9 +500,19 @@ function emptyCell() {
|
|
|
496
500
|
}
|
|
497
501
|
|
|
498
502
|
// src/numbering.ts
|
|
503
|
+
var FMT_TO_LIST_STYLE = {
|
|
504
|
+
decimal: "decimal",
|
|
505
|
+
lowerLetter: "lower-alpha",
|
|
506
|
+
upperLetter: "upper-alpha",
|
|
507
|
+
lowerRoman: "lower-roman",
|
|
508
|
+
upperRoman: "upper-roman"
|
|
509
|
+
};
|
|
499
510
|
var NumberingResolver = class {
|
|
500
511
|
numIdToAbstract = /* @__PURE__ */ new Map();
|
|
501
512
|
abstractLevelFmt = /* @__PURE__ */ new Map();
|
|
513
|
+
abstractLevelStart = /* @__PURE__ */ new Map();
|
|
514
|
+
/** Contadores vivos por instância de lista (numId), indexados por nível. */
|
|
515
|
+
counters = /* @__PURE__ */ new Map();
|
|
502
516
|
constructor(numberingXml) {
|
|
503
517
|
if (!numberingXml) return;
|
|
504
518
|
for (const top of numberingXml) {
|
|
@@ -509,12 +523,16 @@ var NumberingResolver = class {
|
|
|
509
523
|
const abstractId = attr(child, "w:abstractNumId");
|
|
510
524
|
if (!abstractId) continue;
|
|
511
525
|
const levels = /* @__PURE__ */ new Map();
|
|
526
|
+
const starts = /* @__PURE__ */ new Map();
|
|
512
527
|
for (const lvl of findChildren(child, "w:lvl")) {
|
|
513
528
|
const ilvl = parseIntAttr(attr(lvl, "w:ilvl"), 0);
|
|
514
529
|
const fmt = attr(findChild(lvl, "w:numFmt") ?? {}, "w:val");
|
|
515
530
|
if (fmt) levels.set(ilvl, fmt);
|
|
531
|
+
const start = findChild(lvl, "w:start");
|
|
532
|
+
if (start) starts.set(ilvl, parseIntAttr(attr(start, "w:val"), 1));
|
|
516
533
|
}
|
|
517
534
|
this.abstractLevelFmt.set(abstractId, levels);
|
|
535
|
+
this.abstractLevelStart.set(abstractId, starts);
|
|
518
536
|
} else if (tag === "w:num") {
|
|
519
537
|
const numId = attr(child, "w:numId");
|
|
520
538
|
const abstractRef = findChild(child, "w:abstractNumId");
|
|
@@ -524,7 +542,12 @@ var NumberingResolver = class {
|
|
|
524
542
|
}
|
|
525
543
|
}
|
|
526
544
|
}
|
|
527
|
-
/**
|
|
545
|
+
/**
|
|
546
|
+
* Resolves a paragraph's `<w:numPr>` into `{listKind, listLevel, ordinal?,
|
|
547
|
+
* listStyle?}`, or null. STATEFUL for ordered lists: each call advances the
|
|
548
|
+
* per-`numId` counter (Word instance semantics) — call exactly once per
|
|
549
|
+
* numbered paragraph, in document order.
|
|
550
|
+
*/
|
|
528
551
|
resolve(numPr) {
|
|
529
552
|
if (!numPr) return null;
|
|
530
553
|
const ilvlRef = findChild(numPr, "w:ilvl");
|
|
@@ -538,9 +561,21 @@ var NumberingResolver = class {
|
|
|
538
561
|
return { listKind: "bullet", listLevel };
|
|
539
562
|
}
|
|
540
563
|
const levels = this.abstractLevelFmt.get(abstractId);
|
|
541
|
-
const fmt =
|
|
542
|
-
const
|
|
543
|
-
|
|
564
|
+
const fmt = levels?.get(listLevel) ?? "bullet";
|
|
565
|
+
const fmtLower = fmt.toLowerCase();
|
|
566
|
+
const listKind = fmtLower === "bullet" || fmtLower === "none" ? "bullet" : "ordered";
|
|
567
|
+
if (listKind === "bullet") return { listKind, listLevel };
|
|
568
|
+
const start = this.abstractLevelStart.get(abstractId)?.get(listLevel) ?? 1;
|
|
569
|
+
const c = this.counters.get(numId) ?? [];
|
|
570
|
+
c[listLevel] = c[listLevel] == null ? start : c[listLevel] + 1;
|
|
571
|
+
c.length = listLevel + 1;
|
|
572
|
+
this.counters.set(numId, c);
|
|
573
|
+
return {
|
|
574
|
+
listKind,
|
|
575
|
+
listLevel,
|
|
576
|
+
ordinal: c[listLevel],
|
|
577
|
+
listStyle: FMT_TO_LIST_STYLE[fmt] ?? "decimal"
|
|
578
|
+
};
|
|
544
579
|
}
|
|
545
580
|
};
|
|
546
581
|
function clampLevel(n) {
|
|
@@ -604,9 +639,44 @@ async function docxBlobToDocument(input) {
|
|
|
604
639
|
if (blocks.length === 0) {
|
|
605
640
|
blocks.push({ type: "paragraph", text: "", delta: [], attrs: {} });
|
|
606
641
|
}
|
|
642
|
+
pruneNonLeaderListStarts(blocks);
|
|
607
643
|
const pageSettings = sectPrToPageSettings(findChild(body, "w:sectPr"));
|
|
608
644
|
return pageSettings ? { blocks, pageSettings } : { blocks };
|
|
609
645
|
}
|
|
646
|
+
function pruneNonLeaderListStarts(blocks) {
|
|
647
|
+
let grupoAtivo = false;
|
|
648
|
+
let grupoStyle;
|
|
649
|
+
let ordinais = [];
|
|
650
|
+
const resetGrupo = () => {
|
|
651
|
+
grupoAtivo = false;
|
|
652
|
+
grupoStyle = void 0;
|
|
653
|
+
ordinais = [];
|
|
654
|
+
};
|
|
655
|
+
for (const block of blocks) {
|
|
656
|
+
if (block.type !== "listItem") {
|
|
657
|
+
resetGrupo();
|
|
658
|
+
continue;
|
|
659
|
+
}
|
|
660
|
+
if ((block.attrs.listKind ?? "bullet") !== "ordered") {
|
|
661
|
+
resetGrupo();
|
|
662
|
+
continue;
|
|
663
|
+
}
|
|
664
|
+
const level = block.attrs.listLevel ?? 0;
|
|
665
|
+
const ordinal = typeof block.attrs.listStart === "number" ? block.attrs.listStart : 1;
|
|
666
|
+
const mesmoNivelSequencial = ordinais[level] != null && ordinal === ordinais[level] + 1;
|
|
667
|
+
const entrandoEmNivelNovo = ordinais[level] == null && level > 0 && ordinal === 1;
|
|
668
|
+
const continuaGrupo = grupoAtivo && block.attrs.listStyle === grupoStyle && (mesmoNivelSequencial || entrandoEmNivelNovo);
|
|
669
|
+
if (continuaGrupo) {
|
|
670
|
+
delete block.attrs.listStart;
|
|
671
|
+
} else {
|
|
672
|
+
grupoAtivo = true;
|
|
673
|
+
grupoStyle = block.attrs.listStyle;
|
|
674
|
+
ordinais = [];
|
|
675
|
+
}
|
|
676
|
+
ordinais[level] = ordinal;
|
|
677
|
+
ordinais.length = level + 1;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
610
680
|
async function docxBlobToEditorDocument(input) {
|
|
611
681
|
const serialized = await docxBlobToDocument(input);
|
|
612
682
|
return EditorDocument.fromJSON(serialized);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/docx.ts","../src/parse-xml.ts","../src/units.ts","../src/images.ts","../src/runs.ts","../src/paragraphs.ts","../src/tables.ts","../src/numbering.ts","../src/page-settings.ts"],"sourcesContent":["import { EditorDocument, type SerializedBlock, type SerializedDocument } from \"@sofereditor/core\";\nimport { readDocx, childrenOf, tagOf, findChild, type OoxmlNode } from \"./parse-xml\";\nimport { paragraphToBlock } from \"./paragraphs\";\nimport { tableToBlock } from \"./tables\";\nimport { NumberingResolver } from \"./numbering\";\nimport { sectPrToPageSettings } from \"./page-settings\";\nimport type { RunContext } from \"./runs\";\n\n/**\n * Read a `.docx` (OOXML) Blob/ArrayBuffer/Uint8Array and produce a\n * `SerializedDocument` ready to feed `EditorDocument.fromJSON` (or\n * `loadFromJSON` on an existing instance).\n *\n * The mapping is the inverse of `@sofereditor/export-docx`. Round-trip is exact for\n * documents the editor produced; documents authored externally (Word, Google\n * Docs export) load with marks/lists/tables/images recognized and unsupported\n * features dropped silently.\n */\nexport async function docxBlobToDocument(\n input: Blob | ArrayBuffer | Uint8Array,\n): Promise<SerializedDocument> {\n const file = await readDocx(input);\n const numbering = new NumberingResolver(file.numberingXml);\n const ctx: RunContext = {\n relationships: file.relationships,\n mediaBytes: file.mediaBytes,\n };\n\n const body = findBody(file.documentXml);\n if (!body) return { blocks: [{ type: \"paragraph\", text: \"\", delta: [], attrs: {} }] };\n\n const blocks: SerializedBlock[] = [];\n for (const child of childrenOf(body)) {\n const tag = tagOf(child);\n if (tag === \"w:p\") {\n blocks.push(paragraphToBlock(child, ctx, numbering));\n } else if (tag === \"w:tbl\") {\n blocks.push(tableToBlock(child, ctx));\n }\n // w:sectPr is parsed below (page settings); other body-level metadata ignored.\n }\n\n if (blocks.length === 0) {\n blocks.push({ type: \"paragraph\", text: \"\", delta: [], attrs: {} });\n }\n\n const pageSettings = sectPrToPageSettings(findChild(body, \"w:sectPr\"));\n return pageSettings ? { blocks, pageSettings } : { blocks };\n}\n\n/** Convenience: parse → instantiate a fresh `EditorDocument`. */\nexport async function docxBlobToEditorDocument(\n input: Blob | ArrayBuffer | Uint8Array,\n): Promise<EditorDocument> {\n const serialized = await docxBlobToDocument(input);\n return EditorDocument.fromJSON(serialized);\n}\n\nfunction findBody(documentXml: OoxmlNode[]): OoxmlNode | undefined {\n for (const top of documentXml) {\n if (tagOf(top) === \"w:document\") {\n const body = findChild(top, \"w:body\");\n if (body) return body;\n }\n }\n return undefined;\n}\n","import JSZip from \"jszip\";\nimport { XMLParser } from \"fast-xml-parser\";\n\n/**\n * fast-xml-parser with `preserveOrder: true` produces a list of single-key\n * objects per element. Each element is either:\n *\n * - A tag node: `{ \"<tagName>\": <children-array>, \":@\"?: <attrs> }`\n * - A text node: `{ \"#text\": <string> }`\n *\n * Attributes are prefixed with `@_`. The `:@` key holds attributes for the\n * surrounding tag. Children preserve original document order, which matters\n * for paragraph runs (bold word followed by italic word).\n */\nexport type OoxmlNode = Record<string, unknown>;\n\nconst parser = new XMLParser({\n ignoreAttributes: false,\n attributeNamePrefix: \"@_\",\n preserveOrder: true,\n trimValues: false, // keep whitespace inside <w:t>\n parseAttributeValue: false,\n parseTagValue: false,\n});\n\nexport interface DocxFile {\n documentXml: OoxmlNode[];\n numberingXml?: OoxmlNode[];\n /** rId → target path (inside the zip), e.g. \"media/image1.png\". */\n relationships: Map<string, string>;\n /** zip path (without leading \"word/\") → bytes for embedded media. */\n mediaBytes: Map<string, Uint8Array>;\n}\n\nexport async function readDocx(input: Blob | ArrayBuffer | Uint8Array): Promise<DocxFile> {\n const data =\n input instanceof Uint8Array\n ? input\n : input instanceof ArrayBuffer\n ? new Uint8Array(input)\n : new Uint8Array(await (input as Blob).arrayBuffer());\n\n const zip = await JSZip.loadAsync(data);\n const documentXml = await readXml(zip, \"word/document.xml\");\n if (!documentXml) throw new Error(\"Invalid .docx: missing word/document.xml\");\n\n const numberingXml = await readXml(zip, \"word/numbering.xml\");\n const relsXml = await readXml(zip, \"word/_rels/document.xml.rels\");\n const relationships = parseRelationships(relsXml);\n\n const mediaBytes = new Map<string, Uint8Array>();\n const mediaFolder = zip.folder(\"word/media\");\n if (mediaFolder) {\n const promises: Promise<void>[] = [];\n mediaFolder.forEach((relativePath, file) => {\n if (file.dir) return;\n promises.push(\n file.async(\"uint8array\").then((bytes) => {\n mediaBytes.set(`media/${relativePath}`, bytes);\n }),\n );\n });\n await Promise.all(promises);\n }\n\n return { documentXml, numberingXml, relationships, mediaBytes };\n}\n\nasync function readXml(zip: JSZip, path: string): Promise<OoxmlNode[] | undefined> {\n const entry = zip.file(path);\n if (!entry) return undefined;\n const text = await entry.async(\"string\");\n return parser.parse(text) as OoxmlNode[];\n}\n\nfunction parseRelationships(nodes: OoxmlNode[] | undefined): Map<string, string> {\n const out = new Map<string, string>();\n if (!nodes) return out;\n // <Relationships><Relationship Id=\"rId1\" Type=\"...\" Target=\"media/image1.png\"/>...\n for (const top of nodes) {\n const children = top[\"Relationships\"];\n if (!Array.isArray(children)) continue;\n for (const child of children as OoxmlNode[]) {\n if (!(\"Relationship\" in child)) continue;\n const attrs = (child[\":@\"] ?? {}) as Record<string, unknown>;\n const id = attrs[\"@_Id\"];\n const target = attrs[\"@_Target\"];\n if (typeof id === \"string\" && typeof target === \"string\") {\n out.set(id, target);\n }\n }\n }\n return out;\n}\n\n// ---------- generic walkers over preserveOrder shape ----------\n\n/** Returns the tag name (e.g. \"w:p\") of a preserveOrder element, or null for text. */\nexport function tagOf(node: OoxmlNode): string | null {\n for (const key of Object.keys(node)) {\n if (key === \":@\") continue;\n return key;\n }\n return null;\n}\n\n/** Returns the children array of an element, or [] when none. */\nexport function childrenOf(node: OoxmlNode): OoxmlNode[] {\n const tag = tagOf(node);\n if (!tag) return [];\n const v = node[tag];\n return Array.isArray(v) ? (v as OoxmlNode[]) : [];\n}\n\n/** Returns the attribute bag (already with `@_` prefix) for an element. */\nexport function attrsOf(node: OoxmlNode): Record<string, unknown> {\n return ((node[\":@\"] ?? {}) as Record<string, unknown>) ?? {};\n}\n\n/** Read a single `@_key` attribute as a string. */\nexport function attr(node: OoxmlNode, key: string): string | undefined {\n const v = attrsOf(node)[`@_${key}`];\n return typeof v === \"string\" ? v : undefined;\n}\n\n/** Find the first direct child with the given tag name. */\nexport function findChild(node: OoxmlNode, tag: string): OoxmlNode | undefined {\n for (const child of childrenOf(node)) {\n if (tagOf(child) === tag) return child;\n }\n return undefined;\n}\n\n/** Find all direct children with the given tag name. */\nexport function findChildren(node: OoxmlNode, tag: string): OoxmlNode[] {\n const out: OoxmlNode[] = [];\n for (const child of childrenOf(node)) {\n if (tagOf(child) === tag) out.push(child);\n }\n return out;\n}\n\n/** Recursively collect text nodes' concatenated content. */\nexport function textOf(node: OoxmlNode): string {\n let out = \"\";\n for (const child of childrenOf(node)) {\n if (\"#text\" in child) {\n const t = child[\"#text\"];\n if (typeof t === \"string\") out += t;\n } else {\n out += textOf(child);\n }\n }\n return out;\n}\n","/**\n * Unit conversions between OOXML and the editor's serialized format.\n * These are the inverses of the helpers in `@sofereditor/export-docx/src/docx.ts`.\n */\n\n/** docx half-points → CSS pt string. 24 (half-pt) → \"12pt\". */\nexport function halfPointsToCssPt(halfPoints: number): string | undefined {\n if (!Number.isFinite(halfPoints) || halfPoints <= 0) return undefined;\n const pt = halfPoints / 2;\n return `${stripTrailingZeros(pt)}pt`;\n}\n\n/** OOXML RRGGBB (no '#') → CSS hex with leading '#'. */\nexport function docxHexToCssColor(hex: string | undefined): string | undefined {\n if (!hex) return undefined;\n const m = /^[0-9a-f]{6}$/i.exec(hex.trim());\n if (!m) return undefined;\n return `#${hex.toLowerCase()}`;\n}\n\n/** OOXML alignment value → editor AlignValue. */\nexport function parseAlign(val: string | undefined): \"left\" | \"center\" | \"right\" | \"justify\" | undefined {\n if (!val) return undefined;\n switch (val.toLowerCase()) {\n case \"left\":\n case \"start\":\n return \"left\";\n case \"center\":\n return \"center\";\n case \"right\":\n case \"end\":\n return \"right\";\n case \"both\":\n case \"distribute\":\n case \"justify\":\n return \"justify\";\n default:\n return undefined;\n }\n}\n\n/** Parse XML attribute that should be a positive integer. */\nexport function parseIntAttr(val: unknown, fallback = 0): number {\n if (typeof val === \"number\" && Number.isFinite(val)) return Math.trunc(val);\n if (typeof val !== \"string\") return fallback;\n const n = Number.parseInt(val, 10);\n return Number.isFinite(n) ? n : fallback;\n}\n\nfunction stripTrailingZeros(n: number): string {\n // 12 → \"12\", 12.5 → \"12.5\"\n return Number.isInteger(n) ? n.toString() : n.toFixed(2).replace(/\\.?0+$/, \"\");\n}\n","import type { ImageEmbed } from \"@sofereditor/core\";\nimport { attr, childrenOf, tagOf, type OoxmlNode } from \"./parse-xml\";\nimport { parseIntAttr } from \"./units\";\n\n/** 1 inch = 914400 EMU = 96 px → 1 px = 9525 EMU. */\nconst EMU_PER_PX = 9525;\n\nconst MIME_BY_EXT: Record<string, string> = {\n png: \"image/png\",\n jpg: \"image/jpeg\",\n jpeg: \"image/jpeg\",\n gif: \"image/gif\",\n bmp: \"image/bmp\",\n svg: \"image/svg+xml\",\n};\n\nexport interface ImageContext {\n relationships: Map<string, string>;\n mediaBytes: Map<string, Uint8Array>;\n}\n\n/**\n * Walk a `<w:drawing>` node and return an `ImageEmbed` if it contains a\n * recognized inline picture. Returns null for unsupported drawings (shapes,\n * charts, etc.).\n */\nexport function extractImageFromDrawing(\n drawing: OoxmlNode,\n ctx: ImageContext,\n): ImageEmbed | null {\n // The interesting bits live deep inside: a:blip carries `r:embed`, and\n // wp:extent carries cx/cy. We do a generic walk because the wrapping nodes\n // differ between inline (`wp:inline`) and anchored (`wp:anchor`) drawings.\n let embedId: string | undefined;\n let cx: number | undefined;\n let cy: number | undefined;\n\n walk(drawing, (n) => {\n const tag = tagOf(n);\n if (!tag) return;\n if (tag === \"a:blip\") {\n const id = attr(n, \"r:embed\") ?? attr(n, \"r:link\");\n if (id) embedId = id;\n } else if (tag === \"wp:extent\") {\n cx = parseIntAttr(attr(n, \"cx\"));\n cy = parseIntAttr(attr(n, \"cy\"));\n }\n });\n\n if (!embedId) return null;\n const target = ctx.relationships.get(embedId);\n if (!target) return null;\n // Relationship targets are typically \"media/image1.png\"; the zip lookup uses\n // the same path (we stored bytes keyed under \"media/<file>\").\n const bytes = ctx.mediaBytes.get(target);\n if (!bytes) return null;\n\n const ext = extensionOf(target);\n const mime = MIME_BY_EXT[ext] ?? \"image/png\";\n const src = `data:${mime};base64,${bytesToBase64(bytes)}`;\n const widthPx = cx != null ? Math.max(1, Math.round(cx / EMU_PER_PX)) : 100;\n const heightPx = cy != null ? Math.max(1, Math.round(cy / EMU_PER_PX)) : 100;\n\n return { type: \"image\", src, width: widthPx, height: heightPx };\n}\n\nfunction walk(node: OoxmlNode, visit: (n: OoxmlNode) => void): void {\n visit(node);\n for (const child of childrenOf(node)) {\n if (\"#text\" in child) continue;\n walk(child, visit);\n }\n}\n\nfunction extensionOf(path: string): string {\n const m = /\\.([a-z0-9]+)$/i.exec(path);\n return m ? m[1].toLowerCase() : \"\";\n}\n\nfunction bytesToBase64(bytes: Uint8Array): string {\n // Browser path.\n if (typeof btoa === \"function\") {\n let bin = \"\";\n const CHUNK = 0x8000;\n for (let i = 0; i < bytes.length; i += CHUNK) {\n bin += String.fromCharCode.apply(null, Array.from(bytes.subarray(i, i + CHUNK)));\n }\n return btoa(bin);\n }\n // Node fallback.\n return Buffer.from(bytes).toString(\"base64\");\n}\n","import type { DeltaOp, MarkAttrs } from \"@sofereditor/core\";\nimport {\n attr,\n childrenOf,\n findChild,\n tagOf,\n type OoxmlNode,\n} from \"./parse-xml\";\nimport { docxHexToCssColor, halfPointsToCssPt } from \"./units\";\nimport { extractImageFromDrawing, type ImageContext } from \"./images\";\n\nexport interface RunContext extends ImageContext {}\n\n/**\n * Walk a paragraph's children (post `<w:pPr>`) and emit a `DeltaOp[]`. Combines\n * adjacent runs that share the same mark set into a single op for parity with\n * the export — Y.Text.applyDelta would merge them anyway, but pre-merging keeps\n * round-trip output stable.\n */\nexport function paragraphChildrenToDelta(children: OoxmlNode[], ctx: RunContext): DeltaOp[] {\n const ops: DeltaOp[] = [];\n for (const child of children) {\n const tag = tagOf(child);\n if (!tag) continue;\n if (tag === \"w:pPr\") continue;\n if (tag === \"w:r\") {\n collectRun(child, ctx, undefined, ops);\n } else if (tag === \"w:hyperlink\") {\n // hyperlinks carry an r:id that maps via relationships to the href.\n const rId = attr(child, \"r:id\");\n const href = rId ? ctx.relationships.get(rId) : undefined;\n const linkMark: MarkAttrs | undefined = href ? { link: { href } } : undefined;\n for (const sub of childrenOf(child)) {\n if (tagOf(sub) === \"w:r\") collectRun(sub, ctx, linkMark, ops);\n }\n }\n }\n return mergeAdjacent(ops);\n}\n\nfunction collectRun(\n run: OoxmlNode,\n ctx: RunContext,\n wrappingMarks: MarkAttrs | undefined,\n out: DeltaOp[],\n): void {\n const marks = mergeMarks(wrappingMarks, runMarks(findChild(run, \"w:rPr\")));\n for (const child of childrenOf(run)) {\n const tag = tagOf(child);\n if (!tag) continue;\n if (tag === \"w:t\") {\n const text = textContent(child);\n if (text.length > 0) push(out, text, marks);\n } else if (tag === \"w:tab\") {\n push(out, \"\\t\", marks);\n } else if (tag === \"w:br\") {\n // Treat w:br type=\"page\" as also a soft break for the model — we have no\n // explicit page-break node in the schema; pagination is computed live.\n push(out, \"\\n\", marks);\n } else if (tag === \"w:drawing\") {\n const embed = extractImageFromDrawing(child, ctx);\n if (embed) out.push({ insert: embed });\n }\n // Other run children (w:sym, w:fldChar, etc.) are silently dropped.\n }\n}\n\nfunction runMarks(rPr: OoxmlNode | undefined): MarkAttrs {\n const m: MarkAttrs = {};\n if (!rPr) return m;\n for (const child of childrenOf(rPr)) {\n const tag = tagOf(child);\n if (!tag) continue;\n switch (tag) {\n case \"w:b\":\n if (!isFalse(attr(child, \"w:val\"))) m.bold = true;\n break;\n case \"w:i\":\n if (!isFalse(attr(child, \"w:val\"))) m.italic = true;\n break;\n case \"w:u\": {\n const val = attr(child, \"w:val\");\n if (val && val.toLowerCase() !== \"none\") m.underline = true;\n break;\n }\n case \"w:strike\":\n if (!isFalse(attr(child, \"w:val\"))) m.strike = true;\n break;\n case \"w:color\": {\n const hex = attr(child, \"w:val\");\n const css = docxHexToCssColor(hex);\n if (css) m.color = css;\n break;\n }\n // w:rFonts intentionally ignored: school standard is Arial for all\n // exams. Any font declared in the .docx is dropped on import so the\n // imported doc inherits Arial from `.ed-root` / PDF base stylesheet.\n case \"w:sz\": {\n const halfPts = Number.parseFloat(attr(child, \"w:val\") ?? \"\");\n const css = halfPointsToCssPt(halfPts);\n if (css) m.fontSize = css;\n break;\n }\n }\n }\n return m;\n}\n\nfunction mergeMarks(a: MarkAttrs | undefined, b: MarkAttrs): MarkAttrs {\n if (!a) return b;\n return { ...a, ...b };\n}\n\nfunction textContent(node: OoxmlNode): string {\n let out = \"\";\n for (const child of childrenOf(node)) {\n if (\"#text\" in child) {\n const t = child[\"#text\"];\n if (typeof t === \"string\") out += t;\n }\n }\n return out;\n}\n\nfunction isFalse(val: string | undefined): boolean {\n if (val == null) return false;\n const v = val.toLowerCase();\n return v === \"0\" || v === \"false\" || v === \"none\";\n}\n\nfunction push(out: DeltaOp[], text: string, marks: MarkAttrs): void {\n const op: DeltaOp =\n Object.keys(marks).length === 0 ? { insert: text } : { insert: text, attributes: { ...marks } };\n out.push(op);\n}\n\nfunction mergeAdjacent(ops: DeltaOp[]): DeltaOp[] {\n const out: DeltaOp[] = [];\n for (const op of ops) {\n const prev = out[out.length - 1];\n if (\n prev &&\n typeof prev.insert === \"string\" &&\n typeof op.insert === \"string\" &&\n sameMarks(prev.attributes, op.attributes)\n ) {\n prev.insert = prev.insert + op.insert;\n continue;\n }\n out.push(op);\n }\n return out;\n}\n\nfunction sameMarks(a: MarkAttrs | undefined, b: MarkAttrs | undefined): boolean {\n const ak = a ? Object.keys(a).sort() : [];\n const bk = b ? Object.keys(b).sort() : [];\n if (ak.length !== bk.length) return false;\n for (let i = 0; i < ak.length; i++) {\n if (ak[i] !== bk[i]) return false;\n const av = (a as Record<string, unknown>)[ak[i]];\n const bv = (b as Record<string, unknown>)[bk[i]];\n if (typeof av === \"object\" && av !== null && typeof bv === \"object\" && bv !== null) {\n if (JSON.stringify(av) !== JSON.stringify(bv)) return false;\n } else if (av !== bv) {\n return false;\n }\n }\n return true;\n}\n","import type { AlignValue, BlockAttrs, BlockType, DeltaOp, SerializedBlock } from \"@sofereditor/core\";\nimport {\n attr,\n childrenOf,\n findChild,\n tagOf,\n type OoxmlNode,\n} from \"./parse-xml\";\nimport { paragraphChildrenToDelta, type RunContext } from \"./runs\";\nimport { NumberingResolver } from \"./numbering\";\nimport { parseAlign } from \"./units\";\n\n/**\n * Map a `<w:p>` element to a SerializedBlock. Decides between\n * `paragraph / heading / blockquote / codeBlock / listItem` based on the\n * paragraph style + `w:pPr` properties — mirrors the heuristics encoded in\n * `@sofereditor/export-docx/src/docx.ts`.\n */\nexport function paragraphToBlock(\n p: OoxmlNode,\n ctx: RunContext,\n numbering: NumberingResolver,\n): SerializedBlock {\n const pPr = findChild(p, \"w:pPr\");\n const numPr = pPr ? findChild(pPr, \"w:numPr\") : undefined;\n const styleId = pPr ? attr(findChild(pPr, \"w:pStyle\") ?? {}, \"w:val\") : undefined;\n\n const delta = paragraphChildrenToDelta(childrenOf(p), ctx);\n const text = collectText(delta);\n const align = parseAlign(pPr ? attr(findChild(pPr, \"w:jc\") ?? {}, \"w:val\") : undefined);\n const isRtl = pPr ? !!findChild(pPr, \"w:bidi\") : false;\n\n // List? — numPr is the strongest signal.\n if (numPr) {\n const resolved = numbering.resolve(numPr);\n const attrs: BlockAttrs = {\n listKind: resolved?.listKind ?? \"bullet\",\n listLevel: resolved?.listLevel ?? 0,\n };\n if (align) attrs.align = align;\n if (isRtl) attrs.dir = \"rtl\";\n return { type: \"listItem\", text, delta, attrs };\n }\n\n // Heading?\n const headingLevel = styleId ? headingFromStyleId(styleId) : null;\n if (headingLevel != null) {\n const attrs: BlockAttrs = { level: headingLevel };\n if (align) attrs.align = align;\n if (isRtl) attrs.dir = \"rtl\";\n return { type: \"heading\", text, delta, attrs };\n }\n\n // Blockquote (export uses left border + 480 twip indent).\n if (pPr && hasLeftBorder(pPr)) {\n const attrs: BlockAttrs = {};\n if (align) attrs.align = align;\n if (isRtl) attrs.dir = \"rtl\";\n return { type: \"blockquote\", text, delta, attrs };\n }\n\n // Code block (export uses Consolas + light-gray shading).\n if (pPr && hasCodeBlockShading(pPr)) {\n const attrs: BlockAttrs = {};\n if (align) attrs.align = align;\n if (isRtl) attrs.dir = \"rtl\";\n return { type: \"codeBlock\", text, delta, attrs };\n }\n\n const attrs: BlockAttrs = {};\n if (align) attrs.align = align;\n if (isRtl) attrs.dir = \"rtl\";\n return { type: \"paragraph\", text, delta, attrs };\n}\n\nfunction collectText(delta: DeltaOp[]): string {\n let out = \"\";\n for (const op of delta) {\n if (typeof op.insert === \"string\") out += op.insert;\n }\n return out;\n}\n\nfunction headingFromStyleId(id: string): 1 | 2 | 3 | 4 | 5 | 6 | null {\n const m = /^Heading\\s*([1-6])$/i.exec(id);\n if (!m) return null;\n const n = Number.parseInt(m[1], 10);\n return (n as 1 | 2 | 3 | 4 | 5 | 6) ?? null;\n}\n\nfunction hasLeftBorder(pPr: OoxmlNode): boolean {\n const pBdr = findChild(pPr, \"w:pBdr\");\n if (!pBdr) return false;\n return !!findChild(pBdr, \"w:left\");\n}\n\nfunction hasCodeBlockShading(pPr: OoxmlNode): boolean {\n const shd = findChild(pPr, \"w:shd\");\n if (!shd) return false;\n const fill = attr(shd, \"w:fill\");\n if (!fill) return false;\n return fill.toLowerCase() === \"f1f5f9\";\n}\n\n/** Whitelist the block types this module produces (used by callers for typing). */\nexport type ParagraphBlockType = Exclude<BlockType, \"table\">;\n/** Whitelist the align values this module produces (used by callers for typing). */\nexport type ParagraphAlign = AlignValue;\n","import type { BlockAttrs, CellAttrs, DeltaOp, SerializedBlock, SerializedCell } from \"@sofereditor/core\";\nimport {\n attr,\n childrenOf,\n findChild,\n findChildren,\n tagOf,\n type OoxmlNode,\n} from \"./parse-xml\";\nimport { paragraphChildrenToDelta, type RunContext } from \"./runs\";\nimport { parseIntAttr } from \"./units\";\n\n/**\n * Map a `<w:tbl>` element to a SerializedBlock(table). The output `cells` array\n * is row-major with `rows * cols` entries — covered slots are filled with\n * `{attrs: {covered: true}}` placeholders so it matches the invariant required\n * by `@sofereditor/core`'s `EditorDocument`.\n */\nexport function tableToBlock(tbl: OoxmlNode, ctx: RunContext): SerializedBlock {\n const tblGrid = findChild(tbl, \"w:tblGrid\");\n const gridCols = tblGrid ? findChildren(tblGrid, \"w:gridCol\") : [];\n const trs = findChildren(tbl, \"w:tr\");\n\n // The docx writer (and Word itself) may emit fewer `<w:gridCol>` entries than\n // the table's logical column count when a row has merged cells. Take the max\n // of (declared gridCols, widest row's total gridSpan) to stay robust.\n let cols = gridCols.length;\n for (const tr of trs) {\n const tcs = findChildren(tr, \"w:tc\");\n let count = 0;\n for (const tc of tcs) count += gridSpanOf(tc);\n if (count > cols) cols = count;\n }\n if (cols < 1) cols = 1;\n const rows = trs.length;\n\n // Build a row-major grid of slots. Each slot is either a real cell or marked\n // as covered. We track which (row, col) is the anchor for vMerge groups.\n const slots: Array<SerializedCell | null> = new Array(rows * cols).fill(null);\n // Anchor of the active vMerge per column index; resets when a non-merge cell\n // is placed in the same column.\n const vMergeAnchorByCol = new Map<number, { row: number; col: number }>();\n\n for (let r = 0; r < rows; r++) {\n const tr = trs[r];\n let cursor = 0;\n for (const tc of findChildren(tr, \"w:tc\")) {\n // Advance the cursor past already-occupied (covered-from-above) slots.\n while (cursor < cols && slots[r * cols + cursor] !== null) cursor++;\n if (cursor >= cols) break;\n\n const tcPr = findChild(tc, \"w:tcPr\");\n const gridSpan = gridSpanOf(tc);\n const vMergeNode = tcPr ? findChild(tcPr, \"w:vMerge\") : undefined;\n const vMergeVal = vMergeNode ? (attr(vMergeNode, \"w:val\") ?? \"continue\") : null;\n\n if (vMergeNode && vMergeVal !== \"restart\") {\n // Continuation of a vertical merge. Cover this row, and bump the anchor's\n // rowspan if we can find it.\n const anchor = vMergeAnchorByCol.get(cursor);\n if (anchor) {\n const anchorIdx = anchor.row * cols + anchor.col;\n const a = slots[anchorIdx];\n if (a) {\n a.attrs = { ...(a.attrs ?? {}), rowspan: (a.attrs?.rowspan ?? 1) + 1 };\n }\n }\n for (let c = 0; c < gridSpan && cursor + c < cols; c++) {\n slots[r * cols + cursor + c] = coveredCell();\n }\n cursor += gridSpan;\n continue;\n }\n\n // Real cell: build its delta + attrs.\n const delta = cellChildrenToDelta(tc, ctx);\n const text = textOfDelta(delta);\n const cellAttrs: CellAttrs = {};\n if (gridSpan > 1) cellAttrs.colspan = gridSpan;\n // rowspan starts at 1 — vMerge continuations bump it.\n\n const realCell: SerializedCell = { text, delta, attrs: cellAttrs };\n slots[r * cols + cursor] = realCell;\n\n // Mark horizontally-covered slots from gridSpan.\n for (let c = 1; c < gridSpan && cursor + c < cols; c++) {\n slots[r * cols + cursor + c] = coveredCell();\n }\n\n if (vMergeVal === \"restart\") {\n vMergeAnchorByCol.set(cursor, { row: r, col: cursor });\n } else {\n vMergeAnchorByCol.delete(cursor);\n }\n cursor += gridSpan;\n }\n\n // Fill any trailing un-touched slots in this row with empty placeholders so\n // the row-major invariant holds (length = rows * cols).\n for (let c = 0; c < cols; c++) {\n if (slots[r * cols + c] === null) {\n slots[r * cols + c] = emptyCell();\n }\n }\n }\n\n const cells: SerializedCell[] = slots.map((s) => s ?? emptyCell());\n\n const attrs: BlockAttrs = { rows, cols };\n return { type: \"table\", text: \"\", delta: [], attrs, cells };\n}\n\nfunction gridSpanOf(tc: OoxmlNode): number {\n const tcPr = findChild(tc, \"w:tcPr\");\n if (!tcPr) return 1;\n const gs = findChild(tcPr, \"w:gridSpan\");\n if (!gs) return 1;\n const n = parseIntAttr(attr(gs, \"w:val\"), 1);\n return Math.max(1, n);\n}\n\nfunction cellChildrenToDelta(tc: OoxmlNode, ctx: RunContext): DeltaOp[] {\n // A cell can contain multiple paragraphs; we concat their deltas with a\n // newline between adjacent ones to preserve visual separation. The cell\n // model in @sofereditor/core is a single Y.Text, so we flatten.\n const out: DeltaOp[] = [];\n let first = true;\n for (const child of childrenOf(tc)) {\n if (tagOf(child) !== \"w:p\") continue;\n if (!first) out.push({ insert: \"\\n\" });\n first = false;\n out.push(...paragraphChildrenToDelta(childrenOf(child), ctx));\n }\n return out;\n}\n\nfunction textOfDelta(delta: DeltaOp[]): string {\n let out = \"\";\n for (const op of delta) {\n if (typeof op.insert === \"string\") out += op.insert;\n }\n return out;\n}\n\nfunction coveredCell(): SerializedCell {\n return { text: \"\", delta: [], attrs: { covered: true } };\n}\n\nfunction emptyCell(): SerializedCell {\n return { text: \"\", delta: [], attrs: {} };\n}\n","import type { ListKind } from \"@sofereditor/core\";\nimport {\n attr,\n childrenOf,\n findChild,\n findChildren,\n tagOf,\n type OoxmlNode,\n} from \"./parse-xml\";\nimport { parseIntAttr } from \"./units\";\n\n/**\n * Resolves per-paragraph `<w:numPr>` into the editor's `{listKind, listLevel}`.\n *\n * docx numbering is two-step:\n * 1. paragraphs reference a `numId` and an `ilvl`\n * 2. each `<w:num numId=\"...\">` points to a `<w:abstractNum>` via `<w:abstractNumId>`\n * 3. each `<w:lvl ilvl=\"...\">` declares a `<w:numFmt val=\"bullet|decimal|...\">`\n *\n * The export side uses two hardcoded reference names (\"ed-bullet\" / \"ed-ordered\"),\n * but Word-authored documents use arbitrary `numId`s — we resolve by reading the\n * `numFmt` of the target level.\n */\nexport class NumberingResolver {\n private numIdToAbstract = new Map<string, string>();\n private abstractLevelFmt = new Map<string, Map<number, string>>();\n\n constructor(numberingXml: OoxmlNode[] | undefined) {\n if (!numberingXml) return;\n for (const top of numberingXml) {\n if (tagOf(top) !== \"w:numbering\") continue;\n for (const child of childrenOf(top)) {\n const tag = tagOf(child);\n if (tag === \"w:abstractNum\") {\n const abstractId = attr(child, \"w:abstractNumId\");\n if (!abstractId) continue;\n const levels = new Map<number, string>();\n for (const lvl of findChildren(child, \"w:lvl\")) {\n const ilvl = parseIntAttr(attr(lvl, \"w:ilvl\"), 0);\n const fmt = attr(findChild(lvl, \"w:numFmt\") ?? {}, \"w:val\");\n if (fmt) levels.set(ilvl, fmt);\n }\n this.abstractLevelFmt.set(abstractId, levels);\n } else if (tag === \"w:num\") {\n const numId = attr(child, \"w:numId\");\n const abstractRef = findChild(child, \"w:abstractNumId\");\n const abstractId = abstractRef ? attr(abstractRef, \"w:val\") : undefined;\n if (numId && abstractId) this.numIdToAbstract.set(numId, abstractId);\n }\n }\n }\n }\n\n /** Returns `{listKind, listLevel}` for a given paragraph's `<w:numPr>` node, or null. */\n resolve(numPr: OoxmlNode | undefined): { listKind: ListKind; listLevel: number } | null {\n if (!numPr) return null;\n const ilvlRef = findChild(numPr, \"w:ilvl\");\n const numIdRef = findChild(numPr, \"w:numId\");\n if (!numIdRef) return null;\n const numId = attr(numIdRef, \"w:val\");\n if (!numId) return null;\n const listLevel = clampLevel(parseIntAttr(ilvlRef ? attr(ilvlRef, \"w:val\") : undefined, 0));\n const abstractId = this.numIdToAbstract.get(numId);\n if (abstractId == null) {\n // Numbering refs the export side defines without a numbering.xml entry visible\n // to us (the export-docx pipeline generates them dynamically via the docx lib).\n // Fall back by inspecting the numId itself when it is a known sentinel.\n return { listKind: \"bullet\", listLevel };\n }\n const levels = this.abstractLevelFmt.get(abstractId);\n const fmt = (levels?.get(listLevel) ?? \"bullet\").toLowerCase();\n const listKind: ListKind = fmt === \"bullet\" || fmt === \"none\" ? \"bullet\" : \"ordered\";\n return { listKind, listLevel };\n }\n}\n\nfunction clampLevel(n: number): number {\n if (!Number.isFinite(n)) return 0;\n return Math.max(0, Math.min(5, Math.trunc(n)));\n}\n","import { detectPreset, mmToPx, type PageSettings } from \"@sofereditor/core\";\nimport { attr, findChild, type OoxmlNode } from \"./parse-xml\";\nimport { parseIntAttr } from \"./units\";\n\n/**\n * 1 inch = 1440 twips = 25.4 mm. So 1 twip = 25.4/1440 mm.\n *\n * Page size lives in `<w:sectPr><w:pgSz w:w=\"...\" w:h=\"...\"/></w:sectPr>` and\n * margins in `<w:pgMar w:top=\"...\" w:bottom=\"...\" w:left=\"...\" w:right=\"...\"/>`,\n * all in twips. This is the inverse of `sectionPropertiesFor` in\n * `@sofereditor/export-docx`.\n */\nconst MM_PER_TWIP = 25.4 / 1440;\n\nfunction twipsToPx(twips: number): number {\n return mmToPx(twips * MM_PER_TWIP);\n}\n\nexport function sectPrToPageSettings(\n sectPr: OoxmlNode | undefined,\n): PageSettings | undefined {\n if (!sectPr) return undefined;\n const pgSz = findChild(sectPr, \"w:pgSz\");\n const pgMar = findChild(sectPr, \"w:pgMar\");\n if (!pgSz && !pgMar) return undefined;\n\n const widthTwips = pgSz ? parseIntAttr(attr(pgSz, \"w:w\"), 0) : 0;\n const heightTwips = pgSz ? parseIntAttr(attr(pgSz, \"w:h\"), 0) : 0;\n const topTwips = pgMar ? parseIntAttr(attr(pgMar, \"w:top\"), 0) : 0;\n const bottomTwips = pgMar ? parseIntAttr(attr(pgMar, \"w:bottom\"), 0) : 0;\n const leftTwips = pgMar ? parseIntAttr(attr(pgMar, \"w:left\"), 0) : 0;\n const rightTwips = pgMar ? parseIntAttr(attr(pgMar, \"w:right\"), 0) : 0;\n\n if (widthTwips <= 0 && heightTwips <= 0 && topTwips <= 0 && leftTwips <= 0) {\n return undefined;\n }\n\n const width = widthTwips > 0 ? twipsToPx(widthTwips) : 794;\n const height = heightTwips > 0 ? twipsToPx(heightTwips) : 1123;\n const settings: PageSettings = {\n width,\n height,\n marginTop: twipsToPx(topTwips || 0),\n marginBottom: twipsToPx(bottomTwips || 0),\n marginLeft: twipsToPx(leftTwips || 0),\n marginRight: twipsToPx(rightTwips || 0),\n };\n settings.preset = detectPreset(settings.width, settings.height);\n return settings;\n}\n"],"mappings":"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","names":["attrs"]}
|
|
1
|
+
{"version":3,"sources":["../src/docx.ts","../src/parse-xml.ts","../src/units.ts","../src/images.ts","../src/runs.ts","../src/paragraphs.ts","../src/tables.ts","../src/numbering.ts","../src/page-settings.ts"],"sourcesContent":["import { EditorDocument, type SerializedBlock, type SerializedDocument } from \"@sofereditor/core\";\nimport { readDocx, childrenOf, tagOf, findChild, type OoxmlNode } from \"./parse-xml\";\nimport { paragraphToBlock } from \"./paragraphs\";\nimport { tableToBlock } from \"./tables\";\nimport { NumberingResolver } from \"./numbering\";\nimport { sectPrToPageSettings } from \"./page-settings\";\nimport type { RunContext } from \"./runs\";\n\n/**\n * Read a `.docx` (OOXML) Blob/ArrayBuffer/Uint8Array and produce a\n * `SerializedDocument` ready to feed `EditorDocument.fromJSON` (or\n * `loadFromJSON` on an existing instance).\n *\n * The mapping is the inverse of `@sofereditor/export-docx`. Round-trip is exact for\n * documents the editor produced; documents authored externally (Word, Google\n * Docs export) load with marks/lists/tables/images recognized and unsupported\n * features dropped silently.\n */\nexport async function docxBlobToDocument(\n input: Blob | ArrayBuffer | Uint8Array,\n): Promise<SerializedDocument> {\n const file = await readDocx(input);\n const numbering = new NumberingResolver(file.numberingXml);\n const ctx: RunContext = {\n relationships: file.relationships,\n mediaBytes: file.mediaBytes,\n };\n\n const body = findBody(file.documentXml);\n if (!body) return { blocks: [{ type: \"paragraph\", text: \"\", delta: [], attrs: {} }] };\n\n const blocks: SerializedBlock[] = [];\n for (const child of childrenOf(body)) {\n const tag = tagOf(child);\n if (tag === \"w:p\") {\n blocks.push(paragraphToBlock(child, ctx, numbering));\n } else if (tag === \"w:tbl\") {\n blocks.push(tableToBlock(child, ctx));\n }\n // w:sectPr is parsed below (page settings); other body-level metadata ignored.\n }\n\n if (blocks.length === 0) {\n blocks.push({ type: \"paragraph\", text: \"\", delta: [], attrs: {} });\n }\n\n pruneNonLeaderListStarts(blocks);\n\n const pageSettings = sectPrToPageSettings(findChild(body, \"w:sectPr\"));\n return pageSettings ? { blocks, pageSettings } : { blocks };\n}\n\n/**\n * O Word numera por INSTÂNCIA (`numId`): parágrafos comuns entre itens não\n * resetam a contagem. O editor numera por ADJACÊNCIA: o renderer agrupa\n * `listItem`s consecutivos do mesmo `listKind`/`listStyle`, e um `listStart`\n * em item de CONTINUAÇÃO quebra o grupo ali. O parse gravou o ordinal Word em\n * `listStart` de TODOS os itens ordenados; este pós-passe o mantém apenas nos\n * LÍDERES de grupo (primeiro item, item após bloco comum, ou após item de\n * kind/estilo diferente) — assim o editor renderiza exatamente os números do\n * Word (\"3.\" depois de uma linha de resposta, \"b.\" em subitens) sem fragmentar\n * os grupos.\n */\nexport function pruneNonLeaderListStarts(blocks: SerializedBlock[]): void {\n // Estado do grupo de adjacência corrente: estilo do líder e último ordinal\n // visto por nível (para exigir sequência contígua — duas listas Word\n // independentes coladas, \"1,2,3\" + \"1,2\", NÃO podem fundir num 1..5).\n let grupoAtivo = false;\n let grupoStyle: unknown;\n let ordinais: number[] = [];\n\n const resetGrupo = () => {\n grupoAtivo = false;\n grupoStyle = undefined;\n ordinais = [];\n };\n\n for (const block of blocks) {\n if (block.type !== \"listItem\") {\n resetGrupo();\n continue;\n }\n if ((block.attrs.listKind ?? \"bullet\") !== \"ordered\") {\n // Bullet entre ordenados: mantém o grupo do renderer? Não — kind\n // diferente quebra o grupo lá também.\n resetGrupo();\n continue;\n }\n const level = block.attrs.listLevel ?? 0;\n const ordinal = typeof block.attrs.listStart === \"number\" ? block.attrs.listStart : 1;\n\n const mesmoNivelSequencial = ordinais[level] != null && ordinal === ordinais[level] + 1;\n const entrandoEmNivelNovo = ordinais[level] == null && level > 0 && ordinal === 1;\n const continuaGrupo =\n grupoAtivo &&\n block.attrs.listStyle === grupoStyle &&\n (mesmoNivelSequencial || entrandoEmNivelNovo);\n\n if (continuaGrupo) {\n delete block.attrs.listStart;\n } else {\n // Este item lidera um grupo novo no renderer (listStart preservado).\n grupoAtivo = true;\n grupoStyle = block.attrs.listStyle;\n ordinais = [];\n }\n ordinais[level] = ordinal;\n ordinais.length = level + 1;\n }\n}\n\n/** Convenience: parse → instantiate a fresh `EditorDocument`. */\nexport async function docxBlobToEditorDocument(\n input: Blob | ArrayBuffer | Uint8Array,\n): Promise<EditorDocument> {\n const serialized = await docxBlobToDocument(input);\n return EditorDocument.fromJSON(serialized);\n}\n\nfunction findBody(documentXml: OoxmlNode[]): OoxmlNode | undefined {\n for (const top of documentXml) {\n if (tagOf(top) === \"w:document\") {\n const body = findChild(top, \"w:body\");\n if (body) return body;\n }\n }\n return undefined;\n}\n","import JSZip from \"jszip\";\nimport { XMLParser } from \"fast-xml-parser\";\n\n/**\n * fast-xml-parser with `preserveOrder: true` produces a list of single-key\n * objects per element. Each element is either:\n *\n * - A tag node: `{ \"<tagName>\": <children-array>, \":@\"?: <attrs> }`\n * - A text node: `{ \"#text\": <string> }`\n *\n * Attributes are prefixed with `@_`. The `:@` key holds attributes for the\n * surrounding tag. Children preserve original document order, which matters\n * for paragraph runs (bold word followed by italic word).\n */\nexport type OoxmlNode = Record<string, unknown>;\n\nconst parser = new XMLParser({\n ignoreAttributes: false,\n attributeNamePrefix: \"@_\",\n preserveOrder: true,\n trimValues: false, // keep whitespace inside <w:t>\n parseAttributeValue: false,\n parseTagValue: false,\n});\n\nexport interface DocxFile {\n documentXml: OoxmlNode[];\n numberingXml?: OoxmlNode[];\n /** rId → target path (inside the zip), e.g. \"media/image1.png\". */\n relationships: Map<string, string>;\n /** zip path (without leading \"word/\") → bytes for embedded media. */\n mediaBytes: Map<string, Uint8Array>;\n}\n\nexport async function readDocx(input: Blob | ArrayBuffer | Uint8Array): Promise<DocxFile> {\n const data =\n input instanceof Uint8Array\n ? input\n : input instanceof ArrayBuffer\n ? new Uint8Array(input)\n : new Uint8Array(await (input as Blob).arrayBuffer());\n\n const zip = await JSZip.loadAsync(data);\n const documentXml = await readXml(zip, \"word/document.xml\");\n if (!documentXml) throw new Error(\"Invalid .docx: missing word/document.xml\");\n\n const numberingXml = await readXml(zip, \"word/numbering.xml\");\n const relsXml = await readXml(zip, \"word/_rels/document.xml.rels\");\n const relationships = parseRelationships(relsXml);\n\n const mediaBytes = new Map<string, Uint8Array>();\n const mediaFolder = zip.folder(\"word/media\");\n if (mediaFolder) {\n const promises: Promise<void>[] = [];\n mediaFolder.forEach((relativePath, file) => {\n if (file.dir) return;\n promises.push(\n file.async(\"uint8array\").then((bytes) => {\n mediaBytes.set(`media/${relativePath}`, bytes);\n }),\n );\n });\n await Promise.all(promises);\n }\n\n return { documentXml, numberingXml, relationships, mediaBytes };\n}\n\nasync function readXml(zip: JSZip, path: string): Promise<OoxmlNode[] | undefined> {\n const entry = zip.file(path);\n if (!entry) return undefined;\n const text = await entry.async(\"string\");\n return parser.parse(text) as OoxmlNode[];\n}\n\nfunction parseRelationships(nodes: OoxmlNode[] | undefined): Map<string, string> {\n const out = new Map<string, string>();\n if (!nodes) return out;\n // <Relationships><Relationship Id=\"rId1\" Type=\"...\" Target=\"media/image1.png\"/>...\n for (const top of nodes) {\n const children = top[\"Relationships\"];\n if (!Array.isArray(children)) continue;\n for (const child of children as OoxmlNode[]) {\n if (!(\"Relationship\" in child)) continue;\n const attrs = (child[\":@\"] ?? {}) as Record<string, unknown>;\n const id = attrs[\"@_Id\"];\n const target = attrs[\"@_Target\"];\n if (typeof id === \"string\" && typeof target === \"string\") {\n out.set(id, target);\n }\n }\n }\n return out;\n}\n\n// ---------- generic walkers over preserveOrder shape ----------\n\n/** Returns the tag name (e.g. \"w:p\") of a preserveOrder element, or null for text. */\nexport function tagOf(node: OoxmlNode): string | null {\n for (const key of Object.keys(node)) {\n if (key === \":@\") continue;\n return key;\n }\n return null;\n}\n\n/** Returns the children array of an element, or [] when none. */\nexport function childrenOf(node: OoxmlNode): OoxmlNode[] {\n const tag = tagOf(node);\n if (!tag) return [];\n const v = node[tag];\n return Array.isArray(v) ? (v as OoxmlNode[]) : [];\n}\n\n/** Returns the attribute bag (already with `@_` prefix) for an element. */\nexport function attrsOf(node: OoxmlNode): Record<string, unknown> {\n return ((node[\":@\"] ?? {}) as Record<string, unknown>) ?? {};\n}\n\n/** Read a single `@_key` attribute as a string. */\nexport function attr(node: OoxmlNode, key: string): string | undefined {\n const v = attrsOf(node)[`@_${key}`];\n return typeof v === \"string\" ? v : undefined;\n}\n\n/** Find the first direct child with the given tag name. */\nexport function findChild(node: OoxmlNode, tag: string): OoxmlNode | undefined {\n for (const child of childrenOf(node)) {\n if (tagOf(child) === tag) return child;\n }\n return undefined;\n}\n\n/** Find all direct children with the given tag name. */\nexport function findChildren(node: OoxmlNode, tag: string): OoxmlNode[] {\n const out: OoxmlNode[] = [];\n for (const child of childrenOf(node)) {\n if (tagOf(child) === tag) out.push(child);\n }\n return out;\n}\n\n/** Recursively collect text nodes' concatenated content. */\nexport function textOf(node: OoxmlNode): string {\n let out = \"\";\n for (const child of childrenOf(node)) {\n if (\"#text\" in child) {\n const t = child[\"#text\"];\n if (typeof t === \"string\") out += t;\n } else {\n out += textOf(child);\n }\n }\n return out;\n}\n","/**\n * Unit conversions between OOXML and the editor's serialized format.\n * These are the inverses of the helpers in `@sofereditor/export-docx/src/docx.ts`.\n */\n\n/** docx half-points → CSS pt string. 24 (half-pt) → \"12pt\". */\nexport function halfPointsToCssPt(halfPoints: number): string | undefined {\n if (!Number.isFinite(halfPoints) || halfPoints <= 0) return undefined;\n const pt = halfPoints / 2;\n return `${stripTrailingZeros(pt)}pt`;\n}\n\n/** OOXML RRGGBB (no '#') → CSS hex with leading '#'. */\nexport function docxHexToCssColor(hex: string | undefined): string | undefined {\n if (!hex) return undefined;\n const m = /^[0-9a-f]{6}$/i.exec(hex.trim());\n if (!m) return undefined;\n return `#${hex.toLowerCase()}`;\n}\n\n/** OOXML alignment value → editor AlignValue. */\nexport function parseAlign(val: string | undefined): \"left\" | \"center\" | \"right\" | \"justify\" | undefined {\n if (!val) return undefined;\n switch (val.toLowerCase()) {\n case \"left\":\n case \"start\":\n return \"left\";\n case \"center\":\n return \"center\";\n case \"right\":\n case \"end\":\n return \"right\";\n case \"both\":\n case \"distribute\":\n case \"justify\":\n return \"justify\";\n default:\n return undefined;\n }\n}\n\n/** Parse XML attribute that should be a positive integer. */\nexport function parseIntAttr(val: unknown, fallback = 0): number {\n if (typeof val === \"number\" && Number.isFinite(val)) return Math.trunc(val);\n if (typeof val !== \"string\") return fallback;\n const n = Number.parseInt(val, 10);\n return Number.isFinite(n) ? n : fallback;\n}\n\nfunction stripTrailingZeros(n: number): string {\n // 12 → \"12\", 12.5 → \"12.5\"\n return Number.isInteger(n) ? n.toString() : n.toFixed(2).replace(/\\.?0+$/, \"\");\n}\n","import type { ImageEmbed } from \"@sofereditor/core\";\nimport { attr, childrenOf, tagOf, type OoxmlNode } from \"./parse-xml\";\nimport { parseIntAttr } from \"./units\";\n\n/** 1 inch = 914400 EMU = 96 px → 1 px = 9525 EMU. */\nconst EMU_PER_PX = 9525;\n\nconst MIME_BY_EXT: Record<string, string> = {\n png: \"image/png\",\n jpg: \"image/jpeg\",\n jpeg: \"image/jpeg\",\n gif: \"image/gif\",\n bmp: \"image/bmp\",\n svg: \"image/svg+xml\",\n};\n\nexport interface ImageContext {\n relationships: Map<string, string>;\n mediaBytes: Map<string, Uint8Array>;\n}\n\n/**\n * Walk a `<w:drawing>` node and return an `ImageEmbed` if it contains a\n * recognized inline picture. Returns null for unsupported drawings (shapes,\n * charts, etc.).\n */\nexport function extractImageFromDrawing(\n drawing: OoxmlNode,\n ctx: ImageContext,\n): ImageEmbed | null {\n // The interesting bits live deep inside: a:blip carries `r:embed`, and\n // wp:extent carries cx/cy. We do a generic walk because the wrapping nodes\n // differ between inline (`wp:inline`) and anchored (`wp:anchor`) drawings.\n let embedId: string | undefined;\n let cx: number | undefined;\n let cy: number | undefined;\n\n walk(drawing, (n) => {\n const tag = tagOf(n);\n if (!tag) return;\n if (tag === \"a:blip\") {\n const id = attr(n, \"r:embed\") ?? attr(n, \"r:link\");\n if (id) embedId = id;\n } else if (tag === \"wp:extent\") {\n cx = parseIntAttr(attr(n, \"cx\"));\n cy = parseIntAttr(attr(n, \"cy\"));\n }\n });\n\n if (!embedId) return null;\n const target = ctx.relationships.get(embedId);\n if (!target) return null;\n // Relationship targets are typically \"media/image1.png\"; the zip lookup uses\n // the same path (we stored bytes keyed under \"media/<file>\").\n const bytes = ctx.mediaBytes.get(target);\n if (!bytes) return null;\n\n const ext = extensionOf(target);\n const mime = MIME_BY_EXT[ext] ?? \"image/png\";\n const src = `data:${mime};base64,${bytesToBase64(bytes)}`;\n const widthPx = cx != null ? Math.max(1, Math.round(cx / EMU_PER_PX)) : 100;\n const heightPx = cy != null ? Math.max(1, Math.round(cy / EMU_PER_PX)) : 100;\n\n return { type: \"image\", src, width: widthPx, height: heightPx };\n}\n\nfunction walk(node: OoxmlNode, visit: (n: OoxmlNode) => void): void {\n visit(node);\n for (const child of childrenOf(node)) {\n if (\"#text\" in child) continue;\n walk(child, visit);\n }\n}\n\nfunction extensionOf(path: string): string {\n const m = /\\.([a-z0-9]+)$/i.exec(path);\n return m ? m[1].toLowerCase() : \"\";\n}\n\nfunction bytesToBase64(bytes: Uint8Array): string {\n // Browser path.\n if (typeof btoa === \"function\") {\n let bin = \"\";\n const CHUNK = 0x8000;\n for (let i = 0; i < bytes.length; i += CHUNK) {\n bin += String.fromCharCode.apply(null, Array.from(bytes.subarray(i, i + CHUNK)));\n }\n return btoa(bin);\n }\n // Node fallback.\n return Buffer.from(bytes).toString(\"base64\");\n}\n","import type { DeltaOp, MarkAttrs } from \"@sofereditor/core\";\nimport {\n attr,\n childrenOf,\n findChild,\n tagOf,\n type OoxmlNode,\n} from \"./parse-xml\";\nimport { docxHexToCssColor, halfPointsToCssPt } from \"./units\";\nimport { extractImageFromDrawing, type ImageContext } from \"./images\";\n\nexport interface RunContext extends ImageContext {}\n\n/**\n * Walk a paragraph's children (post `<w:pPr>`) and emit a `DeltaOp[]`. Combines\n * adjacent runs that share the same mark set into a single op for parity with\n * the export — Y.Text.applyDelta would merge them anyway, but pre-merging keeps\n * round-trip output stable.\n */\nexport function paragraphChildrenToDelta(children: OoxmlNode[], ctx: RunContext): DeltaOp[] {\n const ops: DeltaOp[] = [];\n for (const child of children) {\n const tag = tagOf(child);\n if (!tag) continue;\n if (tag === \"w:pPr\") continue;\n if (tag === \"w:r\") {\n collectRun(child, ctx, undefined, ops);\n } else if (tag === \"w:hyperlink\") {\n // hyperlinks carry an r:id that maps via relationships to the href.\n const rId = attr(child, \"r:id\");\n const href = rId ? ctx.relationships.get(rId) : undefined;\n const linkMark: MarkAttrs | undefined = href ? { link: { href } } : undefined;\n for (const sub of childrenOf(child)) {\n if (tagOf(sub) === \"w:r\") collectRun(sub, ctx, linkMark, ops);\n }\n }\n }\n return mergeAdjacent(ops);\n}\n\nfunction collectRun(\n run: OoxmlNode,\n ctx: RunContext,\n wrappingMarks: MarkAttrs | undefined,\n out: DeltaOp[],\n): void {\n const marks = mergeMarks(wrappingMarks, runMarks(findChild(run, \"w:rPr\")));\n for (const child of childrenOf(run)) {\n const tag = tagOf(child);\n if (!tag) continue;\n if (tag === \"w:t\") {\n const text = textContent(child);\n if (text.length > 0) push(out, text, marks);\n } else if (tag === \"w:tab\") {\n push(out, \"\\t\", marks);\n } else if (tag === \"w:br\") {\n // Treat w:br type=\"page\" as also a soft break for the model — we have no\n // explicit page-break node in the schema; pagination is computed live.\n push(out, \"\\n\", marks);\n } else if (tag === \"w:drawing\") {\n const embed = extractImageFromDrawing(child, ctx);\n if (embed) out.push({ insert: embed });\n }\n // Other run children (w:sym, w:fldChar, etc.) are silently dropped.\n }\n}\n\nfunction runMarks(rPr: OoxmlNode | undefined): MarkAttrs {\n const m: MarkAttrs = {};\n if (!rPr) return m;\n for (const child of childrenOf(rPr)) {\n const tag = tagOf(child);\n if (!tag) continue;\n switch (tag) {\n case \"w:b\":\n if (!isFalse(attr(child, \"w:val\"))) m.bold = true;\n break;\n case \"w:i\":\n if (!isFalse(attr(child, \"w:val\"))) m.italic = true;\n break;\n case \"w:u\": {\n const val = attr(child, \"w:val\");\n if (val && val.toLowerCase() !== \"none\") m.underline = true;\n break;\n }\n case \"w:strike\":\n if (!isFalse(attr(child, \"w:val\"))) m.strike = true;\n break;\n case \"w:color\": {\n const hex = attr(child, \"w:val\");\n const css = docxHexToCssColor(hex);\n if (css) m.color = css;\n break;\n }\n // w:rFonts intentionally ignored: school standard is Arial for all\n // exams. Any font declared in the .docx is dropped on import so the\n // imported doc inherits Arial from `.ed-root` / PDF base stylesheet.\n case \"w:sz\": {\n const halfPts = Number.parseFloat(attr(child, \"w:val\") ?? \"\");\n const css = halfPointsToCssPt(halfPts);\n if (css) m.fontSize = css;\n break;\n }\n }\n }\n return m;\n}\n\nfunction mergeMarks(a: MarkAttrs | undefined, b: MarkAttrs): MarkAttrs {\n if (!a) return b;\n return { ...a, ...b };\n}\n\nfunction textContent(node: OoxmlNode): string {\n let out = \"\";\n for (const child of childrenOf(node)) {\n if (\"#text\" in child) {\n const t = child[\"#text\"];\n if (typeof t === \"string\") out += t;\n }\n }\n return out;\n}\n\nfunction isFalse(val: string | undefined): boolean {\n if (val == null) return false;\n const v = val.toLowerCase();\n return v === \"0\" || v === \"false\" || v === \"none\";\n}\n\nfunction push(out: DeltaOp[], text: string, marks: MarkAttrs): void {\n const op: DeltaOp =\n Object.keys(marks).length === 0 ? { insert: text } : { insert: text, attributes: { ...marks } };\n out.push(op);\n}\n\nfunction mergeAdjacent(ops: DeltaOp[]): DeltaOp[] {\n const out: DeltaOp[] = [];\n for (const op of ops) {\n const prev = out[out.length - 1];\n if (\n prev &&\n typeof prev.insert === \"string\" &&\n typeof op.insert === \"string\" &&\n sameMarks(prev.attributes, op.attributes)\n ) {\n prev.insert = prev.insert + op.insert;\n continue;\n }\n out.push(op);\n }\n return out;\n}\n\nfunction sameMarks(a: MarkAttrs | undefined, b: MarkAttrs | undefined): boolean {\n const ak = a ? Object.keys(a).sort() : [];\n const bk = b ? Object.keys(b).sort() : [];\n if (ak.length !== bk.length) return false;\n for (let i = 0; i < ak.length; i++) {\n if (ak[i] !== bk[i]) return false;\n const av = (a as Record<string, unknown>)[ak[i]];\n const bv = (b as Record<string, unknown>)[bk[i]];\n if (typeof av === \"object\" && av !== null && typeof bv === \"object\" && bv !== null) {\n if (JSON.stringify(av) !== JSON.stringify(bv)) return false;\n } else if (av !== bv) {\n return false;\n }\n }\n return true;\n}\n","import type { AlignValue, BlockAttrs, BlockType, DeltaOp, SerializedBlock } from \"@sofereditor/core\";\nimport {\n attr,\n childrenOf,\n findChild,\n tagOf,\n type OoxmlNode,\n} from \"./parse-xml\";\nimport { paragraphChildrenToDelta, type RunContext } from \"./runs\";\nimport { NumberingResolver } from \"./numbering\";\nimport { parseAlign } from \"./units\";\n\n/**\n * Map a `<w:p>` element to a SerializedBlock. Decides between\n * `paragraph / heading / blockquote / codeBlock / listItem` based on the\n * paragraph style + `w:pPr` properties — mirrors the heuristics encoded in\n * `@sofereditor/export-docx/src/docx.ts`.\n */\nexport function paragraphToBlock(\n p: OoxmlNode,\n ctx: RunContext,\n numbering: NumberingResolver,\n): SerializedBlock {\n const pPr = findChild(p, \"w:pPr\");\n const numPr = pPr ? findChild(pPr, \"w:numPr\") : undefined;\n const styleId = pPr ? attr(findChild(pPr, \"w:pStyle\") ?? {}, \"w:val\") : undefined;\n\n const delta = paragraphChildrenToDelta(childrenOf(p), ctx);\n const text = collectText(delta);\n const align = parseAlign(pPr ? attr(findChild(pPr, \"w:jc\") ?? {}, \"w:val\") : undefined);\n const isRtl = pPr ? !!findChild(pPr, \"w:bidi\") : false;\n\n // List? — numPr is the strongest signal.\n if (numPr) {\n const resolved = numbering.resolve(numPr);\n const attrs: BlockAttrs = {\n listKind: resolved?.listKind ?? \"bullet\",\n listLevel: resolved?.listLevel ?? 0,\n };\n if (resolved?.listKind === \"ordered\") {\n // O ordinal Word vai TEMPORARIAMENTE em listStart de todos os itens; o\n // pós-passe em docx.ts remove dos não-líderes (um listStart em item de\n // continuação quebraria o grupo no renderer). listStyle fica em todos —\n // itens do mesmo estilo agrupam; estilo diferente (ex.: a/b/c entre\n // questões decimais) quebra o grupo exatamente como no Word.\n if (resolved.ordinal != null) attrs.listStart = resolved.ordinal;\n if (resolved.listStyle) attrs.listStyle = resolved.listStyle;\n }\n if (align) attrs.align = align;\n if (isRtl) attrs.dir = \"rtl\";\n return { type: \"listItem\", text, delta, attrs };\n }\n\n // Heading?\n const headingLevel = styleId ? headingFromStyleId(styleId) : null;\n if (headingLevel != null) {\n const attrs: BlockAttrs = { level: headingLevel };\n if (align) attrs.align = align;\n if (isRtl) attrs.dir = \"rtl\";\n return { type: \"heading\", text, delta, attrs };\n }\n\n // Blockquote (export uses left border + 480 twip indent).\n if (pPr && hasLeftBorder(pPr)) {\n const attrs: BlockAttrs = {};\n if (align) attrs.align = align;\n if (isRtl) attrs.dir = \"rtl\";\n return { type: \"blockquote\", text, delta, attrs };\n }\n\n // Code block (export uses Consolas + light-gray shading).\n if (pPr && hasCodeBlockShading(pPr)) {\n const attrs: BlockAttrs = {};\n if (align) attrs.align = align;\n if (isRtl) attrs.dir = \"rtl\";\n return { type: \"codeBlock\", text, delta, attrs };\n }\n\n const attrs: BlockAttrs = {};\n if (align) attrs.align = align;\n if (isRtl) attrs.dir = \"rtl\";\n return { type: \"paragraph\", text, delta, attrs };\n}\n\nfunction collectText(delta: DeltaOp[]): string {\n let out = \"\";\n for (const op of delta) {\n if (typeof op.insert === \"string\") out += op.insert;\n }\n return out;\n}\n\nfunction headingFromStyleId(id: string): 1 | 2 | 3 | 4 | 5 | 6 | null {\n const m = /^Heading\\s*([1-6])$/i.exec(id);\n if (!m) return null;\n const n = Number.parseInt(m[1], 10);\n return (n as 1 | 2 | 3 | 4 | 5 | 6) ?? null;\n}\n\nfunction hasLeftBorder(pPr: OoxmlNode): boolean {\n const pBdr = findChild(pPr, \"w:pBdr\");\n if (!pBdr) return false;\n return !!findChild(pBdr, \"w:left\");\n}\n\nfunction hasCodeBlockShading(pPr: OoxmlNode): boolean {\n const shd = findChild(pPr, \"w:shd\");\n if (!shd) return false;\n const fill = attr(shd, \"w:fill\");\n if (!fill) return false;\n return fill.toLowerCase() === \"f1f5f9\";\n}\n\n/** Whitelist the block types this module produces (used by callers for typing). */\nexport type ParagraphBlockType = Exclude<BlockType, \"table\">;\n/** Whitelist the align values this module produces (used by callers for typing). */\nexport type ParagraphAlign = AlignValue;\n","import type { BlockAttrs, CellAttrs, DeltaOp, SerializedBlock, SerializedCell } from \"@sofereditor/core\";\nimport {\n attr,\n childrenOf,\n findChild,\n findChildren,\n tagOf,\n type OoxmlNode,\n} from \"./parse-xml\";\nimport { paragraphChildrenToDelta, type RunContext } from \"./runs\";\nimport { parseIntAttr } from \"./units\";\n\n/**\n * Map a `<w:tbl>` element to a SerializedBlock(table). The output `cells` array\n * is row-major with `rows * cols` entries — covered slots are filled with\n * `{attrs: {covered: true}}` placeholders so it matches the invariant required\n * by `@sofereditor/core`'s `EditorDocument`.\n */\nexport function tableToBlock(tbl: OoxmlNode, ctx: RunContext): SerializedBlock {\n const tblGrid = findChild(tbl, \"w:tblGrid\");\n const gridCols = tblGrid ? findChildren(tblGrid, \"w:gridCol\") : [];\n const trs = findChildren(tbl, \"w:tr\");\n\n // The docx writer (and Word itself) may emit fewer `<w:gridCol>` entries than\n // the table's logical column count when a row has merged cells. Take the max\n // of (declared gridCols, widest row's total gridSpan) to stay robust.\n let cols = gridCols.length;\n for (const tr of trs) {\n const tcs = findChildren(tr, \"w:tc\");\n let count = 0;\n for (const tc of tcs) count += gridSpanOf(tc);\n if (count > cols) cols = count;\n }\n if (cols < 1) cols = 1;\n const rows = trs.length;\n\n // Build a row-major grid of slots. Each slot is either a real cell or marked\n // as covered. We track which (row, col) is the anchor for vMerge groups.\n const slots: Array<SerializedCell | null> = new Array(rows * cols).fill(null);\n // Anchor of the active vMerge per column index; resets when a non-merge cell\n // is placed in the same column.\n const vMergeAnchorByCol = new Map<number, { row: number; col: number }>();\n\n for (let r = 0; r < rows; r++) {\n const tr = trs[r];\n let cursor = 0;\n for (const tc of findChildren(tr, \"w:tc\")) {\n // Advance the cursor past already-occupied (covered-from-above) slots.\n while (cursor < cols && slots[r * cols + cursor] !== null) cursor++;\n if (cursor >= cols) break;\n\n const tcPr = findChild(tc, \"w:tcPr\");\n const gridSpan = gridSpanOf(tc);\n const vMergeNode = tcPr ? findChild(tcPr, \"w:vMerge\") : undefined;\n const vMergeVal = vMergeNode ? (attr(vMergeNode, \"w:val\") ?? \"continue\") : null;\n\n if (vMergeNode && vMergeVal !== \"restart\") {\n // Continuation of a vertical merge. Cover this row, and bump the anchor's\n // rowspan if we can find it.\n const anchor = vMergeAnchorByCol.get(cursor);\n if (anchor) {\n const anchorIdx = anchor.row * cols + anchor.col;\n const a = slots[anchorIdx];\n if (a) {\n a.attrs = { ...(a.attrs ?? {}), rowspan: (a.attrs?.rowspan ?? 1) + 1 };\n }\n }\n for (let c = 0; c < gridSpan && cursor + c < cols; c++) {\n slots[r * cols + cursor + c] = coveredCell();\n }\n cursor += gridSpan;\n continue;\n }\n\n // Real cell: build its delta + attrs.\n const delta = cellChildrenToDelta(tc, ctx);\n const text = textOfDelta(delta);\n const cellAttrs: CellAttrs = {};\n if (gridSpan > 1) cellAttrs.colspan = gridSpan;\n // rowspan starts at 1 — vMerge continuations bump it.\n\n const realCell: SerializedCell = { text, delta, attrs: cellAttrs };\n slots[r * cols + cursor] = realCell;\n\n // Mark horizontally-covered slots from gridSpan.\n for (let c = 1; c < gridSpan && cursor + c < cols; c++) {\n slots[r * cols + cursor + c] = coveredCell();\n }\n\n if (vMergeVal === \"restart\") {\n vMergeAnchorByCol.set(cursor, { row: r, col: cursor });\n } else {\n vMergeAnchorByCol.delete(cursor);\n }\n cursor += gridSpan;\n }\n\n // Fill any trailing un-touched slots in this row with empty placeholders so\n // the row-major invariant holds (length = rows * cols).\n for (let c = 0; c < cols; c++) {\n if (slots[r * cols + c] === null) {\n slots[r * cols + c] = emptyCell();\n }\n }\n }\n\n const cells: SerializedCell[] = slots.map((s) => s ?? emptyCell());\n\n const attrs: BlockAttrs = { rows, cols };\n return { type: \"table\", text: \"\", delta: [], attrs, cells };\n}\n\nfunction gridSpanOf(tc: OoxmlNode): number {\n const tcPr = findChild(tc, \"w:tcPr\");\n if (!tcPr) return 1;\n const gs = findChild(tcPr, \"w:gridSpan\");\n if (!gs) return 1;\n const n = parseIntAttr(attr(gs, \"w:val\"), 1);\n return Math.max(1, n);\n}\n\nfunction cellChildrenToDelta(tc: OoxmlNode, ctx: RunContext): DeltaOp[] {\n // A cell can contain multiple paragraphs; we concat their deltas with a\n // newline between adjacent ones to preserve visual separation. The cell\n // model in @sofereditor/core is a single Y.Text, so we flatten.\n const out: DeltaOp[] = [];\n let first = true;\n for (const child of childrenOf(tc)) {\n if (tagOf(child) !== \"w:p\") continue;\n if (!first) out.push({ insert: \"\\n\" });\n first = false;\n out.push(...paragraphChildrenToDelta(childrenOf(child), ctx));\n }\n return out;\n}\n\nfunction textOfDelta(delta: DeltaOp[]): string {\n let out = \"\";\n for (const op of delta) {\n if (typeof op.insert === \"string\") out += op.insert;\n }\n return out;\n}\n\nfunction coveredCell(): SerializedCell {\n return { text: \"\", delta: [], attrs: { covered: true } };\n}\n\nfunction emptyCell(): SerializedCell {\n return { text: \"\", delta: [], attrs: {} };\n}\n","import type { ListKind, ListStyleType } from \"@sofereditor/core\";\nimport {\n attr,\n childrenOf,\n findChild,\n findChildren,\n tagOf,\n type OoxmlNode,\n} from \"./parse-xml\";\nimport { parseIntAttr } from \"./units\";\n\n/**\n * Resolves per-paragraph `<w:numPr>` into the editor's `{listKind, listLevel}`.\n *\n * docx numbering is two-step:\n * 1. paragraphs reference a `numId` and an `ilvl`\n * 2. each `<w:num numId=\"...\">` points to a `<w:abstractNum>` via `<w:abstractNumId>`\n * 3. each `<w:lvl ilvl=\"...\">` declares a `<w:numFmt val=\"bullet|decimal|...\">`\n *\n * The export side uses two hardcoded reference names (\"ed-bullet\" / \"ed-ordered\"),\n * but Word-authored documents use arbitrary `numId`s — we resolve by reading the\n * `numFmt` of the target level.\n */\n/** `w:numFmt` → CSS `list-style-type` do editor. Não listados caem em \"decimal\". */\nconst FMT_TO_LIST_STYLE: Record<string, ListStyleType> = {\n decimal: \"decimal\",\n lowerLetter: \"lower-alpha\",\n upperLetter: \"upper-alpha\",\n lowerRoman: \"lower-roman\",\n upperRoman: \"upper-roman\",\n};\n\nexport interface ResolvedNumbering {\n listKind: ListKind;\n listLevel: number;\n /**\n * Número Word desta entrada (contador por instância `numId`+nível, honrando\n * `w:start` e resetando níveis mais profundos). Só para `ordered`. O Word\n * numera por INSTÂNCIA — parágrafos comuns entre itens não resetam a\n * contagem — enquanto o editor numera por adjacência; o importador usa este\n * ordinal para semear `listStart` nos líderes de grupo (ver docx.ts).\n */\n ordinal?: number;\n /** Estilo do nível (`w:numFmt` mapeado). Só para `ordered`. */\n listStyle?: ListStyleType;\n}\n\nexport class NumberingResolver {\n private numIdToAbstract = new Map<string, string>();\n private abstractLevelFmt = new Map<string, Map<number, string>>();\n private abstractLevelStart = new Map<string, Map<number, number>>();\n /** Contadores vivos por instância de lista (numId), indexados por nível. */\n private counters = new Map<string, number[]>();\n\n constructor(numberingXml: OoxmlNode[] | undefined) {\n if (!numberingXml) return;\n for (const top of numberingXml) {\n if (tagOf(top) !== \"w:numbering\") continue;\n for (const child of childrenOf(top)) {\n const tag = tagOf(child);\n if (tag === \"w:abstractNum\") {\n const abstractId = attr(child, \"w:abstractNumId\");\n if (!abstractId) continue;\n const levels = new Map<number, string>();\n const starts = new Map<number, number>();\n for (const lvl of findChildren(child, \"w:lvl\")) {\n const ilvl = parseIntAttr(attr(lvl, \"w:ilvl\"), 0);\n const fmt = attr(findChild(lvl, \"w:numFmt\") ?? {}, \"w:val\");\n if (fmt) levels.set(ilvl, fmt);\n const start = findChild(lvl, \"w:start\");\n if (start) starts.set(ilvl, parseIntAttr(attr(start, \"w:val\"), 1));\n }\n this.abstractLevelFmt.set(abstractId, levels);\n this.abstractLevelStart.set(abstractId, starts);\n } else if (tag === \"w:num\") {\n const numId = attr(child, \"w:numId\");\n const abstractRef = findChild(child, \"w:abstractNumId\");\n const abstractId = abstractRef ? attr(abstractRef, \"w:val\") : undefined;\n if (numId && abstractId) this.numIdToAbstract.set(numId, abstractId);\n }\n }\n }\n }\n\n /**\n * Resolves a paragraph's `<w:numPr>` into `{listKind, listLevel, ordinal?,\n * listStyle?}`, or null. STATEFUL for ordered lists: each call advances the\n * per-`numId` counter (Word instance semantics) — call exactly once per\n * numbered paragraph, in document order.\n */\n resolve(numPr: OoxmlNode | undefined): ResolvedNumbering | null {\n if (!numPr) return null;\n const ilvlRef = findChild(numPr, \"w:ilvl\");\n const numIdRef = findChild(numPr, \"w:numId\");\n if (!numIdRef) return null;\n const numId = attr(numIdRef, \"w:val\");\n if (!numId) return null;\n const listLevel = clampLevel(parseIntAttr(ilvlRef ? attr(ilvlRef, \"w:val\") : undefined, 0));\n const abstractId = this.numIdToAbstract.get(numId);\n if (abstractId == null) {\n // Numbering refs the export side defines without a numbering.xml entry visible\n // to us (the export-docx pipeline generates them dynamically via the docx lib).\n // Fall back by inspecting the numId itself when it is a known sentinel.\n return { listKind: \"bullet\", listLevel };\n }\n const levels = this.abstractLevelFmt.get(abstractId);\n const fmt = levels?.get(listLevel) ?? \"bullet\";\n const fmtLower = fmt.toLowerCase();\n const listKind: ListKind = fmtLower === \"bullet\" || fmtLower === \"none\" ? \"bullet\" : \"ordered\";\n if (listKind === \"bullet\") return { listKind, listLevel };\n\n // Ordinal Word: contador por numId; nível avança, níveis mais profundos resetam.\n const start = this.abstractLevelStart.get(abstractId)?.get(listLevel) ?? 1;\n const c = this.counters.get(numId) ?? [];\n c[listLevel] = c[listLevel] == null ? start : c[listLevel] + 1;\n c.length = listLevel + 1;\n this.counters.set(numId, c);\n\n return {\n listKind,\n listLevel,\n ordinal: c[listLevel],\n listStyle: FMT_TO_LIST_STYLE[fmt] ?? \"decimal\",\n };\n }\n}\n\nfunction clampLevel(n: number): number {\n if (!Number.isFinite(n)) return 0;\n return Math.max(0, Math.min(5, Math.trunc(n)));\n}\n","import { detectPreset, mmToPx, type PageSettings } from \"@sofereditor/core\";\nimport { attr, findChild, type OoxmlNode } from \"./parse-xml\";\nimport { parseIntAttr } from \"./units\";\n\n/**\n * 1 inch = 1440 twips = 25.4 mm. So 1 twip = 25.4/1440 mm.\n *\n * Page size lives in `<w:sectPr><w:pgSz w:w=\"...\" w:h=\"...\"/></w:sectPr>` and\n * margins in `<w:pgMar w:top=\"...\" w:bottom=\"...\" w:left=\"...\" w:right=\"...\"/>`,\n * all in twips. This is the inverse of `sectionPropertiesFor` in\n * `@sofereditor/export-docx`.\n */\nconst MM_PER_TWIP = 25.4 / 1440;\n\nfunction twipsToPx(twips: number): number {\n return mmToPx(twips * MM_PER_TWIP);\n}\n\nexport function sectPrToPageSettings(\n sectPr: OoxmlNode | undefined,\n): PageSettings | undefined {\n if (!sectPr) return undefined;\n const pgSz = findChild(sectPr, \"w:pgSz\");\n const pgMar = findChild(sectPr, \"w:pgMar\");\n if (!pgSz && !pgMar) return undefined;\n\n const widthTwips = pgSz ? parseIntAttr(attr(pgSz, \"w:w\"), 0) : 0;\n const heightTwips = pgSz ? parseIntAttr(attr(pgSz, \"w:h\"), 0) : 0;\n const topTwips = pgMar ? parseIntAttr(attr(pgMar, \"w:top\"), 0) : 0;\n const bottomTwips = pgMar ? parseIntAttr(attr(pgMar, \"w:bottom\"), 0) : 0;\n const leftTwips = pgMar ? parseIntAttr(attr(pgMar, \"w:left\"), 0) : 0;\n const rightTwips = pgMar ? parseIntAttr(attr(pgMar, \"w:right\"), 0) : 0;\n\n if (widthTwips <= 0 && heightTwips <= 0 && topTwips <= 0 && leftTwips <= 0) {\n return undefined;\n }\n\n const width = widthTwips > 0 ? twipsToPx(widthTwips) : 794;\n const height = heightTwips > 0 ? twipsToPx(heightTwips) : 1123;\n const settings: PageSettings = {\n width,\n height,\n marginTop: twipsToPx(topTwips || 0),\n marginBottom: twipsToPx(bottomTwips || 0),\n marginLeft: twipsToPx(leftTwips || 0),\n marginRight: twipsToPx(rightTwips || 0),\n };\n settings.preset = detectPreset(settings.width, settings.height);\n return settings;\n}\n"],"mappings":"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","names":["attrs"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sofereditor/import-docx",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "@sofereditor/import-docx — Parse .docx (OOXML) in browser or Node into a SerializedDocument loadable by the Sofer editor.",
|
|
5
5
|
"license": "AGPL-3.0-or-later",
|
|
6
6
|
"author": "Rafael Marreca",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"jszip": "^3.10.1"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"@sofereditor/export-docx": "^0.3.
|
|
62
|
+
"@sofereditor/export-docx": "^0.3.4",
|
|
63
63
|
"tsup": "^8.3.5",
|
|
64
64
|
"typescript": "^5.7.2",
|
|
65
65
|
"vitest": "^2.1.8"
|