@sofereditor/import-docx 0.6.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +68 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +70 -5
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -36,7 +36,7 @@ __export(index_exports, {
|
|
|
36
36
|
module.exports = __toCommonJS(index_exports);
|
|
37
37
|
|
|
38
38
|
// src/docx.ts
|
|
39
|
-
var
|
|
39
|
+
var import_core3 = require("@sofereditor/core");
|
|
40
40
|
|
|
41
41
|
// src/parse-xml.ts
|
|
42
42
|
var import_jszip = __toESM(require("jszip"), 1);
|
|
@@ -161,6 +161,9 @@ function borderSideOn(parent, ...names) {
|
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
// src/units.ts
|
|
164
|
+
function twipToMillimeters(twip) {
|
|
165
|
+
return twip * 25.4 / 1440;
|
|
166
|
+
}
|
|
164
167
|
function halfPointsToCssPt(halfPoints) {
|
|
165
168
|
if (!Number.isFinite(halfPoints) || halfPoints <= 0) return void 0;
|
|
166
169
|
const pt = halfPoints / 2;
|
|
@@ -520,7 +523,8 @@ function hasCodeBlockShading(pPr) {
|
|
|
520
523
|
}
|
|
521
524
|
|
|
522
525
|
// src/tables.ts
|
|
523
|
-
|
|
526
|
+
var import_core = require("@sofereditor/core");
|
|
527
|
+
function tableToBlock(tbl, ctx, larguraUtilTwips) {
|
|
524
528
|
const tblGrid = findChild(tbl, "w:tblGrid");
|
|
525
529
|
const gridCols = tblGrid ? findChildren(tblGrid, "w:gridCol") : [];
|
|
526
530
|
const trs = findChildren(tbl, "w:tr");
|
|
@@ -588,8 +592,50 @@ function tableToBlock(tbl, ctx) {
|
|
|
588
592
|
if (preset) attrs.borderPreset = preset;
|
|
589
593
|
const borderColor = readBorderColor(tbl);
|
|
590
594
|
if (borderColor) attrs.borderColor = borderColor;
|
|
595
|
+
const twips = gridCols.map((g) => Number(attr(g, "w:w") ?? 0));
|
|
596
|
+
attrs.colWidths = (0, import_core.normalizarLarguras)(twips, cols);
|
|
597
|
+
const rowHeights = readRowHeights(trs);
|
|
598
|
+
if (rowHeights) attrs.rowHeights = rowHeights;
|
|
599
|
+
const tableWidth = readTableWidth(tbl, larguraUtilTwips);
|
|
600
|
+
if (tableWidth !== void 0) attrs.tableWidth = tableWidth;
|
|
591
601
|
return { type: "table", text: "", delta: [], attrs, cells };
|
|
592
602
|
}
|
|
603
|
+
function leMedida(bruto) {
|
|
604
|
+
if (bruto === void 0) return void 0;
|
|
605
|
+
const t = bruto.trim();
|
|
606
|
+
const comSufixo = t.endsWith("%");
|
|
607
|
+
const n = Number(comSufixo ? t.slice(0, -1) : t);
|
|
608
|
+
if (!Number.isFinite(n) || n <= 0) return void 0;
|
|
609
|
+
return { valor: n, ehPercentSufixo: comSufixo };
|
|
610
|
+
}
|
|
611
|
+
function readTableWidth(tbl, larguraUtilTwips) {
|
|
612
|
+
const tblPr = findChild(tbl, "w:tblPr");
|
|
613
|
+
const tblW = tblPr ? findChild(tblPr, "w:tblW") : void 0;
|
|
614
|
+
if (!tblW) return void 0;
|
|
615
|
+
const medida = leMedida(attr(tblW, "w:w"));
|
|
616
|
+
if (!medida) return void 0;
|
|
617
|
+
const type = attr(tblW, "w:type");
|
|
618
|
+
if (medida.ehPercentSufixo) return (0, import_core.travaLarguraTabela)(arredondaPct(medida.valor));
|
|
619
|
+
if (type === "pct") return (0, import_core.travaLarguraTabela)(arredondaPct(medida.valor / 50));
|
|
620
|
+
if (type === "dxa" || type === void 0) {
|
|
621
|
+
if (larguraUtilTwips === void 0 || larguraUtilTwips <= 0) return void 0;
|
|
622
|
+
return (0, import_core.travaLarguraTabela)(arredondaPct(medida.valor / larguraUtilTwips * 100));
|
|
623
|
+
}
|
|
624
|
+
return void 0;
|
|
625
|
+
}
|
|
626
|
+
function arredondaPct(pct) {
|
|
627
|
+
return Math.round(pct * 100) / 100;
|
|
628
|
+
}
|
|
629
|
+
function readRowHeights(trs) {
|
|
630
|
+
const heights = trs.map((tr) => {
|
|
631
|
+
const trPr = findChild(tr, "w:trPr");
|
|
632
|
+
const trHeight = trPr ? findChild(trPr, "w:trHeight") : void 0;
|
|
633
|
+
const val = trHeight ? Number(attr(trHeight, "w:val") ?? "") : NaN;
|
|
634
|
+
return Number.isFinite(val) && val > 0 ? (0, import_core.mmToPx)(twipToMillimeters(val)) : void 0;
|
|
635
|
+
});
|
|
636
|
+
if (heights.every((h) => h === void 0)) return void 0;
|
|
637
|
+
return heights.map((h) => h ?? import_core.MIN_LINHA_PX);
|
|
638
|
+
}
|
|
593
639
|
function readBorderColor(tbl) {
|
|
594
640
|
const tblPr = findChild(tbl, "w:tblPr");
|
|
595
641
|
const b = tblPr ? findChild(tblPr, "w:tblBorders") : void 0;
|
|
@@ -752,10 +798,10 @@ function clampLevel(n) {
|
|
|
752
798
|
}
|
|
753
799
|
|
|
754
800
|
// src/page-settings.ts
|
|
755
|
-
var
|
|
801
|
+
var import_core2 = require("@sofereditor/core");
|
|
756
802
|
var MM_PER_TWIP = 25.4 / 1440;
|
|
757
803
|
function twipsToPx(twips) {
|
|
758
|
-
return (0,
|
|
804
|
+
return (0, import_core2.mmToPx)(twips * MM_PER_TWIP);
|
|
759
805
|
}
|
|
760
806
|
function sectPrToPageSettings(sectPr) {
|
|
761
807
|
if (!sectPr) return void 0;
|
|
@@ -781,9 +827,21 @@ function sectPrToPageSettings(sectPr) {
|
|
|
781
827
|
marginLeft: twipsToPx(leftTwips || 0),
|
|
782
828
|
marginRight: twipsToPx(rightTwips || 0)
|
|
783
829
|
};
|
|
784
|
-
settings.preset = (0,
|
|
830
|
+
settings.preset = (0, import_core2.detectPreset)(settings.width, settings.height);
|
|
785
831
|
return settings;
|
|
786
832
|
}
|
|
833
|
+
function larguraUtilTwipsDe(sectPr) {
|
|
834
|
+
if (!sectPr) return void 0;
|
|
835
|
+
const pgSz = findChild(sectPr, "w:pgSz");
|
|
836
|
+
if (!pgSz) return void 0;
|
|
837
|
+
const width = parseIntAttr(attr(pgSz, "w:w"), 0);
|
|
838
|
+
if (width <= 0) return void 0;
|
|
839
|
+
const pgMar = findChild(sectPr, "w:pgMar");
|
|
840
|
+
const left = pgMar ? parseIntAttr(attr(pgMar, "w:left"), 0) : 0;
|
|
841
|
+
const right = pgMar ? parseIntAttr(attr(pgMar, "w:right"), 0) : 0;
|
|
842
|
+
const util = width - left - right;
|
|
843
|
+
return util > 0 ? util : void 0;
|
|
844
|
+
}
|
|
787
845
|
|
|
788
846
|
// src/docx.ts
|
|
789
847
|
async function docxBlobToDocument(input) {
|
|
@@ -795,20 +853,22 @@ async function docxBlobToDocument(input) {
|
|
|
795
853
|
};
|
|
796
854
|
const body = findBody(file.documentXml);
|
|
797
855
|
if (!body) return { blocks: [{ type: "paragraph", text: "", delta: [], attrs: {} }] };
|
|
856
|
+
const sectPr = findChild(body, "w:sectPr");
|
|
857
|
+
const pageSettings = sectPrToPageSettings(sectPr);
|
|
858
|
+
const larguraUtilTwips = larguraUtilTwipsDe(sectPr);
|
|
798
859
|
const blocks = [];
|
|
799
860
|
for (const child of childrenOf(body)) {
|
|
800
861
|
const tag = tagOf(child);
|
|
801
862
|
if (tag === "w:p") {
|
|
802
863
|
blocks.push(paragraphToBlock(child, ctx, numbering));
|
|
803
864
|
} else if (tag === "w:tbl") {
|
|
804
|
-
blocks.push(tableToBlock(child, ctx));
|
|
865
|
+
blocks.push(tableToBlock(child, ctx, larguraUtilTwips));
|
|
805
866
|
}
|
|
806
867
|
}
|
|
807
868
|
if (blocks.length === 0) {
|
|
808
869
|
blocks.push({ type: "paragraph", text: "", delta: [], attrs: {} });
|
|
809
870
|
}
|
|
810
871
|
pruneNonLeaderListStarts(blocks);
|
|
811
|
-
const pageSettings = sectPrToPageSettings(findChild(body, "w:sectPr"));
|
|
812
872
|
return pageSettings ? { blocks, pageSettings } : { blocks };
|
|
813
873
|
}
|
|
814
874
|
function pruneNonLeaderListStarts(blocks) {
|
|
@@ -847,7 +907,7 @@ function pruneNonLeaderListStarts(blocks) {
|
|
|
847
907
|
}
|
|
848
908
|
async function docxBlobToEditorDocument(input) {
|
|
849
909
|
const serialized = await docxBlobToDocument(input);
|
|
850
|
-
return
|
|
910
|
+
return import_core3.EditorDocument.fromJSON(serialized);
|
|
851
911
|
}
|
|
852
912
|
function findBody(documentXml) {
|
|
853
913
|
for (const top of documentXml) {
|
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 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/**\n * Returns the children array of an element, or [] when none.\n *\n * Content controls (`w:sdt`) são desembrulhados aqui, no lugar. No OOXML eles\n * são wrappers TRANSPARENTES: o conteúdo real vive em `w:sdtContent` e o\n * `w:sdtPr` carrega só metadados (alias, trava). O Word emite `w:sdt` ao\n * BLOQUEAR um trecho, e ele pode aparecer em qualquer nível — envolvendo uma\n * tabela no body, uma `w:tc` dentro de `w:tr`, um `w:p` dentro de `w:tc`, ou um\n * `w:r` dentro de `w:p`.\n *\n * Desembrulhar aqui, e não em cada chamador, é o que garante que todos esses\n * níveis funcionem: `findChild` e `findChildren` também passam por aqui. Antes\n * disso, cada lista branca de tag ignorava o `w:sdt` e o conteúdo travado sumia\n * silenciosamente.\n */\nexport function childrenOf(node: OoxmlNode): OoxmlNode[] {\n const tag = tagOf(node);\n if (!tag) return [];\n const v = node[tag];\n if (!Array.isArray(v)) return [];\n const kids = v as OoxmlNode[];\n // Caminho rápido: sem content control, devolve o array original sem alocar.\n // `childrenOf` é chamada em todo nó do documento.\n let temSdt = false;\n for (const k of kids) {\n if (tagOf(k) === \"w:sdt\") {\n temSdt = true;\n break;\n }\n }\n if (!temSdt) return kids;\n\n const out: OoxmlNode[] = [];\n for (const k of kids) {\n if (tagOf(k) !== \"w:sdt\") {\n out.push(k);\n continue;\n }\n // Só `w:sdtContent` é conteúdo; `w:sdtPr`/`w:sdtEndPr` são metadados.\n // A recursão trata content controls aninhados.\n const content = childrenOf(k).find((c) => tagOf(c) === \"w:sdtContent\");\n if (content) out.push(...childrenOf(content));\n }\n return out;\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/**\n * Um lado de borda (`w:top`, `w:left`, `w:insideH`, …) está LIGADO?\n *\n * A mera presença do elemento não basta: o Word grava blocos de borda\n * COMPLETOS com todos os lados `w:val=\"none\"` — uma declaração no-op. Ler só a\n * presença fazia parágrafos comuns virarem blockquote (cinza e itálico) só\n * porque traziam um `w:pBdr` vazio de significado.\n *\n * Aceita nomes alternativos porque o OOXML estrito usa `w:start`/`w:end` no\n * lugar de `w:left`/`w:right`.\n */\nexport function borderSideOn(parent: OoxmlNode | undefined, ...names: string[]): boolean {\n if (!parent) return false;\n return names.some((name) => {\n const n = findChild(parent, name);\n if (!n) return false;\n const val = (attr(n, \"w:val\") ?? \"\").toLowerCase();\n return val !== \"\" && val !== \"none\" && val !== \"nil\";\n });\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\n/**\n * Os valores nomeados de `w:highlight` do OOXML. O Word só aceita esta lista\n * fechada — documentos com cor arbitrária usam `w:shd`, que é o que o nosso\n * export emite. `none` fica de fora de propósito: ausência = sem marca.\n */\nconst DOCX_HIGHLIGHT_COLORS: Record<string, string> = {\n yellow: \"#ffff00\",\n green: \"#00ff00\",\n cyan: \"#00ffff\",\n magenta: \"#ff00ff\",\n blue: \"#0000ff\",\n red: \"#ff0000\",\n darkblue: \"#000080\",\n darkcyan: \"#008080\",\n darkgreen: \"#008000\",\n darkmagenta: \"#800080\",\n darkred: \"#800000\",\n darkyellow: \"#808000\",\n darkgray: \"#808080\",\n lightgray: \"#c0c0c0\",\n black: \"#000000\",\n white: \"#ffffff\",\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 case \"w:shd\": {\n // Sombreamento de RUN = marca-texto. `auto` significa \"sem cor\".\n const fill = attr(child, \"w:fill\");\n if (fill && fill.toLowerCase() !== \"auto\") {\n const css = docxHexToCssColor(fill);\n if (css) m.highlight = css;\n }\n break;\n }\n case \"w:highlight\": {\n const css = DOCX_HIGHLIGHT_COLORS[(attr(child, \"w:val\") ?? \"\").toLowerCase()];\n if (css) m.highlight = 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 {\n AlignValue,\n AnswerLineSpacing,\n BlockAttrs,\n BlockType,\n DeltaOp,\n SerializedBlock,\n} from \"@sofereditor/core\";\nimport {\n attr,\n borderSideOn,\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 Object.assign(attrs, readAnswerLine(pPr, text.length > 0));\n return { type: \"paragraph\", text, delta, attrs };\n}\n\n/**\n * Parágrafo SEM texto e com borda INFERIOR = linha de resposta.\n *\n * A exigência de estar vazio é essencial: um parágrafo com texto e régua é um\n * título sublinhado, e convertê-lo em linha de resposta destruiria a semântica\n * do conteúdo. A borda ESQUERDA já é tratada antes como blockquote.\n */\nfunction readAnswerLine(pPr: OoxmlNode | undefined, hasText: boolean): Partial<BlockAttrs> {\n if (!pPr || hasText) return {};\n const pBdr = findChild(pPr, \"w:pBdr\");\n if (!pBdr) return {};\n if (!borderSideOn(pBdr, \"w:bottom\")) return {};\n return { answerLine: true, answerLineSpacing: readAnswerLineSpacing(pPr) };\n}\n\n/** 240 twips = 1 linha. Arredonda para o bucket suportado mais próximo. */\nfunction readAnswerLineSpacing(pPr: OoxmlNode): AnswerLineSpacing {\n const sp = findChild(pPr, \"w:spacing\");\n const line = sp ? Number.parseFloat(attr(sp, \"w:line\") ?? \"\") : NaN;\n if (!Number.isFinite(line)) return 1;\n const buckets: AnswerLineSpacing[] = [1, 1.5, 2];\n let best: AnswerLineSpacing = 1;\n let bestDist = Infinity;\n for (const b of buckets) {\n const d = Math.abs(line - 240 * b);\n if (d < bestDist) {\n bestDist = d;\n best = b;\n }\n }\n return best;\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 // `borderSideOn` (e não a mera presença do elemento): o Word grava pBdr\n // completo com todos os lados \"none\", e ler a presença convertia parágrafo\n // comum em blockquote.\n return borderSideOn(pBdr, \"w:left\", \"w:start\");\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 {\n BlockAttrs,\n CellAttrs,\n DeltaOp,\n SerializedBlock,\n SerializedCell,\n TableBorderPreset,\n} from \"@sofereditor/core\";\nimport {\n attr,\n borderSideOn,\n childrenOf,\n findChild,\n findChildren,\n tagOf,\n type OoxmlNode,\n} from \"./parse-xml\";\nimport { paragraphChildrenToDelta, type RunContext } from \"./runs\";\nimport { docxHexToCssColor, 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 const preset = readBorderPreset(tbl);\n if (preset) attrs.borderPreset = preset;\n const borderColor = readBorderColor(tbl);\n if (borderColor) attrs.borderColor = borderColor;\n return { type: \"table\", text: \"\", delta: [], attrs, cells };\n}\n\n/**\n * Reduz `w:tblBorders` ao preset mais próximo.\n *\n * O modelo não tem borda por célula, então `w:tcBorders` continua ignorado —\n * deliberadamente. Combinação não mapeável cai em `all`, que é o padrão visual\n * e o comportamento menos surpreendente para quem importa um documento externo.\n *\n * Retorna `undefined` quando a tabela não declara `tblBorders`, para não gravar\n * a chave à toa.\n */\n/**\n * Cor da grade, lida do PRIMEIRO lado LIGADO do `w:tblBorders`.\n *\n * Lados desligados são ignorados de propósito: o Word emite `w:val=\"none\"` com\n * `w:color=\"auto\"`, que não carrega informação de cor — ler dali gravaria lixo.\n * `auto` também não grava, para o documento cair no default do modelo.\n */\nfunction readBorderColor(tbl: OoxmlNode): string | undefined {\n const tblPr = findChild(tbl, \"w:tblPr\");\n const b = tblPr ? findChild(tblPr, \"w:tblBorders\") : undefined;\n if (!b) return undefined;\n const LADOS = [\n \"w:top\",\n \"w:bottom\",\n \"w:left\",\n \"w:start\",\n \"w:right\",\n \"w:end\",\n \"w:insideH\",\n \"w:insideV\",\n ];\n for (const nome of LADOS) {\n const n = findChild(b, nome);\n if (!n) continue;\n const val = (attr(n, \"w:val\") ?? \"\").toLowerCase();\n if (val === \"\" || val === \"none\" || val === \"nil\") continue;\n const hex = attr(n, \"w:color\");\n if (!hex || hex.toLowerCase() === \"auto\") continue;\n const css = docxHexToCssColor(hex);\n if (css) return css;\n }\n return undefined;\n}\n\nfunction readBorderPreset(tbl: OoxmlNode): TableBorderPreset | undefined {\n const tblPr = findChild(tbl, \"w:tblPr\");\n const b = tblPr ? findChild(tblPr, \"w:tblBorders\") : undefined;\n if (!b) return undefined;\n\n // `borderSideOn` trata os nomes alternativos do OOXML estrito (start/end) e\n // ignora lados declarados como \"none\"/\"nil\".\n const ligado = (...nomes: string[]): boolean => borderSideOn(b, ...nomes);\n\n const top = ligado(\"w:top\");\n const bottom = ligado(\"w:bottom\");\n const left = ligado(\"w:left\", \"w:start\");\n const right = ligado(\"w:right\", \"w:end\");\n const iH = ligado(\"w:insideH\");\n const iV = ligado(\"w:insideV\");\n\n if (top && bottom && left && right && iH && iV) return \"all\";\n if (top && bottom && left && right && !iH && !iV) return \"outer\";\n if (top && bottom && !left && !right && iH && !iV) return \"horizontal\";\n if (!top && !bottom && left && right && !iH && iV) return \"vertical\";\n if (!top && !bottom && !left && !right && !iH && !iV) return \"none\";\n return \"all\";\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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAA,eAA8E;;;ACA9E,mBAAkB;AAClB,6BAA0B;AAe1B,IAAM,SAAS,IAAI,iCAAU;AAAA,EAC3B,kBAAkB;AAAA,EAClB,qBAAqB;AAAA,EACrB,eAAe;AAAA,EACf,YAAY;AAAA;AAAA,EACZ,qBAAqB;AAAA,EACrB,eAAe;AACjB,CAAC;AAWD,eAAsB,SAAS,OAA2D;AACxF,QAAM,OACJ,iBAAiB,aACb,QACA,iBAAiB,cACf,IAAI,WAAW,KAAK,IACpB,IAAI,WAAW,MAAO,MAAe,YAAY,CAAC;AAE1D,QAAM,MAAM,MAAM,aAAAC,QAAM,UAAU,IAAI;AACtC,QAAM,cAAc,MAAM,QAAQ,KAAK,mBAAmB;AAC1D,MAAI,CAAC,YAAa,OAAM,IAAI,MAAM,0CAA0C;AAE5E,QAAM,eAAe,MAAM,QAAQ,KAAK,oBAAoB;AAC5D,QAAM,UAAU,MAAM,QAAQ,KAAK,8BAA8B;AACjE,QAAM,gBAAgB,mBAAmB,OAAO;AAEhD,QAAM,aAAa,oBAAI,IAAwB;AAC/C,QAAM,cAAc,IAAI,OAAO,YAAY;AAC3C,MAAI,aAAa;AACf,UAAM,WAA4B,CAAC;AACnC,gBAAY,QAAQ,CAAC,cAAc,SAAS;AAC1C,UAAI,KAAK,IAAK;AACd,eAAS;AAAA,QACP,KAAK,MAAM,YAAY,EAAE,KAAK,CAAC,UAAU;AACvC,qBAAW,IAAI,SAAS,YAAY,IAAI,KAAK;AAAA,QAC/C,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AACD,UAAM,QAAQ,IAAI,QAAQ;AAAA,EAC5B;AAEA,SAAO,EAAE,aAAa,cAAc,eAAe,WAAW;AAChE;AAEA,eAAe,QAAQ,KAAY,MAAgD;AACjF,QAAM,QAAQ,IAAI,KAAK,IAAI;AAC3B,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,OAAO,MAAM,MAAM,MAAM,QAAQ;AACvC,SAAO,OAAO,MAAM,IAAI;AAC1B;AAEA,SAAS,mBAAmB,OAAqD;AAC/E,QAAM,MAAM,oBAAI,IAAoB;AACpC,MAAI,CAAC,MAAO,QAAO;AAEnB,aAAW,OAAO,OAAO;AACvB,UAAM,WAAW,IAAI,eAAe;AACpC,QAAI,CAAC,MAAM,QAAQ,QAAQ,EAAG;AAC9B,eAAW,SAAS,UAAyB;AAC3C,UAAI,EAAE,kBAAkB,OAAQ;AAChC,YAAM,QAAS,MAAM,IAAI,KAAK,CAAC;AAC/B,YAAM,KAAK,MAAM,MAAM;AACvB,YAAM,SAAS,MAAM,UAAU;AAC/B,UAAI,OAAO,OAAO,YAAY,OAAO,WAAW,UAAU;AACxD,YAAI,IAAI,IAAI,MAAM;AAAA,MACpB;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAKO,SAAS,MAAM,MAAgC;AACpD,aAAW,OAAO,OAAO,KAAK,IAAI,GAAG;AACnC,QAAI,QAAQ,KAAM;AAClB,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAiBO,SAAS,WAAW,MAA8B;AACvD,QAAM,MAAM,MAAM,IAAI;AACtB,MAAI,CAAC,IAAK,QAAO,CAAC;AAClB,QAAM,IAAI,KAAK,GAAG;AAClB,MAAI,CAAC,MAAM,QAAQ,CAAC,EAAG,QAAO,CAAC;AAC/B,QAAM,OAAO;AAGb,MAAI,SAAS;AACb,aAAW,KAAK,MAAM;AACpB,QAAI,MAAM,CAAC,MAAM,SAAS;AACxB,eAAS;AACT;AAAA,IACF;AAAA,EACF;AACA,MAAI,CAAC,OAAQ,QAAO;AAEpB,QAAM,MAAmB,CAAC;AAC1B,aAAW,KAAK,MAAM;AACpB,QAAI,MAAM,CAAC,MAAM,SAAS;AACxB,UAAI,KAAK,CAAC;AACV;AAAA,IACF;AAGA,UAAM,UAAU,WAAW,CAAC,EAAE,KAAK,CAAC,MAAM,MAAM,CAAC,MAAM,cAAc;AACrE,QAAI,QAAS,KAAI,KAAK,GAAG,WAAW,OAAO,CAAC;AAAA,EAC9C;AACA,SAAO;AACT;AAGO,SAAS,QAAQ,MAA0C;AAChE,SAAS,KAAK,IAAI,KAAK,CAAC,KAAkC,CAAC;AAC7D;AAGO,SAAS,KAAK,MAAiB,KAAiC;AACrE,QAAM,IAAI,QAAQ,IAAI,EAAE,KAAK,GAAG,EAAE;AAClC,SAAO,OAAO,MAAM,WAAW,IAAI;AACrC;AAGO,SAAS,UAAU,MAAiB,KAAoC;AAC7E,aAAW,SAAS,WAAW,IAAI,GAAG;AACpC,QAAI,MAAM,KAAK,MAAM,IAAK,QAAO;AAAA,EACnC;AACA,SAAO;AACT;AAGO,SAAS,aAAa,MAAiB,KAA0B;AACtE,QAAM,MAAmB,CAAC;AAC1B,aAAW,SAAS,WAAW,IAAI,GAAG;AACpC,QAAI,MAAM,KAAK,MAAM,IAAK,KAAI,KAAK,KAAK;AAAA,EAC1C;AACA,SAAO;AACT;AA2BO,SAAS,aAAa,WAAkC,OAA0B;AACvF,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO,MAAM,KAAK,CAAC,SAAS;AAC1B,UAAM,IAAI,UAAU,QAAQ,IAAI;AAChC,QAAI,CAAC,EAAG,QAAO;AACf,UAAM,OAAO,KAAK,GAAG,OAAO,KAAK,IAAI,YAAY;AACjD,WAAO,QAAQ,MAAM,QAAQ,UAAU,QAAQ;AAAA,EACjD,CAAC;AACH;;;AC/MO,SAAS,kBAAkB,YAAwC;AACxE,MAAI,CAAC,OAAO,SAAS,UAAU,KAAK,cAAc,EAAG,QAAO;AAC5D,QAAM,KAAK,aAAa;AACxB,SAAO,GAAG,mBAAmB,EAAE,CAAC;AAClC;AAGO,SAAS,kBAAkB,KAA6C;AAC7E,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,IAAI,iBAAiB,KAAK,IAAI,KAAK,CAAC;AAC1C,MAAI,CAAC,EAAG,QAAO;AACf,SAAO,IAAI,IAAI,YAAY,CAAC;AAC9B;AAGO,SAAS,WAAW,KAA8E;AACvG,MAAI,CAAC,IAAK,QAAO;AACjB,UAAQ,IAAI,YAAY,GAAG;AAAA,IACzB,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAGO,SAAS,aAAa,KAAc,WAAW,GAAW;AAC/D,MAAI,OAAO,QAAQ,YAAY,OAAO,SAAS,GAAG,EAAG,QAAO,KAAK,MAAM,GAAG;AAC1E,MAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,QAAM,IAAI,OAAO,SAAS,KAAK,EAAE;AACjC,SAAO,OAAO,SAAS,CAAC,IAAI,IAAI;AAClC;AAEA,SAAS,mBAAmB,GAAmB;AAE7C,SAAO,OAAO,UAAU,CAAC,IAAI,EAAE,SAAS,IAAI,EAAE,QAAQ,CAAC,EAAE,QAAQ,UAAU,EAAE;AAC/E;;;AC/CA,IAAM,aAAa;AAEnB,IAAM,cAAsC;AAAA,EAC1C,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AACP;AAYO,SAAS,wBACd,SACA,KACmB;AAInB,MAAI;AACJ,MAAI;AACJ,MAAI;AAEJ,OAAK,SAAS,CAAC,MAAM;AACnB,UAAM,MAAM,MAAM,CAAC;AACnB,QAAI,CAAC,IAAK;AACV,QAAI,QAAQ,UAAU;AACpB,YAAM,KAAK,KAAK,GAAG,SAAS,KAAK,KAAK,GAAG,QAAQ;AACjD,UAAI,GAAI,WAAU;AAAA,IACpB,WAAW,QAAQ,aAAa;AAC9B,WAAK,aAAa,KAAK,GAAG,IAAI,CAAC;AAC/B,WAAK,aAAa,KAAK,GAAG,IAAI,CAAC;AAAA,IACjC;AAAA,EACF,CAAC;AAED,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,SAAS,IAAI,cAAc,IAAI,OAAO;AAC5C,MAAI,CAAC,OAAQ,QAAO;AAGpB,QAAM,QAAQ,IAAI,WAAW,IAAI,MAAM;AACvC,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,MAAM,YAAY,MAAM;AAC9B,QAAM,OAAO,YAAY,GAAG,KAAK;AACjC,QAAM,MAAM,QAAQ,IAAI,WAAW,cAAc,KAAK,CAAC;AACvD,QAAM,UAAU,MAAM,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,UAAU,CAAC,IAAI;AACxE,QAAM,WAAW,MAAM,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,UAAU,CAAC,IAAI;AAEzE,SAAO,EAAE,MAAM,SAAS,KAAK,OAAO,SAAS,QAAQ,SAAS;AAChE;AAEA,SAAS,KAAK,MAAiB,OAAqC;AAClE,QAAM,IAAI;AACV,aAAW,SAAS,WAAW,IAAI,GAAG;AACpC,QAAI,WAAW,MAAO;AACtB,SAAK,OAAO,KAAK;AAAA,EACnB;AACF;AAEA,SAAS,YAAY,MAAsB;AACzC,QAAM,IAAI,kBAAkB,KAAK,IAAI;AACrC,SAAO,IAAI,EAAE,CAAC,EAAE,YAAY,IAAI;AAClC;AAEA,SAAS,cAAc,OAA2B;AAEhD,MAAI,OAAO,SAAS,YAAY;AAC9B,QAAI,MAAM;AACV,UAAM,QAAQ;AACd,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,OAAO;AAC5C,aAAO,OAAO,aAAa,MAAM,MAAM,MAAM,KAAK,MAAM,SAAS,GAAG,IAAI,KAAK,CAAC,CAAC;AAAA,IACjF;AACA,WAAO,KAAK,GAAG;AAAA,EACjB;AAEA,SAAO,OAAO,KAAK,KAAK,EAAE,SAAS,QAAQ;AAC7C;;;ACxEO,SAAS,yBAAyB,UAAuB,KAA4B;AAC1F,QAAM,MAAiB,CAAC;AACxB,aAAW,SAAS,UAAU;AAC5B,UAAM,MAAM,MAAM,KAAK;AACvB,QAAI,CAAC,IAAK;AACV,QAAI,QAAQ,QAAS;AACrB,QAAI,QAAQ,OAAO;AACjB,iBAAW,OAAO,KAAK,QAAW,GAAG;AAAA,IACvC,WAAW,QAAQ,eAAe;AAEhC,YAAM,MAAM,KAAK,OAAO,MAAM;AAC9B,YAAM,OAAO,MAAM,IAAI,cAAc,IAAI,GAAG,IAAI;AAChD,YAAM,WAAkC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI;AACpE,iBAAW,OAAO,WAAW,KAAK,GAAG;AACnC,YAAI,MAAM,GAAG,MAAM,MAAO,YAAW,KAAK,KAAK,UAAU,GAAG;AAAA,MAC9D;AAAA,IACF;AAAA,EACF;AACA,SAAO,cAAc,GAAG;AAC1B;AAEA,SAAS,WACP,KACA,KACA,eACA,KACM;AACN,QAAM,QAAQ,WAAW,eAAe,SAAS,UAAU,KAAK,OAAO,CAAC,CAAC;AACzE,aAAW,SAAS,WAAW,GAAG,GAAG;AACnC,UAAM,MAAM,MAAM,KAAK;AACvB,QAAI,CAAC,IAAK;AACV,QAAI,QAAQ,OAAO;AACjB,YAAM,OAAO,YAAY,KAAK;AAC9B,UAAI,KAAK,SAAS,EAAG,MAAK,KAAK,MAAM,KAAK;AAAA,IAC5C,WAAW,QAAQ,SAAS;AAC1B,WAAK,KAAK,KAAM,KAAK;AAAA,IACvB,WAAW,QAAQ,QAAQ;AAGzB,WAAK,KAAK,MAAM,KAAK;AAAA,IACvB,WAAW,QAAQ,aAAa;AAC9B,YAAM,QAAQ,wBAAwB,OAAO,GAAG;AAChD,UAAI,MAAO,KAAI,KAAK,EAAE,QAAQ,MAAM,CAAC;AAAA,IACvC;AAAA,EAEF;AACF;AAOA,IAAM,wBAAgD;AAAA,EACpD,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,SAAS;AAAA,EACT,MAAM;AAAA,EACN,KAAK;AAAA,EACL,UAAU;AAAA,EACV,UAAU;AAAA,EACV,WAAW;AAAA,EACX,aAAa;AAAA,EACb,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,WAAW;AAAA,EACX,OAAO;AAAA,EACP,OAAO;AACT;AAEA,SAAS,SAAS,KAAuC;AACvD,QAAM,IAAe,CAAC;AACtB,MAAI,CAAC,IAAK,QAAO;AACjB,aAAW,SAAS,WAAW,GAAG,GAAG;AACnC,UAAM,MAAM,MAAM,KAAK;AACvB,QAAI,CAAC,IAAK;AACV,YAAQ,KAAK;AAAA,MACX,KAAK;AACH,YAAI,CAAC,QAAQ,KAAK,OAAO,OAAO,CAAC,EAAG,GAAE,OAAO;AAC7C;AAAA,MACF,KAAK;AACH,YAAI,CAAC,QAAQ,KAAK,OAAO,OAAO,CAAC,EAAG,GAAE,SAAS;AAC/C;AAAA,MACF,KAAK,OAAO;AACV,cAAM,MAAM,KAAK,OAAO,OAAO;AAC/B,YAAI,OAAO,IAAI,YAAY,MAAM,OAAQ,GAAE,YAAY;AACvD;AAAA,MACF;AAAA,MACA,KAAK;AACH,YAAI,CAAC,QAAQ,KAAK,OAAO,OAAO,CAAC,EAAG,GAAE,SAAS;AAC/C;AAAA,MACF,KAAK,WAAW;AACd,cAAM,MAAM,KAAK,OAAO,OAAO;AAC/B,cAAM,MAAM,kBAAkB,GAAG;AACjC,YAAI,IAAK,GAAE,QAAQ;AACnB;AAAA,MACF;AAAA,MACA,KAAK,SAAS;AAEZ,cAAM,OAAO,KAAK,OAAO,QAAQ;AACjC,YAAI,QAAQ,KAAK,YAAY,MAAM,QAAQ;AACzC,gBAAM,MAAM,kBAAkB,IAAI;AAClC,cAAI,IAAK,GAAE,YAAY;AAAA,QACzB;AACA;AAAA,MACF;AAAA,MACA,KAAK,eAAe;AAClB,cAAM,MAAM,uBAAuB,KAAK,OAAO,OAAO,KAAK,IAAI,YAAY,CAAC;AAC5E,YAAI,IAAK,GAAE,YAAY;AACvB;AAAA,MACF;AAAA;AAAA;AAAA;AAAA,MAIA,KAAK,QAAQ;AACX,cAAM,UAAU,OAAO,WAAW,KAAK,OAAO,OAAO,KAAK,EAAE;AAC5D,cAAM,MAAM,kBAAkB,OAAO;AACrC,YAAI,IAAK,GAAE,WAAW;AACtB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,WAAW,GAA0B,GAAyB;AACrE,MAAI,CAAC,EAAG,QAAO;AACf,SAAO,EAAE,GAAG,GAAG,GAAG,EAAE;AACtB;AAEA,SAAS,YAAY,MAAyB;AAC5C,MAAI,MAAM;AACV,aAAW,SAAS,WAAW,IAAI,GAAG;AACpC,QAAI,WAAW,OAAO;AACpB,YAAM,IAAI,MAAM,OAAO;AACvB,UAAI,OAAO,MAAM,SAAU,QAAO;AAAA,IACpC;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,QAAQ,KAAkC;AACjD,MAAI,OAAO,KAAM,QAAO;AACxB,QAAM,IAAI,IAAI,YAAY;AAC1B,SAAO,MAAM,OAAO,MAAM,WAAW,MAAM;AAC7C;AAEA,SAAS,KAAK,KAAgB,MAAc,OAAwB;AAClE,QAAM,KACJ,OAAO,KAAK,KAAK,EAAE,WAAW,IAAI,EAAE,QAAQ,KAAK,IAAI,EAAE,QAAQ,MAAM,YAAY,EAAE,GAAG,MAAM,EAAE;AAChG,MAAI,KAAK,EAAE;AACb;AAEA,SAAS,cAAc,KAA2B;AAChD,QAAM,MAAiB,CAAC;AACxB,aAAW,MAAM,KAAK;AACpB,UAAM,OAAO,IAAI,IAAI,SAAS,CAAC;AAC/B,QACE,QACA,OAAO,KAAK,WAAW,YACvB,OAAO,GAAG,WAAW,YACrB,UAAU,KAAK,YAAY,GAAG,UAAU,GACxC;AACA,WAAK,SAAS,KAAK,SAAS,GAAG;AAC/B;AAAA,IACF;AACA,QAAI,KAAK,EAAE;AAAA,EACb;AACA,SAAO;AACT;AAEA,SAAS,UAAU,GAA0B,GAAmC;AAC9E,QAAM,KAAK,IAAI,OAAO,KAAK,CAAC,EAAE,KAAK,IAAI,CAAC;AACxC,QAAM,KAAK,IAAI,OAAO,KAAK,CAAC,EAAE,KAAK,IAAI,CAAC;AACxC,MAAI,GAAG,WAAW,GAAG,OAAQ,QAAO;AACpC,WAAS,IAAI,GAAG,IAAI,GAAG,QAAQ,KAAK;AAClC,QAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAG,QAAO;AAC5B,UAAM,KAAM,EAA8B,GAAG,CAAC,CAAC;AAC/C,UAAM,KAAM,EAA8B,GAAG,CAAC,CAAC;AAC/C,QAAI,OAAO,OAAO,YAAY,OAAO,QAAQ,OAAO,OAAO,YAAY,OAAO,MAAM;AAClF,UAAI,KAAK,UAAU,EAAE,MAAM,KAAK,UAAU,EAAE,EAAG,QAAO;AAAA,IACxD,WAAW,OAAO,IAAI;AACpB,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;;;ACrLO,SAAS,iBACd,GACA,KACA,WACiB;AACjB,QAAM,MAAM,UAAU,GAAG,OAAO;AAChC,QAAM,QAAQ,MAAM,UAAU,KAAK,SAAS,IAAI;AAChD,QAAM,UAAU,MAAM,KAAK,UAAU,KAAK,UAAU,KAAK,CAAC,GAAG,OAAO,IAAI;AAExE,QAAM,QAAQ,yBAAyB,WAAW,CAAC,GAAG,GAAG;AACzD,QAAM,OAAO,YAAY,KAAK;AAC9B,QAAM,QAAQ,WAAW,MAAM,KAAK,UAAU,KAAK,MAAM,KAAK,CAAC,GAAG,OAAO,IAAI,MAAS;AACtF,QAAM,QAAQ,MAAM,CAAC,CAAC,UAAU,KAAK,QAAQ,IAAI;AAGjD,MAAI,OAAO;AACT,UAAM,WAAW,UAAU,QAAQ,KAAK;AACxC,UAAMC,SAAoB;AAAA,MACxB,UAAU,UAAU,YAAY;AAAA,MAChC,WAAW,UAAU,aAAa;AAAA,IACpC;AACA,QAAI,UAAU,aAAa,WAAW;AAMpC,UAAI,SAAS,WAAW,KAAM,CAAAA,OAAM,YAAY,SAAS;AACzD,UAAI,SAAS,UAAW,CAAAA,OAAM,YAAY,SAAS;AAAA,IACrD;AACA,QAAI,MAAO,CAAAA,OAAM,QAAQ;AACzB,QAAI,MAAO,CAAAA,OAAM,MAAM;AACvB,WAAO,EAAE,MAAM,YAAY,MAAM,OAAO,OAAAA,OAAM;AAAA,EAChD;AAGA,QAAM,eAAe,UAAU,mBAAmB,OAAO,IAAI;AAC7D,MAAI,gBAAgB,MAAM;AACxB,UAAMA,SAAoB,EAAE,OAAO,aAAa;AAChD,QAAI,MAAO,CAAAA,OAAM,QAAQ;AACzB,QAAI,MAAO,CAAAA,OAAM,MAAM;AACvB,WAAO,EAAE,MAAM,WAAW,MAAM,OAAO,OAAAA,OAAM;AAAA,EAC/C;AAGA,MAAI,OAAO,cAAc,GAAG,GAAG;AAC7B,UAAMA,SAAoB,CAAC;AAC3B,QAAI,MAAO,CAAAA,OAAM,QAAQ;AACzB,QAAI,MAAO,CAAAA,OAAM,MAAM;AACvB,WAAO,EAAE,MAAM,cAAc,MAAM,OAAO,OAAAA,OAAM;AAAA,EAClD;AAGA,MAAI,OAAO,oBAAoB,GAAG,GAAG;AACnC,UAAMA,SAAoB,CAAC;AAC3B,QAAI,MAAO,CAAAA,OAAM,QAAQ;AACzB,QAAI,MAAO,CAAAA,OAAM,MAAM;AACvB,WAAO,EAAE,MAAM,aAAa,MAAM,OAAO,OAAAA,OAAM;AAAA,EACjD;AAEA,QAAM,QAAoB,CAAC;AAC3B,MAAI,MAAO,OAAM,QAAQ;AACzB,MAAI,MAAO,OAAM,MAAM;AACvB,SAAO,OAAO,OAAO,eAAe,KAAK,KAAK,SAAS,CAAC,CAAC;AACzD,SAAO,EAAE,MAAM,aAAa,MAAM,OAAO,MAAM;AACjD;AASA,SAAS,eAAe,KAA4B,SAAuC;AACzF,MAAI,CAAC,OAAO,QAAS,QAAO,CAAC;AAC7B,QAAM,OAAO,UAAU,KAAK,QAAQ;AACpC,MAAI,CAAC,KAAM,QAAO,CAAC;AACnB,MAAI,CAAC,aAAa,MAAM,UAAU,EAAG,QAAO,CAAC;AAC7C,SAAO,EAAE,YAAY,MAAM,mBAAmB,sBAAsB,GAAG,EAAE;AAC3E;AAGA,SAAS,sBAAsB,KAAmC;AAChE,QAAM,KAAK,UAAU,KAAK,WAAW;AACrC,QAAM,OAAO,KAAK,OAAO,WAAW,KAAK,IAAI,QAAQ,KAAK,EAAE,IAAI;AAChE,MAAI,CAAC,OAAO,SAAS,IAAI,EAAG,QAAO;AACnC,QAAM,UAA+B,CAAC,GAAG,KAAK,CAAC;AAC/C,MAAI,OAA0B;AAC9B,MAAI,WAAW;AACf,aAAW,KAAK,SAAS;AACvB,UAAM,IAAI,KAAK,IAAI,OAAO,MAAM,CAAC;AACjC,QAAI,IAAI,UAAU;AAChB,iBAAW;AACX,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,YAAY,OAA0B;AAC7C,MAAI,MAAM;AACV,aAAW,MAAM,OAAO;AACtB,QAAI,OAAO,GAAG,WAAW,SAAU,QAAO,GAAG;AAAA,EAC/C;AACA,SAAO;AACT;AAEA,SAAS,mBAAmB,IAA0C;AACpE,QAAM,IAAI,uBAAuB,KAAK,EAAE;AACxC,MAAI,CAAC,EAAG,QAAO;AACf,QAAM,IAAI,OAAO,SAAS,EAAE,CAAC,GAAG,EAAE;AAClC,SAAQ,KAA+B;AACzC;AAEA,SAAS,cAAc,KAAyB;AAC9C,QAAM,OAAO,UAAU,KAAK,QAAQ;AACpC,MAAI,CAAC,KAAM,QAAO;AAIlB,SAAO,aAAa,MAAM,UAAU,SAAS;AAC/C;AAEA,SAAS,oBAAoB,KAAyB;AACpD,QAAM,MAAM,UAAU,KAAK,OAAO;AAClC,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,OAAO,KAAK,KAAK,QAAQ;AAC/B,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,KAAK,YAAY,MAAM;AAChC;;;AClIO,SAAS,aAAa,KAAgB,KAAkC;AAC7E,QAAM,UAAU,UAAU,KAAK,WAAW;AAC1C,QAAM,WAAW,UAAU,aAAa,SAAS,WAAW,IAAI,CAAC;AACjE,QAAM,MAAM,aAAa,KAAK,MAAM;AAKpC,MAAI,OAAO,SAAS;AACpB,aAAW,MAAM,KAAK;AACpB,UAAM,MAAM,aAAa,IAAI,MAAM;AACnC,QAAI,QAAQ;AACZ,eAAW,MAAM,IAAK,UAAS,WAAW,EAAE;AAC5C,QAAI,QAAQ,KAAM,QAAO;AAAA,EAC3B;AACA,MAAI,OAAO,EAAG,QAAO;AACrB,QAAM,OAAO,IAAI;AAIjB,QAAM,QAAsC,IAAI,MAAM,OAAO,IAAI,EAAE,KAAK,IAAI;AAG5E,QAAM,oBAAoB,oBAAI,IAA0C;AAExE,WAAS,IAAI,GAAG,IAAI,MAAM,KAAK;AAC7B,UAAM,KAAK,IAAI,CAAC;AAChB,QAAI,SAAS;AACb,eAAW,MAAM,aAAa,IAAI,MAAM,GAAG;AAEzC,aAAO,SAAS,QAAQ,MAAM,IAAI,OAAO,MAAM,MAAM,KAAM;AAC3D,UAAI,UAAU,KAAM;AAEpB,YAAM,OAAO,UAAU,IAAI,QAAQ;AACnC,YAAM,WAAW,WAAW,EAAE;AAC9B,YAAM,aAAa,OAAO,UAAU,MAAM,UAAU,IAAI;AACxD,YAAM,YAAY,aAAc,KAAK,YAAY,OAAO,KAAK,aAAc;AAE3E,UAAI,cAAc,cAAc,WAAW;AAGzC,cAAM,SAAS,kBAAkB,IAAI,MAAM;AAC3C,YAAI,QAAQ;AACV,gBAAM,YAAY,OAAO,MAAM,OAAO,OAAO;AAC7C,gBAAM,IAAI,MAAM,SAAS;AACzB,cAAI,GAAG;AACL,cAAE,QAAQ,EAAE,GAAI,EAAE,SAAS,CAAC,GAAI,UAAU,EAAE,OAAO,WAAW,KAAK,EAAE;AAAA,UACvE;AAAA,QACF;AACA,iBAAS,IAAI,GAAG,IAAI,YAAY,SAAS,IAAI,MAAM,KAAK;AACtD,gBAAM,IAAI,OAAO,SAAS,CAAC,IAAI,YAAY;AAAA,QAC7C;AACA,kBAAU;AACV;AAAA,MACF;AAGA,YAAM,QAAQ,oBAAoB,IAAI,GAAG;AACzC,YAAM,OAAO,YAAY,KAAK;AAC9B,YAAM,YAAuB,CAAC;AAC9B,UAAI,WAAW,EAAG,WAAU,UAAU;AAGtC,YAAM,WAA2B,EAAE,MAAM,OAAO,OAAO,UAAU;AACjE,YAAM,IAAI,OAAO,MAAM,IAAI;AAG3B,eAAS,IAAI,GAAG,IAAI,YAAY,SAAS,IAAI,MAAM,KAAK;AACtD,cAAM,IAAI,OAAO,SAAS,CAAC,IAAI,YAAY;AAAA,MAC7C;AAEA,UAAI,cAAc,WAAW;AAC3B,0BAAkB,IAAI,QAAQ,EAAE,KAAK,GAAG,KAAK,OAAO,CAAC;AAAA,MACvD,OAAO;AACL,0BAAkB,OAAO,MAAM;AAAA,MACjC;AACA,gBAAU;AAAA,IACZ;AAIA,aAAS,IAAI,GAAG,IAAI,MAAM,KAAK;AAC7B,UAAI,MAAM,IAAI,OAAO,CAAC,MAAM,MAAM;AAChC,cAAM,IAAI,OAAO,CAAC,IAAI,UAAU;AAAA,MAClC;AAAA,IACF;AAAA,EACF;AAEA,QAAM,QAA0B,MAAM,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC;AAEjE,QAAM,QAAoB,EAAE,MAAM,KAAK;AACvC,QAAM,SAAS,iBAAiB,GAAG;AACnC,MAAI,OAAQ,OAAM,eAAe;AACjC,QAAM,cAAc,gBAAgB,GAAG;AACvC,MAAI,YAAa,OAAM,cAAc;AACrC,SAAO,EAAE,MAAM,SAAS,MAAM,IAAI,OAAO,CAAC,GAAG,OAAO,MAAM;AAC5D;AAmBA,SAAS,gBAAgB,KAAoC;AAC3D,QAAM,QAAQ,UAAU,KAAK,SAAS;AACtC,QAAM,IAAI,QAAQ,UAAU,OAAO,cAAc,IAAI;AACrD,MAAI,CAAC,EAAG,QAAO;AACf,QAAM,QAAQ;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,aAAW,QAAQ,OAAO;AACxB,UAAM,IAAI,UAAU,GAAG,IAAI;AAC3B,QAAI,CAAC,EAAG;AACR,UAAM,OAAO,KAAK,GAAG,OAAO,KAAK,IAAI,YAAY;AACjD,QAAI,QAAQ,MAAM,QAAQ,UAAU,QAAQ,MAAO;AACnD,UAAM,MAAM,KAAK,GAAG,SAAS;AAC7B,QAAI,CAAC,OAAO,IAAI,YAAY,MAAM,OAAQ;AAC1C,UAAM,MAAM,kBAAkB,GAAG;AACjC,QAAI,IAAK,QAAO;AAAA,EAClB;AACA,SAAO;AACT;AAEA,SAAS,iBAAiB,KAA+C;AACvE,QAAM,QAAQ,UAAU,KAAK,SAAS;AACtC,QAAM,IAAI,QAAQ,UAAU,OAAO,cAAc,IAAI;AACrD,MAAI,CAAC,EAAG,QAAO;AAIf,QAAM,SAAS,IAAI,UAA6B,aAAa,GAAG,GAAG,KAAK;AAExE,QAAM,MAAM,OAAO,OAAO;AAC1B,QAAM,SAAS,OAAO,UAAU;AAChC,QAAM,OAAO,OAAO,UAAU,SAAS;AACvC,QAAM,QAAQ,OAAO,WAAW,OAAO;AACvC,QAAM,KAAK,OAAO,WAAW;AAC7B,QAAM,KAAK,OAAO,WAAW;AAE7B,MAAI,OAAO,UAAU,QAAQ,SAAS,MAAM,GAAI,QAAO;AACvD,MAAI,OAAO,UAAU,QAAQ,SAAS,CAAC,MAAM,CAAC,GAAI,QAAO;AACzD,MAAI,OAAO,UAAU,CAAC,QAAQ,CAAC,SAAS,MAAM,CAAC,GAAI,QAAO;AAC1D,MAAI,CAAC,OAAO,CAAC,UAAU,QAAQ,SAAS,CAAC,MAAM,GAAI,QAAO;AAC1D,MAAI,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,GAAI,QAAO;AAC7D,SAAO;AACT;AAEA,SAAS,WAAW,IAAuB;AACzC,QAAM,OAAO,UAAU,IAAI,QAAQ;AACnC,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,KAAK,UAAU,MAAM,YAAY;AACvC,MAAI,CAAC,GAAI,QAAO;AAChB,QAAM,IAAI,aAAa,KAAK,IAAI,OAAO,GAAG,CAAC;AAC3C,SAAO,KAAK,IAAI,GAAG,CAAC;AACtB;AAEA,SAAS,oBAAoB,IAAe,KAA4B;AAItE,QAAM,MAAiB,CAAC;AACxB,MAAI,QAAQ;AACZ,aAAW,SAAS,WAAW,EAAE,GAAG;AAClC,QAAI,MAAM,KAAK,MAAM,MAAO;AAC5B,QAAI,CAAC,MAAO,KAAI,KAAK,EAAE,QAAQ,KAAK,CAAC;AACrC,YAAQ;AACR,QAAI,KAAK,GAAG,yBAAyB,WAAW,KAAK,GAAG,GAAG,CAAC;AAAA,EAC9D;AACA,SAAO;AACT;AAEA,SAAS,YAAY,OAA0B;AAC7C,MAAI,MAAM;AACV,aAAW,MAAM,OAAO;AACtB,QAAI,OAAO,GAAG,WAAW,SAAU,QAAO,GAAG;AAAA,EAC/C;AACA,SAAO;AACT;AAEA,SAAS,cAA8B;AACrC,SAAO,EAAE,MAAM,IAAI,OAAO,CAAC,GAAG,OAAO,EAAE,SAAS,KAAK,EAAE;AACzD;AAEA,SAAS,YAA4B;AACnC,SAAO,EAAE,MAAM,IAAI,OAAO,CAAC,GAAG,OAAO,CAAC,EAAE;AAC1C;;;AC9MA,IAAM,oBAAmD;AAAA,EACvD,SAAS;AAAA,EACT,aAAa;AAAA,EACb,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,YAAY;AACd;AAiBO,IAAM,oBAAN,MAAwB;AAAA,EACrB,kBAAkB,oBAAI,IAAoB;AAAA,EAC1C,mBAAmB,oBAAI,IAAiC;AAAA,EACxD,qBAAqB,oBAAI,IAAiC;AAAA;AAAA,EAE1D,WAAW,oBAAI,IAAsB;AAAA,EAE7C,YAAY,cAAuC;AACjD,QAAI,CAAC,aAAc;AACnB,eAAW,OAAO,cAAc;AAC9B,UAAI,MAAM,GAAG,MAAM,cAAe;AAClC,iBAAW,SAAS,WAAW,GAAG,GAAG;AACnC,cAAM,MAAM,MAAM,KAAK;AACvB,YAAI,QAAQ,iBAAiB;AAC3B,gBAAM,aAAa,KAAK,OAAO,iBAAiB;AAChD,cAAI,CAAC,WAAY;AACjB,gBAAM,SAAS,oBAAI,IAAoB;AACvC,gBAAM,SAAS,oBAAI,IAAoB;AACvC,qBAAW,OAAO,aAAa,OAAO,OAAO,GAAG;AAC9C,kBAAM,OAAO,aAAa,KAAK,KAAK,QAAQ,GAAG,CAAC;AAChD,kBAAM,MAAM,KAAK,UAAU,KAAK,UAAU,KAAK,CAAC,GAAG,OAAO;AAC1D,gBAAI,IAAK,QAAO,IAAI,MAAM,GAAG;AAC7B,kBAAM,QAAQ,UAAU,KAAK,SAAS;AACtC,gBAAI,MAAO,QAAO,IAAI,MAAM,aAAa,KAAK,OAAO,OAAO,GAAG,CAAC,CAAC;AAAA,UACnE;AACA,eAAK,iBAAiB,IAAI,YAAY,MAAM;AAC5C,eAAK,mBAAmB,IAAI,YAAY,MAAM;AAAA,QAChD,WAAW,QAAQ,SAAS;AAC1B,gBAAM,QAAQ,KAAK,OAAO,SAAS;AACnC,gBAAM,cAAc,UAAU,OAAO,iBAAiB;AACtD,gBAAM,aAAa,cAAc,KAAK,aAAa,OAAO,IAAI;AAC9D,cAAI,SAAS,WAAY,MAAK,gBAAgB,IAAI,OAAO,UAAU;AAAA,QACrE;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,QAAQ,OAAwD;AAC9D,QAAI,CAAC,MAAO,QAAO;AACnB,UAAM,UAAU,UAAU,OAAO,QAAQ;AACzC,UAAM,WAAW,UAAU,OAAO,SAAS;AAC3C,QAAI,CAAC,SAAU,QAAO;AACtB,UAAM,QAAQ,KAAK,UAAU,OAAO;AACpC,QAAI,CAAC,MAAO,QAAO;AACnB,UAAM,YAAY,WAAW,aAAa,UAAU,KAAK,SAAS,OAAO,IAAI,QAAW,CAAC,CAAC;AAC1F,UAAM,aAAa,KAAK,gBAAgB,IAAI,KAAK;AACjD,QAAI,cAAc,MAAM;AAItB,aAAO,EAAE,UAAU,UAAU,UAAU;AAAA,IACzC;AACA,UAAM,SAAS,KAAK,iBAAiB,IAAI,UAAU;AACnD,UAAM,MAAM,QAAQ,IAAI,SAAS,KAAK;AACtC,UAAM,WAAW,IAAI,YAAY;AACjC,UAAM,WAAqB,aAAa,YAAY,aAAa,SAAS,WAAW;AACrF,QAAI,aAAa,SAAU,QAAO,EAAE,UAAU,UAAU;AAGxD,UAAM,QAAQ,KAAK,mBAAmB,IAAI,UAAU,GAAG,IAAI,SAAS,KAAK;AACzE,UAAM,IAAI,KAAK,SAAS,IAAI,KAAK,KAAK,CAAC;AACvC,MAAE,SAAS,IAAI,EAAE,SAAS,KAAK,OAAO,QAAQ,EAAE,SAAS,IAAI;AAC7D,MAAE,SAAS,YAAY;AACvB,SAAK,SAAS,IAAI,OAAO,CAAC;AAE1B,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,SAAS,EAAE,SAAS;AAAA,MACpB,WAAW,kBAAkB,GAAG,KAAK;AAAA,IACvC;AAAA,EACF;AACF;AAEA,SAAS,WAAW,GAAmB;AACrC,MAAI,CAAC,OAAO,SAAS,CAAC,EAAG,QAAO;AAChC,SAAO,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,MAAM,CAAC,CAAC,CAAC;AAC/C;;;AClIA,kBAAwD;AAYxD,IAAM,cAAc,OAAO;AAE3B,SAAS,UAAU,OAAuB;AACxC,aAAO,oBAAO,QAAQ,WAAW;AACnC;AAEO,SAAS,qBACd,QAC0B;AAC1B,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,OAAO,UAAU,QAAQ,QAAQ;AACvC,QAAM,QAAQ,UAAU,QAAQ,SAAS;AACzC,MAAI,CAAC,QAAQ,CAAC,MAAO,QAAO;AAE5B,QAAM,aAAa,OAAO,aAAa,KAAK,MAAM,KAAK,GAAG,CAAC,IAAI;AAC/D,QAAM,cAAc,OAAO,aAAa,KAAK,MAAM,KAAK,GAAG,CAAC,IAAI;AAChE,QAAM,WAAW,QAAQ,aAAa,KAAK,OAAO,OAAO,GAAG,CAAC,IAAI;AACjE,QAAM,cAAc,QAAQ,aAAa,KAAK,OAAO,UAAU,GAAG,CAAC,IAAI;AACvE,QAAM,YAAY,QAAQ,aAAa,KAAK,OAAO,QAAQ,GAAG,CAAC,IAAI;AACnE,QAAM,aAAa,QAAQ,aAAa,KAAK,OAAO,SAAS,GAAG,CAAC,IAAI;AAErE,MAAI,cAAc,KAAK,eAAe,KAAK,YAAY,KAAK,aAAa,GAAG;AAC1E,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,aAAa,IAAI,UAAU,UAAU,IAAI;AACvD,QAAM,SAAS,cAAc,IAAI,UAAU,WAAW,IAAI;AAC1D,QAAM,WAAyB;AAAA,IAC7B;AAAA,IACA;AAAA,IACA,WAAW,UAAU,YAAY,CAAC;AAAA,IAClC,cAAc,UAAU,eAAe,CAAC;AAAA,IACxC,YAAY,UAAU,aAAa,CAAC;AAAA,IACpC,aAAa,UAAU,cAAc,CAAC;AAAA,EACxC;AACA,WAAS,aAAS,0BAAa,SAAS,OAAO,SAAS,MAAM;AAC9D,SAAO;AACT;;;AR/BA,eAAsB,mBACpB,OAC6B;AAC7B,QAAM,OAAO,MAAM,SAAS,KAAK;AACjC,QAAM,YAAY,IAAI,kBAAkB,KAAK,YAAY;AACzD,QAAM,MAAkB;AAAA,IACtB,eAAe,KAAK;AAAA,IACpB,YAAY,KAAK;AAAA,EACnB;AAEA,QAAM,OAAO,SAAS,KAAK,WAAW;AACtC,MAAI,CAAC,KAAM,QAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,aAAa,MAAM,IAAI,OAAO,CAAC,GAAG,OAAO,CAAC,EAAE,CAAC,EAAE;AAEpF,QAAM,SAA4B,CAAC;AACnC,aAAW,SAAS,WAAW,IAAI,GAAG;AACpC,UAAM,MAAM,MAAM,KAAK;AACvB,QAAI,QAAQ,OAAO;AACjB,aAAO,KAAK,iBAAiB,OAAO,KAAK,SAAS,CAAC;AAAA,IACrD,WAAW,QAAQ,SAAS;AAC1B,aAAO,KAAK,aAAa,OAAO,GAAG,CAAC;AAAA,IACtC;AAAA,EAEF;AAEA,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO,KAAK,EAAE,MAAM,aAAa,MAAM,IAAI,OAAO,CAAC,GAAG,OAAO,CAAC,EAAE,CAAC;AAAA,EACnE;AAEA,2BAAyB,MAAM;AAE/B,QAAM,eAAe,qBAAqB,UAAU,MAAM,UAAU,CAAC;AACrE,SAAO,eAAe,EAAE,QAAQ,aAAa,IAAI,EAAE,OAAO;AAC5D;AAaO,SAAS,yBAAyB,QAAiC;AAIxE,MAAI,aAAa;AACjB,MAAI;AACJ,MAAI,WAAqB,CAAC;AAE1B,QAAM,aAAa,MAAM;AACvB,iBAAa;AACb,iBAAa;AACb,eAAW,CAAC;AAAA,EACd;AAEA,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,SAAS,YAAY;AAC7B,iBAAW;AACX;AAAA,IACF;AACA,SAAK,MAAM,MAAM,YAAY,cAAc,WAAW;AAGpD,iBAAW;AACX;AAAA,IACF;AACA,UAAM,QAAQ,MAAM,MAAM,aAAa;AACvC,UAAM,UAAU,OAAO,MAAM,MAAM,cAAc,WAAW,MAAM,MAAM,YAAY;AAEpF,UAAM,uBAAuB,SAAS,KAAK,KAAK,QAAQ,YAAY,SAAS,KAAK,IAAI;AACtF,UAAM,sBAAsB,SAAS,KAAK,KAAK,QAAQ,QAAQ,KAAK,YAAY;AAChF,UAAM,gBACJ,cACA,MAAM,MAAM,cAAc,eACzB,wBAAwB;AAE3B,QAAI,eAAe;AACjB,aAAO,MAAM,MAAM;AAAA,IACrB,OAAO;AAEL,mBAAa;AACb,mBAAa,MAAM,MAAM;AACzB,iBAAW,CAAC;AAAA,IACd;AACA,aAAS,KAAK,IAAI;AAClB,aAAS,SAAS,QAAQ;AAAA,EAC5B;AACF;AAGA,eAAsB,yBACpB,OACyB;AACzB,QAAM,aAAa,MAAM,mBAAmB,KAAK;AACjD,SAAO,4BAAe,SAAS,UAAU;AAC3C;AAEA,SAAS,SAAS,aAAiD;AACjE,aAAW,OAAO,aAAa;AAC7B,QAAI,MAAM,GAAG,MAAM,cAAc;AAC/B,YAAM,OAAO,UAAU,KAAK,QAAQ;AACpC,UAAI,KAAM,QAAO;AAAA,IACnB;AAAA,EACF;AACA,SAAO;AACT;","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 { larguraUtilTwipsDe, 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 // Lido ANTES do loop de blocos: `tableToBlock` precisa da largura útil da\n // página para reconstruir `tableWidth` a partir de `w:tblW` (twips\n // absolutos só fazem sentido percentualmente contra a largura da página).\n // `w:sectPr` é sempre um único nó ao final do `body`, então lê-lo cedo não\n // muda nada do que já era verdade sobre a ordem do documento.\n const sectPr = findChild(body, \"w:sectPr\");\n const pageSettings = sectPrToPageSettings(sectPr);\n const larguraUtilTwips = larguraUtilTwipsDe(sectPr);\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, larguraUtilTwips));\n }\n // w:sectPr already read above; 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 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/**\n * Returns the children array of an element, or [] when none.\n *\n * Content controls (`w:sdt`) são desembrulhados aqui, no lugar. No OOXML eles\n * são wrappers TRANSPARENTES: o conteúdo real vive em `w:sdtContent` e o\n * `w:sdtPr` carrega só metadados (alias, trava). O Word emite `w:sdt` ao\n * BLOQUEAR um trecho, e ele pode aparecer em qualquer nível — envolvendo uma\n * tabela no body, uma `w:tc` dentro de `w:tr`, um `w:p` dentro de `w:tc`, ou um\n * `w:r` dentro de `w:p`.\n *\n * Desembrulhar aqui, e não em cada chamador, é o que garante que todos esses\n * níveis funcionem: `findChild` e `findChildren` também passam por aqui. Antes\n * disso, cada lista branca de tag ignorava o `w:sdt` e o conteúdo travado sumia\n * silenciosamente.\n */\nexport function childrenOf(node: OoxmlNode): OoxmlNode[] {\n const tag = tagOf(node);\n if (!tag) return [];\n const v = node[tag];\n if (!Array.isArray(v)) return [];\n const kids = v as OoxmlNode[];\n // Caminho rápido: sem content control, devolve o array original sem alocar.\n // `childrenOf` é chamada em todo nó do documento.\n let temSdt = false;\n for (const k of kids) {\n if (tagOf(k) === \"w:sdt\") {\n temSdt = true;\n break;\n }\n }\n if (!temSdt) return kids;\n\n const out: OoxmlNode[] = [];\n for (const k of kids) {\n if (tagOf(k) !== \"w:sdt\") {\n out.push(k);\n continue;\n }\n // Só `w:sdtContent` é conteúdo; `w:sdtPr`/`w:sdtEndPr` são metadados.\n // A recursão trata content controls aninhados.\n const content = childrenOf(k).find((c) => tagOf(c) === \"w:sdtContent\");\n if (content) out.push(...childrenOf(content));\n }\n return out;\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/**\n * Um lado de borda (`w:top`, `w:left`, `w:insideH`, …) está LIGADO?\n *\n * A mera presença do elemento não basta: o Word grava blocos de borda\n * COMPLETOS com todos os lados `w:val=\"none\"` — uma declaração no-op. Ler só a\n * presença fazia parágrafos comuns virarem blockquote (cinza e itálico) só\n * porque traziam um `w:pBdr` vazio de significado.\n *\n * Aceita nomes alternativos porque o OOXML estrito usa `w:start`/`w:end` no\n * lugar de `w:left`/`w:right`.\n */\nexport function borderSideOn(parent: OoxmlNode | undefined, ...names: string[]): boolean {\n if (!parent) return false;\n return names.some((name) => {\n const n = findChild(parent, name);\n if (!n) return false;\n const val = (attr(n, \"w:val\") ?? \"\").toLowerCase();\n return val !== \"\" && val !== \"none\" && val !== \"nil\";\n });\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/**\n * OOXML twip → millimeters. Inverse of `convertMillimetersToTwip` from the\n * `docx` package (used by `@sofereditor/export-docx`), reimplemented here\n * because `import-docx` doesn't depend on `docx` — 1 twip = 1/20 pt =\n * 1/1440 in = 25.4/1440 mm.\n */\nexport function twipToMillimeters(twip: number): number {\n return (twip * 25.4) / 1440;\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\n/**\n * Os valores nomeados de `w:highlight` do OOXML. O Word só aceita esta lista\n * fechada — documentos com cor arbitrária usam `w:shd`, que é o que o nosso\n * export emite. `none` fica de fora de propósito: ausência = sem marca.\n */\nconst DOCX_HIGHLIGHT_COLORS: Record<string, string> = {\n yellow: \"#ffff00\",\n green: \"#00ff00\",\n cyan: \"#00ffff\",\n magenta: \"#ff00ff\",\n blue: \"#0000ff\",\n red: \"#ff0000\",\n darkblue: \"#000080\",\n darkcyan: \"#008080\",\n darkgreen: \"#008000\",\n darkmagenta: \"#800080\",\n darkred: \"#800000\",\n darkyellow: \"#808000\",\n darkgray: \"#808080\",\n lightgray: \"#c0c0c0\",\n black: \"#000000\",\n white: \"#ffffff\",\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 case \"w:shd\": {\n // Sombreamento de RUN = marca-texto. `auto` significa \"sem cor\".\n const fill = attr(child, \"w:fill\");\n if (fill && fill.toLowerCase() !== \"auto\") {\n const css = docxHexToCssColor(fill);\n if (css) m.highlight = css;\n }\n break;\n }\n case \"w:highlight\": {\n const css = DOCX_HIGHLIGHT_COLORS[(attr(child, \"w:val\") ?? \"\").toLowerCase()];\n if (css) m.highlight = 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 {\n AlignValue,\n AnswerLineSpacing,\n BlockAttrs,\n BlockType,\n DeltaOp,\n SerializedBlock,\n} from \"@sofereditor/core\";\nimport {\n attr,\n borderSideOn,\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 Object.assign(attrs, readAnswerLine(pPr, text.length > 0));\n return { type: \"paragraph\", text, delta, attrs };\n}\n\n/**\n * Parágrafo SEM texto e com borda INFERIOR = linha de resposta.\n *\n * A exigência de estar vazio é essencial: um parágrafo com texto e régua é um\n * título sublinhado, e convertê-lo em linha de resposta destruiria a semântica\n * do conteúdo. A borda ESQUERDA já é tratada antes como blockquote.\n */\nfunction readAnswerLine(pPr: OoxmlNode | undefined, hasText: boolean): Partial<BlockAttrs> {\n if (!pPr || hasText) return {};\n const pBdr = findChild(pPr, \"w:pBdr\");\n if (!pBdr) return {};\n if (!borderSideOn(pBdr, \"w:bottom\")) return {};\n return { answerLine: true, answerLineSpacing: readAnswerLineSpacing(pPr) };\n}\n\n/** 240 twips = 1 linha. Arredonda para o bucket suportado mais próximo. */\nfunction readAnswerLineSpacing(pPr: OoxmlNode): AnswerLineSpacing {\n const sp = findChild(pPr, \"w:spacing\");\n const line = sp ? Number.parseFloat(attr(sp, \"w:line\") ?? \"\") : NaN;\n if (!Number.isFinite(line)) return 1;\n const buckets: AnswerLineSpacing[] = [1, 1.5, 2];\n let best: AnswerLineSpacing = 1;\n let bestDist = Infinity;\n for (const b of buckets) {\n const d = Math.abs(line - 240 * b);\n if (d < bestDist) {\n bestDist = d;\n best = b;\n }\n }\n return best;\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 // `borderSideOn` (e não a mera presença do elemento): o Word grava pBdr\n // completo com todos os lados \"none\", e ler a presença convertia parágrafo\n // comum em blockquote.\n return borderSideOn(pBdr, \"w:left\", \"w:start\");\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 {\n BlockAttrs,\n CellAttrs,\n DeltaOp,\n SerializedBlock,\n SerializedCell,\n TableBorderPreset,\n} from \"@sofereditor/core\";\nimport {\n MIN_LINHA_PX,\n mmToPx,\n normalizarLarguras,\n travaLarguraTabela,\n} from \"@sofereditor/core\";\nimport {\n attr,\n borderSideOn,\n childrenOf,\n findChild,\n findChildren,\n tagOf,\n type OoxmlNode,\n} from \"./parse-xml\";\nimport { paragraphChildrenToDelta, type RunContext } from \"./runs\";\nimport { docxHexToCssColor, parseIntAttr, twipToMillimeters } 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 *\n * `larguraUtilTwips` (largura útil da PÁGINA, de `w:sectPr`, lida uma vez em\n * `docxBlobToDocument`) é o que permite reconstruir `tableWidth` a partir de\n * `w:tblW` — sem ela, uma tabela exportada com 50% de largura reimportaria\n * como 100%, porque `normalizarLarguras` só recupera a proporção ENTRE\n * colunas, nunca a largura total da tabela contra a página.\n */\nexport function tableToBlock(\n tbl: OoxmlNode,\n ctx: RunContext,\n larguraUtilTwips?: number,\n): 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 const preset = readBorderPreset(tbl);\n if (preset) attrs.borderPreset = preset;\n const borderColor = readBorderColor(tbl);\n if (borderColor) attrs.borderColor = borderColor;\n // `w:gridCol` chega em twips absolutos; `normalizarLarguras` converte para\n // proporção somando 100 — a mesma conta usada para normalizar documentos\n // antigos em px, então não duplicamos a lógica aqui. Quando faltam gridCols\n // (ou o número não bate com `cols`), o próprio helper cai no split igual, o\n // que é idêntico a omitir o atributo — gravá-lo de qualquer forma é\n // inofensivo.\n const twips = gridCols.map((g) => Number(attr(g, \"w:w\") ?? 0));\n attrs.colWidths = normalizarLarguras(twips, cols);\n const rowHeights = readRowHeights(trs);\n if (rowHeights) attrs.rowHeights = rowHeights;\n const tableWidth = readTableWidth(tbl, larguraUtilTwips);\n if (tableWidth !== undefined) attrs.tableWidth = tableWidth;\n return { type: \"table\", text: \"\", delta: [], attrs, cells };\n}\n\n/**\n * Lê `w:w`, que no OOXML é `ST_MeasurementOrPercent`: pode vir como número\n * puro OU com sufixo `%` (\"50%\"). `Number(\"50%\")` é `NaN`, e sem tratar isso\n * a largura era descartada em silêncio e a tabela voltava com 100%.\n */\nfunction leMedida(bruto: string | undefined): { valor: number; ehPercentSufixo: boolean } | undefined {\n if (bruto === undefined) return undefined;\n const t = bruto.trim();\n const comSufixo = t.endsWith(\"%\");\n const n = Number(comSufixo ? t.slice(0, -1) : t);\n if (!Number.isFinite(n) || n <= 0) return undefined;\n return { valor: n, ehPercentSufixo: comSufixo };\n}\n\n/**\n * `w:tblW` → percentual da largura útil da página (`tableWidth`).\n *\n * Dois tipos possíveis: `dxa` (twips absolutos — divide contra\n * `larguraUtilTwips`, a MESMA conta que `export-docx` fez ao contrário) e\n * `pct` (já percentual, só que em quinquagésimos — `5000` = 100%). Qualquer\n * outra coisa (ausente, `auto`, `larguraUtilTwips` desconhecida) devolve\n * `undefined` e o bloco fica sem `tableWidth` — que é exatamente o default\n * (100%) do modelo, então omitir é seguro.\n */\nfunction readTableWidth(tbl: OoxmlNode, larguraUtilTwips: number | undefined): number | undefined {\n const tblPr = findChild(tbl, \"w:tblPr\");\n const tblW = tblPr ? findChild(tblPr, \"w:tblW\") : undefined;\n if (!tblW) return undefined;\n const medida = leMedida(attr(tblW, \"w:w\"));\n if (!medida) return undefined;\n const type = attr(tblW, \"w:type\");\n\n // O Word aceita tabela mais larga que a página; o editor não. `travaLarguraTabela`\n // é a MESMA faixa que `setTableWidth` usa, importada do core de propósito —\n // duas travas separadas divergiriam, e foi medido o que acontece sem ela:\n // `w:tblW` de 7500 pct entrava como 150%, a tabela era cortada pelo\n // `overflow: hidden` da página e a última coluna sumia da tela E do papel.\n // Um `9639 dxa` entrava como 113% e invadia 80 dos 96px de margem, parando\n // a 17px da borda do papel — dentro da faixa que impressora não imprime.\n if (medida.ehPercentSufixo) return travaLarguraTabela(arredondaPct(medida.valor));\n if (type === \"pct\") return travaLarguraTabela(arredondaPct(medida.valor / 50));\n if (type === \"dxa\" || type === undefined) {\n if (larguraUtilTwips === undefined || larguraUtilTwips <= 0) return undefined;\n return travaLarguraTabela(arredondaPct((medida.valor / larguraUtilTwips) * 100));\n }\n return undefined;\n}\n\nfunction arredondaPct(pct: number): number {\n return Math.round(pct * 100) / 100;\n}\n\n/**\n * `w:trHeight` por linha, convertido de twips para px (o editor guarda\n * altura em px). Devolve `undefined` quando NENHUMA linha declara altura —\n * gravar um array cheio de `undefined`/0 faria uma tabela importada sem\n * altura nascer \"congelada\" no mínimo, quando ela deveria crescer livremente\n * com o conteúdo (mesmo comportamento de hoje, sem `rowHeights`).\n */\nfunction readRowHeights(trs: OoxmlNode[]): number[] | undefined {\n const heights = trs.map((tr) => {\n const trPr = findChild(tr, \"w:trPr\");\n const trHeight = trPr ? findChild(trPr, \"w:trHeight\") : undefined;\n const val = trHeight ? Number(attr(trHeight, \"w:val\") ?? \"\") : NaN;\n return Number.isFinite(val) && val > 0 ? mmToPx(twipToMillimeters(val)) : undefined;\n });\n if (heights.every((h) => h === undefined)) return undefined;\n // Ao menos uma linha declarou altura — as que não declararam ficam no\n // mínimo do modelo (MIN_LINHA_PX), não em 0: é o mesmo \"sem restrição\n // real\" que a linha já tem hoje sem `rowHeights`, só que representável\n // dentro do array sem inventar um valor arbitrário.\n return heights.map((h) => h ?? MIN_LINHA_PX);\n}\n\n/**\n * Reduz `w:tblBorders` ao preset mais próximo.\n *\n * O modelo não tem borda por célula, então `w:tcBorders` continua ignorado —\n * deliberadamente. Combinação não mapeável cai em `all`, que é o padrão visual\n * e o comportamento menos surpreendente para quem importa um documento externo.\n *\n * Retorna `undefined` quando a tabela não declara `tblBorders`, para não gravar\n * a chave à toa.\n */\n/**\n * Cor da grade, lida do PRIMEIRO lado LIGADO do `w:tblBorders`.\n *\n * Lados desligados são ignorados de propósito: o Word emite `w:val=\"none\"` com\n * `w:color=\"auto\"`, que não carrega informação de cor — ler dali gravaria lixo.\n * `auto` também não grava, para o documento cair no default do modelo.\n */\nfunction readBorderColor(tbl: OoxmlNode): string | undefined {\n const tblPr = findChild(tbl, \"w:tblPr\");\n const b = tblPr ? findChild(tblPr, \"w:tblBorders\") : undefined;\n if (!b) return undefined;\n const LADOS = [\n \"w:top\",\n \"w:bottom\",\n \"w:left\",\n \"w:start\",\n \"w:right\",\n \"w:end\",\n \"w:insideH\",\n \"w:insideV\",\n ];\n for (const nome of LADOS) {\n const n = findChild(b, nome);\n if (!n) continue;\n const val = (attr(n, \"w:val\") ?? \"\").toLowerCase();\n if (val === \"\" || val === \"none\" || val === \"nil\") continue;\n const hex = attr(n, \"w:color\");\n if (!hex || hex.toLowerCase() === \"auto\") continue;\n const css = docxHexToCssColor(hex);\n if (css) return css;\n }\n return undefined;\n}\n\nfunction readBorderPreset(tbl: OoxmlNode): TableBorderPreset | undefined {\n const tblPr = findChild(tbl, \"w:tblPr\");\n const b = tblPr ? findChild(tblPr, \"w:tblBorders\") : undefined;\n if (!b) return undefined;\n\n // `borderSideOn` trata os nomes alternativos do OOXML estrito (start/end) e\n // ignora lados declarados como \"none\"/\"nil\".\n const ligado = (...nomes: string[]): boolean => borderSideOn(b, ...nomes);\n\n const top = ligado(\"w:top\");\n const bottom = ligado(\"w:bottom\");\n const left = ligado(\"w:left\", \"w:start\");\n const right = ligado(\"w:right\", \"w:end\");\n const iH = ligado(\"w:insideH\");\n const iV = ligado(\"w:insideV\");\n\n if (top && bottom && left && right && iH && iV) return \"all\";\n if (top && bottom && left && right && !iH && !iV) return \"outer\";\n if (top && bottom && !left && !right && iH && !iV) return \"horizontal\";\n if (!top && !bottom && left && right && !iH && iV) return \"vertical\";\n if (!top && !bottom && !left && !right && !iH && !iV) return \"none\";\n return \"all\";\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\n/**\n * Largura útil da página em twips, direto do `w:sectPr` — `pgSz.w` menos as\n * margens esquerda/direita, tudo em twips, sem passar por px/mm no meio.\n *\n * Usada para reconstruir `tableWidth` (percentual) a partir de `w:tblW`, que\n * também está em twips: dividir twip-contra-twip evita compor DUAS conversões\n * com arredondamento próprio (px→mm→twip na leitura da página E na leitura\n * da tabela) — a mesma fonte de erro documentada acima em `twipsToPx`.\n *\n * `undefined` quando o documento não declara `pgSz` — sem largura de página\n * não há largura útil para calcular `tableWidth` contra, então o import\n * deixa o atributo ausente (default 100) em vez de arriscar uma conta contra\n * um denominador inventado.\n */\nexport function larguraUtilTwipsDe(sectPr: OoxmlNode | undefined): number | undefined {\n if (!sectPr) return undefined;\n const pgSz = findChild(sectPr, \"w:pgSz\");\n if (!pgSz) return undefined;\n const width = parseIntAttr(attr(pgSz, \"w:w\"), 0);\n if (width <= 0) return undefined;\n const pgMar = findChild(sectPr, \"w:pgMar\");\n const left = pgMar ? parseIntAttr(attr(pgMar, \"w:left\"), 0) : 0;\n const right = pgMar ? parseIntAttr(attr(pgMar, \"w:right\"), 0) : 0;\n const util = width - left - right;\n return util > 0 ? util : undefined;\n}\n"],"mappings":"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","names":["import_core","JSZip","attrs","import_core"]}
|
package/dist/index.js
CHANGED
|
@@ -124,6 +124,9 @@ function borderSideOn(parent, ...names) {
|
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
// src/units.ts
|
|
127
|
+
function twipToMillimeters(twip) {
|
|
128
|
+
return twip * 25.4 / 1440;
|
|
129
|
+
}
|
|
127
130
|
function halfPointsToCssPt(halfPoints) {
|
|
128
131
|
if (!Number.isFinite(halfPoints) || halfPoints <= 0) return void 0;
|
|
129
132
|
const pt = halfPoints / 2;
|
|
@@ -483,7 +486,13 @@ function hasCodeBlockShading(pPr) {
|
|
|
483
486
|
}
|
|
484
487
|
|
|
485
488
|
// src/tables.ts
|
|
486
|
-
|
|
489
|
+
import {
|
|
490
|
+
MIN_LINHA_PX,
|
|
491
|
+
mmToPx,
|
|
492
|
+
normalizarLarguras,
|
|
493
|
+
travaLarguraTabela
|
|
494
|
+
} from "@sofereditor/core";
|
|
495
|
+
function tableToBlock(tbl, ctx, larguraUtilTwips) {
|
|
487
496
|
const tblGrid = findChild(tbl, "w:tblGrid");
|
|
488
497
|
const gridCols = tblGrid ? findChildren(tblGrid, "w:gridCol") : [];
|
|
489
498
|
const trs = findChildren(tbl, "w:tr");
|
|
@@ -551,8 +560,50 @@ function tableToBlock(tbl, ctx) {
|
|
|
551
560
|
if (preset) attrs.borderPreset = preset;
|
|
552
561
|
const borderColor = readBorderColor(tbl);
|
|
553
562
|
if (borderColor) attrs.borderColor = borderColor;
|
|
563
|
+
const twips = gridCols.map((g) => Number(attr(g, "w:w") ?? 0));
|
|
564
|
+
attrs.colWidths = normalizarLarguras(twips, cols);
|
|
565
|
+
const rowHeights = readRowHeights(trs);
|
|
566
|
+
if (rowHeights) attrs.rowHeights = rowHeights;
|
|
567
|
+
const tableWidth = readTableWidth(tbl, larguraUtilTwips);
|
|
568
|
+
if (tableWidth !== void 0) attrs.tableWidth = tableWidth;
|
|
554
569
|
return { type: "table", text: "", delta: [], attrs, cells };
|
|
555
570
|
}
|
|
571
|
+
function leMedida(bruto) {
|
|
572
|
+
if (bruto === void 0) return void 0;
|
|
573
|
+
const t = bruto.trim();
|
|
574
|
+
const comSufixo = t.endsWith("%");
|
|
575
|
+
const n = Number(comSufixo ? t.slice(0, -1) : t);
|
|
576
|
+
if (!Number.isFinite(n) || n <= 0) return void 0;
|
|
577
|
+
return { valor: n, ehPercentSufixo: comSufixo };
|
|
578
|
+
}
|
|
579
|
+
function readTableWidth(tbl, larguraUtilTwips) {
|
|
580
|
+
const tblPr = findChild(tbl, "w:tblPr");
|
|
581
|
+
const tblW = tblPr ? findChild(tblPr, "w:tblW") : void 0;
|
|
582
|
+
if (!tblW) return void 0;
|
|
583
|
+
const medida = leMedida(attr(tblW, "w:w"));
|
|
584
|
+
if (!medida) return void 0;
|
|
585
|
+
const type = attr(tblW, "w:type");
|
|
586
|
+
if (medida.ehPercentSufixo) return travaLarguraTabela(arredondaPct(medida.valor));
|
|
587
|
+
if (type === "pct") return travaLarguraTabela(arredondaPct(medida.valor / 50));
|
|
588
|
+
if (type === "dxa" || type === void 0) {
|
|
589
|
+
if (larguraUtilTwips === void 0 || larguraUtilTwips <= 0) return void 0;
|
|
590
|
+
return travaLarguraTabela(arredondaPct(medida.valor / larguraUtilTwips * 100));
|
|
591
|
+
}
|
|
592
|
+
return void 0;
|
|
593
|
+
}
|
|
594
|
+
function arredondaPct(pct) {
|
|
595
|
+
return Math.round(pct * 100) / 100;
|
|
596
|
+
}
|
|
597
|
+
function readRowHeights(trs) {
|
|
598
|
+
const heights = trs.map((tr) => {
|
|
599
|
+
const trPr = findChild(tr, "w:trPr");
|
|
600
|
+
const trHeight = trPr ? findChild(trPr, "w:trHeight") : void 0;
|
|
601
|
+
const val = trHeight ? Number(attr(trHeight, "w:val") ?? "") : NaN;
|
|
602
|
+
return Number.isFinite(val) && val > 0 ? mmToPx(twipToMillimeters(val)) : void 0;
|
|
603
|
+
});
|
|
604
|
+
if (heights.every((h) => h === void 0)) return void 0;
|
|
605
|
+
return heights.map((h) => h ?? MIN_LINHA_PX);
|
|
606
|
+
}
|
|
556
607
|
function readBorderColor(tbl) {
|
|
557
608
|
const tblPr = findChild(tbl, "w:tblPr");
|
|
558
609
|
const b = tblPr ? findChild(tblPr, "w:tblBorders") : void 0;
|
|
@@ -715,10 +766,10 @@ function clampLevel(n) {
|
|
|
715
766
|
}
|
|
716
767
|
|
|
717
768
|
// src/page-settings.ts
|
|
718
|
-
import { detectPreset, mmToPx } from "@sofereditor/core";
|
|
769
|
+
import { detectPreset, mmToPx as mmToPx2 } from "@sofereditor/core";
|
|
719
770
|
var MM_PER_TWIP = 25.4 / 1440;
|
|
720
771
|
function twipsToPx(twips) {
|
|
721
|
-
return
|
|
772
|
+
return mmToPx2(twips * MM_PER_TWIP);
|
|
722
773
|
}
|
|
723
774
|
function sectPrToPageSettings(sectPr) {
|
|
724
775
|
if (!sectPr) return void 0;
|
|
@@ -747,6 +798,18 @@ function sectPrToPageSettings(sectPr) {
|
|
|
747
798
|
settings.preset = detectPreset(settings.width, settings.height);
|
|
748
799
|
return settings;
|
|
749
800
|
}
|
|
801
|
+
function larguraUtilTwipsDe(sectPr) {
|
|
802
|
+
if (!sectPr) return void 0;
|
|
803
|
+
const pgSz = findChild(sectPr, "w:pgSz");
|
|
804
|
+
if (!pgSz) return void 0;
|
|
805
|
+
const width = parseIntAttr(attr(pgSz, "w:w"), 0);
|
|
806
|
+
if (width <= 0) return void 0;
|
|
807
|
+
const pgMar = findChild(sectPr, "w:pgMar");
|
|
808
|
+
const left = pgMar ? parseIntAttr(attr(pgMar, "w:left"), 0) : 0;
|
|
809
|
+
const right = pgMar ? parseIntAttr(attr(pgMar, "w:right"), 0) : 0;
|
|
810
|
+
const util = width - left - right;
|
|
811
|
+
return util > 0 ? util : void 0;
|
|
812
|
+
}
|
|
750
813
|
|
|
751
814
|
// src/docx.ts
|
|
752
815
|
async function docxBlobToDocument(input) {
|
|
@@ -758,20 +821,22 @@ async function docxBlobToDocument(input) {
|
|
|
758
821
|
};
|
|
759
822
|
const body = findBody(file.documentXml);
|
|
760
823
|
if (!body) return { blocks: [{ type: "paragraph", text: "", delta: [], attrs: {} }] };
|
|
824
|
+
const sectPr = findChild(body, "w:sectPr");
|
|
825
|
+
const pageSettings = sectPrToPageSettings(sectPr);
|
|
826
|
+
const larguraUtilTwips = larguraUtilTwipsDe(sectPr);
|
|
761
827
|
const blocks = [];
|
|
762
828
|
for (const child of childrenOf(body)) {
|
|
763
829
|
const tag = tagOf(child);
|
|
764
830
|
if (tag === "w:p") {
|
|
765
831
|
blocks.push(paragraphToBlock(child, ctx, numbering));
|
|
766
832
|
} else if (tag === "w:tbl") {
|
|
767
|
-
blocks.push(tableToBlock(child, ctx));
|
|
833
|
+
blocks.push(tableToBlock(child, ctx, larguraUtilTwips));
|
|
768
834
|
}
|
|
769
835
|
}
|
|
770
836
|
if (blocks.length === 0) {
|
|
771
837
|
blocks.push({ type: "paragraph", text: "", delta: [], attrs: {} });
|
|
772
838
|
}
|
|
773
839
|
pruneNonLeaderListStarts(blocks);
|
|
774
|
-
const pageSettings = sectPrToPageSettings(findChild(body, "w:sectPr"));
|
|
775
840
|
return pageSettings ? { blocks, pageSettings } : { blocks };
|
|
776
841
|
}
|
|
777
842
|
function pruneNonLeaderListStarts(blocks) {
|
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 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/**\n * Returns the children array of an element, or [] when none.\n *\n * Content controls (`w:sdt`) são desembrulhados aqui, no lugar. No OOXML eles\n * são wrappers TRANSPARENTES: o conteúdo real vive em `w:sdtContent` e o\n * `w:sdtPr` carrega só metadados (alias, trava). O Word emite `w:sdt` ao\n * BLOQUEAR um trecho, e ele pode aparecer em qualquer nível — envolvendo uma\n * tabela no body, uma `w:tc` dentro de `w:tr`, um `w:p` dentro de `w:tc`, ou um\n * `w:r` dentro de `w:p`.\n *\n * Desembrulhar aqui, e não em cada chamador, é o que garante que todos esses\n * níveis funcionem: `findChild` e `findChildren` também passam por aqui. Antes\n * disso, cada lista branca de tag ignorava o `w:sdt` e o conteúdo travado sumia\n * silenciosamente.\n */\nexport function childrenOf(node: OoxmlNode): OoxmlNode[] {\n const tag = tagOf(node);\n if (!tag) return [];\n const v = node[tag];\n if (!Array.isArray(v)) return [];\n const kids = v as OoxmlNode[];\n // Caminho rápido: sem content control, devolve o array original sem alocar.\n // `childrenOf` é chamada em todo nó do documento.\n let temSdt = false;\n for (const k of kids) {\n if (tagOf(k) === \"w:sdt\") {\n temSdt = true;\n break;\n }\n }\n if (!temSdt) return kids;\n\n const out: OoxmlNode[] = [];\n for (const k of kids) {\n if (tagOf(k) !== \"w:sdt\") {\n out.push(k);\n continue;\n }\n // Só `w:sdtContent` é conteúdo; `w:sdtPr`/`w:sdtEndPr` são metadados.\n // A recursão trata content controls aninhados.\n const content = childrenOf(k).find((c) => tagOf(c) === \"w:sdtContent\");\n if (content) out.push(...childrenOf(content));\n }\n return out;\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/**\n * Um lado de borda (`w:top`, `w:left`, `w:insideH`, …) está LIGADO?\n *\n * A mera presença do elemento não basta: o Word grava blocos de borda\n * COMPLETOS com todos os lados `w:val=\"none\"` — uma declaração no-op. Ler só a\n * presença fazia parágrafos comuns virarem blockquote (cinza e itálico) só\n * porque traziam um `w:pBdr` vazio de significado.\n *\n * Aceita nomes alternativos porque o OOXML estrito usa `w:start`/`w:end` no\n * lugar de `w:left`/`w:right`.\n */\nexport function borderSideOn(parent: OoxmlNode | undefined, ...names: string[]): boolean {\n if (!parent) return false;\n return names.some((name) => {\n const n = findChild(parent, name);\n if (!n) return false;\n const val = (attr(n, \"w:val\") ?? \"\").toLowerCase();\n return val !== \"\" && val !== \"none\" && val !== \"nil\";\n });\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\n/**\n * Os valores nomeados de `w:highlight` do OOXML. O Word só aceita esta lista\n * fechada — documentos com cor arbitrária usam `w:shd`, que é o que o nosso\n * export emite. `none` fica de fora de propósito: ausência = sem marca.\n */\nconst DOCX_HIGHLIGHT_COLORS: Record<string, string> = {\n yellow: \"#ffff00\",\n green: \"#00ff00\",\n cyan: \"#00ffff\",\n magenta: \"#ff00ff\",\n blue: \"#0000ff\",\n red: \"#ff0000\",\n darkblue: \"#000080\",\n darkcyan: \"#008080\",\n darkgreen: \"#008000\",\n darkmagenta: \"#800080\",\n darkred: \"#800000\",\n darkyellow: \"#808000\",\n darkgray: \"#808080\",\n lightgray: \"#c0c0c0\",\n black: \"#000000\",\n white: \"#ffffff\",\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 case \"w:shd\": {\n // Sombreamento de RUN = marca-texto. `auto` significa \"sem cor\".\n const fill = attr(child, \"w:fill\");\n if (fill && fill.toLowerCase() !== \"auto\") {\n const css = docxHexToCssColor(fill);\n if (css) m.highlight = css;\n }\n break;\n }\n case \"w:highlight\": {\n const css = DOCX_HIGHLIGHT_COLORS[(attr(child, \"w:val\") ?? \"\").toLowerCase()];\n if (css) m.highlight = 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 {\n AlignValue,\n AnswerLineSpacing,\n BlockAttrs,\n BlockType,\n DeltaOp,\n SerializedBlock,\n} from \"@sofereditor/core\";\nimport {\n attr,\n borderSideOn,\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 Object.assign(attrs, readAnswerLine(pPr, text.length > 0));\n return { type: \"paragraph\", text, delta, attrs };\n}\n\n/**\n * Parágrafo SEM texto e com borda INFERIOR = linha de resposta.\n *\n * A exigência de estar vazio é essencial: um parágrafo com texto e régua é um\n * título sublinhado, e convertê-lo em linha de resposta destruiria a semântica\n * do conteúdo. A borda ESQUERDA já é tratada antes como blockquote.\n */\nfunction readAnswerLine(pPr: OoxmlNode | undefined, hasText: boolean): Partial<BlockAttrs> {\n if (!pPr || hasText) return {};\n const pBdr = findChild(pPr, \"w:pBdr\");\n if (!pBdr) return {};\n if (!borderSideOn(pBdr, \"w:bottom\")) return {};\n return { answerLine: true, answerLineSpacing: readAnswerLineSpacing(pPr) };\n}\n\n/** 240 twips = 1 linha. Arredonda para o bucket suportado mais próximo. */\nfunction readAnswerLineSpacing(pPr: OoxmlNode): AnswerLineSpacing {\n const sp = findChild(pPr, \"w:spacing\");\n const line = sp ? Number.parseFloat(attr(sp, \"w:line\") ?? \"\") : NaN;\n if (!Number.isFinite(line)) return 1;\n const buckets: AnswerLineSpacing[] = [1, 1.5, 2];\n let best: AnswerLineSpacing = 1;\n let bestDist = Infinity;\n for (const b of buckets) {\n const d = Math.abs(line - 240 * b);\n if (d < bestDist) {\n bestDist = d;\n best = b;\n }\n }\n return best;\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 // `borderSideOn` (e não a mera presença do elemento): o Word grava pBdr\n // completo com todos os lados \"none\", e ler a presença convertia parágrafo\n // comum em blockquote.\n return borderSideOn(pBdr, \"w:left\", \"w:start\");\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 {\n BlockAttrs,\n CellAttrs,\n DeltaOp,\n SerializedBlock,\n SerializedCell,\n TableBorderPreset,\n} from \"@sofereditor/core\";\nimport {\n attr,\n borderSideOn,\n childrenOf,\n findChild,\n findChildren,\n tagOf,\n type OoxmlNode,\n} from \"./parse-xml\";\nimport { paragraphChildrenToDelta, type RunContext } from \"./runs\";\nimport { docxHexToCssColor, 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 const preset = readBorderPreset(tbl);\n if (preset) attrs.borderPreset = preset;\n const borderColor = readBorderColor(tbl);\n if (borderColor) attrs.borderColor = borderColor;\n return { type: \"table\", text: \"\", delta: [], attrs, cells };\n}\n\n/**\n * Reduz `w:tblBorders` ao preset mais próximo.\n *\n * O modelo não tem borda por célula, então `w:tcBorders` continua ignorado —\n * deliberadamente. Combinação não mapeável cai em `all`, que é o padrão visual\n * e o comportamento menos surpreendente para quem importa um documento externo.\n *\n * Retorna `undefined` quando a tabela não declara `tblBorders`, para não gravar\n * a chave à toa.\n */\n/**\n * Cor da grade, lida do PRIMEIRO lado LIGADO do `w:tblBorders`.\n *\n * Lados desligados são ignorados de propósito: o Word emite `w:val=\"none\"` com\n * `w:color=\"auto\"`, que não carrega informação de cor — ler dali gravaria lixo.\n * `auto` também não grava, para o documento cair no default do modelo.\n */\nfunction readBorderColor(tbl: OoxmlNode): string | undefined {\n const tblPr = findChild(tbl, \"w:tblPr\");\n const b = tblPr ? findChild(tblPr, \"w:tblBorders\") : undefined;\n if (!b) return undefined;\n const LADOS = [\n \"w:top\",\n \"w:bottom\",\n \"w:left\",\n \"w:start\",\n \"w:right\",\n \"w:end\",\n \"w:insideH\",\n \"w:insideV\",\n ];\n for (const nome of LADOS) {\n const n = findChild(b, nome);\n if (!n) continue;\n const val = (attr(n, \"w:val\") ?? \"\").toLowerCase();\n if (val === \"\" || val === \"none\" || val === \"nil\") continue;\n const hex = attr(n, \"w:color\");\n if (!hex || hex.toLowerCase() === \"auto\") continue;\n const css = docxHexToCssColor(hex);\n if (css) return css;\n }\n return undefined;\n}\n\nfunction readBorderPreset(tbl: OoxmlNode): TableBorderPreset | undefined {\n const tblPr = findChild(tbl, \"w:tblPr\");\n const b = tblPr ? findChild(tblPr, \"w:tblBorders\") : undefined;\n if (!b) return undefined;\n\n // `borderSideOn` trata os nomes alternativos do OOXML estrito (start/end) e\n // ignora lados declarados como \"none\"/\"nil\".\n const ligado = (...nomes: string[]): boolean => borderSideOn(b, ...nomes);\n\n const top = ligado(\"w:top\");\n const bottom = ligado(\"w:bottom\");\n const left = ligado(\"w:left\", \"w:start\");\n const right = ligado(\"w:right\", \"w:end\");\n const iH = ligado(\"w:insideH\");\n const iV = ligado(\"w:insideV\");\n\n if (top && bottom && left && right && iH && iV) return \"all\";\n if (top && bottom && left && right && !iH && !iV) return \"outer\";\n if (top && bottom && !left && !right && iH && !iV) return \"horizontal\";\n if (!top && !bottom && left && right && !iH && iV) return \"vertical\";\n if (!top && !bottom && !left && !right && !iH && !iV) return \"none\";\n return \"all\";\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"]}
|
|
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 { larguraUtilTwipsDe, 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 // Lido ANTES do loop de blocos: `tableToBlock` precisa da largura útil da\n // página para reconstruir `tableWidth` a partir de `w:tblW` (twips\n // absolutos só fazem sentido percentualmente contra a largura da página).\n // `w:sectPr` é sempre um único nó ao final do `body`, então lê-lo cedo não\n // muda nada do que já era verdade sobre a ordem do documento.\n const sectPr = findChild(body, \"w:sectPr\");\n const pageSettings = sectPrToPageSettings(sectPr);\n const larguraUtilTwips = larguraUtilTwipsDe(sectPr);\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, larguraUtilTwips));\n }\n // w:sectPr already read above; 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 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/**\n * Returns the children array of an element, or [] when none.\n *\n * Content controls (`w:sdt`) são desembrulhados aqui, no lugar. No OOXML eles\n * são wrappers TRANSPARENTES: o conteúdo real vive em `w:sdtContent` e o\n * `w:sdtPr` carrega só metadados (alias, trava). O Word emite `w:sdt` ao\n * BLOQUEAR um trecho, e ele pode aparecer em qualquer nível — envolvendo uma\n * tabela no body, uma `w:tc` dentro de `w:tr`, um `w:p` dentro de `w:tc`, ou um\n * `w:r` dentro de `w:p`.\n *\n * Desembrulhar aqui, e não em cada chamador, é o que garante que todos esses\n * níveis funcionem: `findChild` e `findChildren` também passam por aqui. Antes\n * disso, cada lista branca de tag ignorava o `w:sdt` e o conteúdo travado sumia\n * silenciosamente.\n */\nexport function childrenOf(node: OoxmlNode): OoxmlNode[] {\n const tag = tagOf(node);\n if (!tag) return [];\n const v = node[tag];\n if (!Array.isArray(v)) return [];\n const kids = v as OoxmlNode[];\n // Caminho rápido: sem content control, devolve o array original sem alocar.\n // `childrenOf` é chamada em todo nó do documento.\n let temSdt = false;\n for (const k of kids) {\n if (tagOf(k) === \"w:sdt\") {\n temSdt = true;\n break;\n }\n }\n if (!temSdt) return kids;\n\n const out: OoxmlNode[] = [];\n for (const k of kids) {\n if (tagOf(k) !== \"w:sdt\") {\n out.push(k);\n continue;\n }\n // Só `w:sdtContent` é conteúdo; `w:sdtPr`/`w:sdtEndPr` são metadados.\n // A recursão trata content controls aninhados.\n const content = childrenOf(k).find((c) => tagOf(c) === \"w:sdtContent\");\n if (content) out.push(...childrenOf(content));\n }\n return out;\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/**\n * Um lado de borda (`w:top`, `w:left`, `w:insideH`, …) está LIGADO?\n *\n * A mera presença do elemento não basta: o Word grava blocos de borda\n * COMPLETOS com todos os lados `w:val=\"none\"` — uma declaração no-op. Ler só a\n * presença fazia parágrafos comuns virarem blockquote (cinza e itálico) só\n * porque traziam um `w:pBdr` vazio de significado.\n *\n * Aceita nomes alternativos porque o OOXML estrito usa `w:start`/`w:end` no\n * lugar de `w:left`/`w:right`.\n */\nexport function borderSideOn(parent: OoxmlNode | undefined, ...names: string[]): boolean {\n if (!parent) return false;\n return names.some((name) => {\n const n = findChild(parent, name);\n if (!n) return false;\n const val = (attr(n, \"w:val\") ?? \"\").toLowerCase();\n return val !== \"\" && val !== \"none\" && val !== \"nil\";\n });\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/**\n * OOXML twip → millimeters. Inverse of `convertMillimetersToTwip` from the\n * `docx` package (used by `@sofereditor/export-docx`), reimplemented here\n * because `import-docx` doesn't depend on `docx` — 1 twip = 1/20 pt =\n * 1/1440 in = 25.4/1440 mm.\n */\nexport function twipToMillimeters(twip: number): number {\n return (twip * 25.4) / 1440;\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\n/**\n * Os valores nomeados de `w:highlight` do OOXML. O Word só aceita esta lista\n * fechada — documentos com cor arbitrária usam `w:shd`, que é o que o nosso\n * export emite. `none` fica de fora de propósito: ausência = sem marca.\n */\nconst DOCX_HIGHLIGHT_COLORS: Record<string, string> = {\n yellow: \"#ffff00\",\n green: \"#00ff00\",\n cyan: \"#00ffff\",\n magenta: \"#ff00ff\",\n blue: \"#0000ff\",\n red: \"#ff0000\",\n darkblue: \"#000080\",\n darkcyan: \"#008080\",\n darkgreen: \"#008000\",\n darkmagenta: \"#800080\",\n darkred: \"#800000\",\n darkyellow: \"#808000\",\n darkgray: \"#808080\",\n lightgray: \"#c0c0c0\",\n black: \"#000000\",\n white: \"#ffffff\",\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 case \"w:shd\": {\n // Sombreamento de RUN = marca-texto. `auto` significa \"sem cor\".\n const fill = attr(child, \"w:fill\");\n if (fill && fill.toLowerCase() !== \"auto\") {\n const css = docxHexToCssColor(fill);\n if (css) m.highlight = css;\n }\n break;\n }\n case \"w:highlight\": {\n const css = DOCX_HIGHLIGHT_COLORS[(attr(child, \"w:val\") ?? \"\").toLowerCase()];\n if (css) m.highlight = 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 {\n AlignValue,\n AnswerLineSpacing,\n BlockAttrs,\n BlockType,\n DeltaOp,\n SerializedBlock,\n} from \"@sofereditor/core\";\nimport {\n attr,\n borderSideOn,\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 Object.assign(attrs, readAnswerLine(pPr, text.length > 0));\n return { type: \"paragraph\", text, delta, attrs };\n}\n\n/**\n * Parágrafo SEM texto e com borda INFERIOR = linha de resposta.\n *\n * A exigência de estar vazio é essencial: um parágrafo com texto e régua é um\n * título sublinhado, e convertê-lo em linha de resposta destruiria a semântica\n * do conteúdo. A borda ESQUERDA já é tratada antes como blockquote.\n */\nfunction readAnswerLine(pPr: OoxmlNode | undefined, hasText: boolean): Partial<BlockAttrs> {\n if (!pPr || hasText) return {};\n const pBdr = findChild(pPr, \"w:pBdr\");\n if (!pBdr) return {};\n if (!borderSideOn(pBdr, \"w:bottom\")) return {};\n return { answerLine: true, answerLineSpacing: readAnswerLineSpacing(pPr) };\n}\n\n/** 240 twips = 1 linha. Arredonda para o bucket suportado mais próximo. */\nfunction readAnswerLineSpacing(pPr: OoxmlNode): AnswerLineSpacing {\n const sp = findChild(pPr, \"w:spacing\");\n const line = sp ? Number.parseFloat(attr(sp, \"w:line\") ?? \"\") : NaN;\n if (!Number.isFinite(line)) return 1;\n const buckets: AnswerLineSpacing[] = [1, 1.5, 2];\n let best: AnswerLineSpacing = 1;\n let bestDist = Infinity;\n for (const b of buckets) {\n const d = Math.abs(line - 240 * b);\n if (d < bestDist) {\n bestDist = d;\n best = b;\n }\n }\n return best;\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 // `borderSideOn` (e não a mera presença do elemento): o Word grava pBdr\n // completo com todos os lados \"none\", e ler a presença convertia parágrafo\n // comum em blockquote.\n return borderSideOn(pBdr, \"w:left\", \"w:start\");\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 {\n BlockAttrs,\n CellAttrs,\n DeltaOp,\n SerializedBlock,\n SerializedCell,\n TableBorderPreset,\n} from \"@sofereditor/core\";\nimport {\n MIN_LINHA_PX,\n mmToPx,\n normalizarLarguras,\n travaLarguraTabela,\n} from \"@sofereditor/core\";\nimport {\n attr,\n borderSideOn,\n childrenOf,\n findChild,\n findChildren,\n tagOf,\n type OoxmlNode,\n} from \"./parse-xml\";\nimport { paragraphChildrenToDelta, type RunContext } from \"./runs\";\nimport { docxHexToCssColor, parseIntAttr, twipToMillimeters } 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 *\n * `larguraUtilTwips` (largura útil da PÁGINA, de `w:sectPr`, lida uma vez em\n * `docxBlobToDocument`) é o que permite reconstruir `tableWidth` a partir de\n * `w:tblW` — sem ela, uma tabela exportada com 50% de largura reimportaria\n * como 100%, porque `normalizarLarguras` só recupera a proporção ENTRE\n * colunas, nunca a largura total da tabela contra a página.\n */\nexport function tableToBlock(\n tbl: OoxmlNode,\n ctx: RunContext,\n larguraUtilTwips?: number,\n): 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 const preset = readBorderPreset(tbl);\n if (preset) attrs.borderPreset = preset;\n const borderColor = readBorderColor(tbl);\n if (borderColor) attrs.borderColor = borderColor;\n // `w:gridCol` chega em twips absolutos; `normalizarLarguras` converte para\n // proporção somando 100 — a mesma conta usada para normalizar documentos\n // antigos em px, então não duplicamos a lógica aqui. Quando faltam gridCols\n // (ou o número não bate com `cols`), o próprio helper cai no split igual, o\n // que é idêntico a omitir o atributo — gravá-lo de qualquer forma é\n // inofensivo.\n const twips = gridCols.map((g) => Number(attr(g, \"w:w\") ?? 0));\n attrs.colWidths = normalizarLarguras(twips, cols);\n const rowHeights = readRowHeights(trs);\n if (rowHeights) attrs.rowHeights = rowHeights;\n const tableWidth = readTableWidth(tbl, larguraUtilTwips);\n if (tableWidth !== undefined) attrs.tableWidth = tableWidth;\n return { type: \"table\", text: \"\", delta: [], attrs, cells };\n}\n\n/**\n * Lê `w:w`, que no OOXML é `ST_MeasurementOrPercent`: pode vir como número\n * puro OU com sufixo `%` (\"50%\"). `Number(\"50%\")` é `NaN`, e sem tratar isso\n * a largura era descartada em silêncio e a tabela voltava com 100%.\n */\nfunction leMedida(bruto: string | undefined): { valor: number; ehPercentSufixo: boolean } | undefined {\n if (bruto === undefined) return undefined;\n const t = bruto.trim();\n const comSufixo = t.endsWith(\"%\");\n const n = Number(comSufixo ? t.slice(0, -1) : t);\n if (!Number.isFinite(n) || n <= 0) return undefined;\n return { valor: n, ehPercentSufixo: comSufixo };\n}\n\n/**\n * `w:tblW` → percentual da largura útil da página (`tableWidth`).\n *\n * Dois tipos possíveis: `dxa` (twips absolutos — divide contra\n * `larguraUtilTwips`, a MESMA conta que `export-docx` fez ao contrário) e\n * `pct` (já percentual, só que em quinquagésimos — `5000` = 100%). Qualquer\n * outra coisa (ausente, `auto`, `larguraUtilTwips` desconhecida) devolve\n * `undefined` e o bloco fica sem `tableWidth` — que é exatamente o default\n * (100%) do modelo, então omitir é seguro.\n */\nfunction readTableWidth(tbl: OoxmlNode, larguraUtilTwips: number | undefined): number | undefined {\n const tblPr = findChild(tbl, \"w:tblPr\");\n const tblW = tblPr ? findChild(tblPr, \"w:tblW\") : undefined;\n if (!tblW) return undefined;\n const medida = leMedida(attr(tblW, \"w:w\"));\n if (!medida) return undefined;\n const type = attr(tblW, \"w:type\");\n\n // O Word aceita tabela mais larga que a página; o editor não. `travaLarguraTabela`\n // é a MESMA faixa que `setTableWidth` usa, importada do core de propósito —\n // duas travas separadas divergiriam, e foi medido o que acontece sem ela:\n // `w:tblW` de 7500 pct entrava como 150%, a tabela era cortada pelo\n // `overflow: hidden` da página e a última coluna sumia da tela E do papel.\n // Um `9639 dxa` entrava como 113% e invadia 80 dos 96px de margem, parando\n // a 17px da borda do papel — dentro da faixa que impressora não imprime.\n if (medida.ehPercentSufixo) return travaLarguraTabela(arredondaPct(medida.valor));\n if (type === \"pct\") return travaLarguraTabela(arredondaPct(medida.valor / 50));\n if (type === \"dxa\" || type === undefined) {\n if (larguraUtilTwips === undefined || larguraUtilTwips <= 0) return undefined;\n return travaLarguraTabela(arredondaPct((medida.valor / larguraUtilTwips) * 100));\n }\n return undefined;\n}\n\nfunction arredondaPct(pct: number): number {\n return Math.round(pct * 100) / 100;\n}\n\n/**\n * `w:trHeight` por linha, convertido de twips para px (o editor guarda\n * altura em px). Devolve `undefined` quando NENHUMA linha declara altura —\n * gravar um array cheio de `undefined`/0 faria uma tabela importada sem\n * altura nascer \"congelada\" no mínimo, quando ela deveria crescer livremente\n * com o conteúdo (mesmo comportamento de hoje, sem `rowHeights`).\n */\nfunction readRowHeights(trs: OoxmlNode[]): number[] | undefined {\n const heights = trs.map((tr) => {\n const trPr = findChild(tr, \"w:trPr\");\n const trHeight = trPr ? findChild(trPr, \"w:trHeight\") : undefined;\n const val = trHeight ? Number(attr(trHeight, \"w:val\") ?? \"\") : NaN;\n return Number.isFinite(val) && val > 0 ? mmToPx(twipToMillimeters(val)) : undefined;\n });\n if (heights.every((h) => h === undefined)) return undefined;\n // Ao menos uma linha declarou altura — as que não declararam ficam no\n // mínimo do modelo (MIN_LINHA_PX), não em 0: é o mesmo \"sem restrição\n // real\" que a linha já tem hoje sem `rowHeights`, só que representável\n // dentro do array sem inventar um valor arbitrário.\n return heights.map((h) => h ?? MIN_LINHA_PX);\n}\n\n/**\n * Reduz `w:tblBorders` ao preset mais próximo.\n *\n * O modelo não tem borda por célula, então `w:tcBorders` continua ignorado —\n * deliberadamente. Combinação não mapeável cai em `all`, que é o padrão visual\n * e o comportamento menos surpreendente para quem importa um documento externo.\n *\n * Retorna `undefined` quando a tabela não declara `tblBorders`, para não gravar\n * a chave à toa.\n */\n/**\n * Cor da grade, lida do PRIMEIRO lado LIGADO do `w:tblBorders`.\n *\n * Lados desligados são ignorados de propósito: o Word emite `w:val=\"none\"` com\n * `w:color=\"auto\"`, que não carrega informação de cor — ler dali gravaria lixo.\n * `auto` também não grava, para o documento cair no default do modelo.\n */\nfunction readBorderColor(tbl: OoxmlNode): string | undefined {\n const tblPr = findChild(tbl, \"w:tblPr\");\n const b = tblPr ? findChild(tblPr, \"w:tblBorders\") : undefined;\n if (!b) return undefined;\n const LADOS = [\n \"w:top\",\n \"w:bottom\",\n \"w:left\",\n \"w:start\",\n \"w:right\",\n \"w:end\",\n \"w:insideH\",\n \"w:insideV\",\n ];\n for (const nome of LADOS) {\n const n = findChild(b, nome);\n if (!n) continue;\n const val = (attr(n, \"w:val\") ?? \"\").toLowerCase();\n if (val === \"\" || val === \"none\" || val === \"nil\") continue;\n const hex = attr(n, \"w:color\");\n if (!hex || hex.toLowerCase() === \"auto\") continue;\n const css = docxHexToCssColor(hex);\n if (css) return css;\n }\n return undefined;\n}\n\nfunction readBorderPreset(tbl: OoxmlNode): TableBorderPreset | undefined {\n const tblPr = findChild(tbl, \"w:tblPr\");\n const b = tblPr ? findChild(tblPr, \"w:tblBorders\") : undefined;\n if (!b) return undefined;\n\n // `borderSideOn` trata os nomes alternativos do OOXML estrito (start/end) e\n // ignora lados declarados como \"none\"/\"nil\".\n const ligado = (...nomes: string[]): boolean => borderSideOn(b, ...nomes);\n\n const top = ligado(\"w:top\");\n const bottom = ligado(\"w:bottom\");\n const left = ligado(\"w:left\", \"w:start\");\n const right = ligado(\"w:right\", \"w:end\");\n const iH = ligado(\"w:insideH\");\n const iV = ligado(\"w:insideV\");\n\n if (top && bottom && left && right && iH && iV) return \"all\";\n if (top && bottom && left && right && !iH && !iV) return \"outer\";\n if (top && bottom && !left && !right && iH && !iV) return \"horizontal\";\n if (!top && !bottom && left && right && !iH && iV) return \"vertical\";\n if (!top && !bottom && !left && !right && !iH && !iV) return \"none\";\n return \"all\";\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\n/**\n * Largura útil da página em twips, direto do `w:sectPr` — `pgSz.w` menos as\n * margens esquerda/direita, tudo em twips, sem passar por px/mm no meio.\n *\n * Usada para reconstruir `tableWidth` (percentual) a partir de `w:tblW`, que\n * também está em twips: dividir twip-contra-twip evita compor DUAS conversões\n * com arredondamento próprio (px→mm→twip na leitura da página E na leitura\n * da tabela) — a mesma fonte de erro documentada acima em `twipsToPx`.\n *\n * `undefined` quando o documento não declara `pgSz` — sem largura de página\n * não há largura útil para calcular `tableWidth` contra, então o import\n * deixa o atributo ausente (default 100) em vez de arriscar uma conta contra\n * um denominador inventado.\n */\nexport function larguraUtilTwipsDe(sectPr: OoxmlNode | undefined): number | undefined {\n if (!sectPr) return undefined;\n const pgSz = findChild(sectPr, \"w:pgSz\");\n if (!pgSz) return undefined;\n const width = parseIntAttr(attr(pgSz, \"w:w\"), 0);\n if (width <= 0) return undefined;\n const pgMar = findChild(sectPr, \"w:pgMar\");\n const left = pgMar ? parseIntAttr(attr(pgMar, \"w:left\"), 0) : 0;\n const right = pgMar ? parseIntAttr(attr(pgMar, \"w:right\"), 0) : 0;\n const util = width - left - right;\n return util > 0 ? util : undefined;\n}\n"],"mappings":"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","names":["attrs","mmToPx","mmToPx"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sofereditor/import-docx",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
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",
|
|
@@ -54,12 +54,12 @@
|
|
|
54
54
|
"test": "vitest run"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@sofereditor/core": "^0.
|
|
57
|
+
"@sofereditor/core": "^0.9.0",
|
|
58
58
|
"fast-xml-parser": "^4.5.0",
|
|
59
59
|
"jszip": "^3.10.1"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"@sofereditor/export-docx": "^0.
|
|
62
|
+
"@sofereditor/export-docx": "^0.9.0",
|
|
63
63
|
"tsup": "^8.3.5",
|
|
64
64
|
"typescript": "^5.7.2",
|
|
65
65
|
"vitest": "^2.1.8"
|