@pixerate/editor 0.47.0 → 0.49.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/agent/index.cjs +248 -29
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +18 -6
- package/dist/agent/index.d.ts +18 -6
- package/dist/agent/index.js +228 -9
- package/dist/agent/index.js.map +1 -1
- package/dist/{builtins-xs7rK6ys.d.cts → builtins-1kqwLUnb.d.cts} +1 -1
- package/dist/{builtins-D2nMtw2W.d.ts → builtins-BKYlHH1s.d.ts} +1 -1
- package/dist/chart/index.cjs +216 -3541
- package/dist/chart/index.cjs.map +1 -1
- package/dist/chart/index.d.cts +4 -494
- package/dist/chart/index.d.ts +4 -494
- package/dist/chart/index.js +155 -3480
- package/dist/chart/index.js.map +1 -1
- package/dist/{chunk-5VXI5GED.js → chunk-2CJ3LPYQ.js} +3 -3
- package/dist/{chunk-TXXNBDQX.cjs → chunk-2Q46FKZK.cjs} +113 -34
- package/dist/chunk-2Q46FKZK.cjs.map +1 -0
- package/dist/chunk-3JNRQVTS.cjs +521 -0
- package/dist/chunk-3JNRQVTS.cjs.map +1 -0
- package/dist/chunk-5TWIN7ZJ.js +113 -0
- package/dist/chunk-5TWIN7ZJ.js.map +1 -0
- package/dist/{chunk-PQFAHT5O.js → chunk-DQPBQXKG.js} +27 -94
- package/dist/chunk-DQPBQXKG.js.map +1 -0
- package/dist/{chunk-ZFBBVGCI.js → chunk-EKYHKQPG.js} +243 -243
- package/dist/{chunk-ZFBBVGCI.js.map → chunk-EKYHKQPG.js.map} +1 -1
- package/dist/{chunk-J3R2OWOE.cjs → chunk-FEMIVHN3.cjs} +610 -15
- package/dist/chunk-FEMIVHN3.cjs.map +1 -0
- package/dist/{chunk-C3NWJE3K.js → chunk-GJBIVWB2.js} +11 -672
- package/dist/chunk-GJBIVWB2.js.map +1 -0
- package/dist/chunk-GTZXF4BI.cjs +3424 -0
- package/dist/chunk-GTZXF4BI.cjs.map +1 -0
- package/dist/chunk-JOX6MJW4.cjs +674 -0
- package/dist/chunk-JOX6MJW4.cjs.map +1 -0
- package/dist/{chunk-REAGGLXS.js → chunk-JQ3BB3E6.js} +2 -2
- package/dist/{chunk-H4PICYNL.cjs → chunk-LNKZPIQD.cjs} +113 -180
- package/dist/chunk-LNKZPIQD.cjs.map +1 -0
- package/dist/chunk-OV7UAKIY.js +674 -0
- package/dist/chunk-OV7UAKIY.js.map +1 -0
- package/dist/{chunk-TK2XZK6Z.js → chunk-QFTVLEVN.js} +596 -1
- package/dist/chunk-QFTVLEVN.js.map +1 -0
- package/dist/{chunk-KRGXUQ2Y.js → chunk-T6XU4B54.js} +82 -3
- package/dist/chunk-T6XU4B54.js.map +1 -0
- package/dist/chunk-TGBCBQFV.cjs +113 -0
- package/dist/chunk-TGBCBQFV.cjs.map +1 -0
- package/dist/{chunk-SQC26VQV.cjs → chunk-UN33YOXW.cjs} +191 -191
- package/dist/{chunk-SQC26VQV.cjs.map → chunk-UN33YOXW.cjs.map} +1 -1
- package/dist/chunk-WBOAXDKD.js +3424 -0
- package/dist/chunk-WBOAXDKD.js.map +1 -0
- package/dist/{chunk-LYGEEDNR.cjs → chunk-XP5IUZUO.cjs} +242 -242
- package/dist/chunk-XP5IUZUO.cjs.map +1 -0
- package/dist/{chunk-BBRK6MOI.cjs → chunk-YU4WQE5M.cjs} +100 -100
- package/dist/{chunk-BBRK6MOI.cjs.map → chunk-YU4WQE5M.cjs.map} +1 -1
- package/dist/commands/index.d.cts +1 -1
- package/dist/commands/index.d.ts +1 -1
- package/dist/controller-ChjCCMLl.d.cts +822 -0
- package/dist/controller-DtbEo3om.d.ts +822 -0
- package/dist/export/index.cjs +4 -2
- package/dist/export/index.cjs.map +1 -1
- package/dist/export/index.d.cts +5 -1
- package/dist/export/index.d.ts +5 -1
- package/dist/export/index.js +3 -1
- package/dist/extensions/index.cjs +33 -4
- package/dist/extensions/index.cjs.map +1 -1
- package/dist/extensions/index.d.cts +4 -2
- package/dist/extensions/index.d.ts +4 -2
- package/dist/extensions/index.js +32 -3
- package/dist/{index-QrqMmZ75.d.cts → index-DoHqT1mq.d.cts} +203 -7
- package/dist/{index-CSUCQYAH.d.ts → index-YLZ0fKqE.d.ts} +203 -7
- package/dist/index.cjs +39 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -7
- package/dist/index.d.ts +9 -7
- package/dist/index.js +33 -7
- package/dist/index.js.map +1 -1
- package/dist/spreadsheet/index.cjs +4 -4
- package/dist/spreadsheet/index.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-C3NWJE3K.js.map +0 -1
- package/dist/chunk-H4PICYNL.cjs.map +0 -1
- package/dist/chunk-J3R2OWOE.cjs.map +0 -1
- package/dist/chunk-KRGXUQ2Y.js.map +0 -1
- package/dist/chunk-LYGEEDNR.cjs.map +0 -1
- package/dist/chunk-NEOO6QJD.cjs +0 -1182
- package/dist/chunk-NEOO6QJD.cjs.map +0 -1
- package/dist/chunk-PQFAHT5O.js.map +0 -1
- package/dist/chunk-TK2XZK6Z.js.map +0 -1
- package/dist/chunk-TXXNBDQX.cjs.map +0 -1
- package/dist/types-BVqWm3d1.d.cts +0 -320
- package/dist/types-BVqWm3d1.d.ts +0 -320
- /package/dist/{chunk-5VXI5GED.js.map → chunk-2CJ3LPYQ.js.map} +0 -0
- /package/dist/{chunk-REAGGLXS.js.map → chunk-JQ3BB3E6.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/extensions/table/nesting.ts","../src/extensions/find-replace/pattern.ts","../src/extensions/find-replace/search.ts","../src/extensions/table/extension.ts","../src/extensions/table/actions.ts"],"sourcesContent":["import { Fragment, Slice, type Node as ProsemirrorNode, type ResolvedPos } from \"@tiptap/pm/model\";\nimport { Plugin, PluginKey, Selection, type Transaction } from \"@tiptap/pm/state\";\nimport type { EditorView } from \"@tiptap/pm/view\";\nimport {\n CellSelection,\n __pastedCells,\n handlePaste as handleTablePaste,\n} from \"@tiptap/pm/tables\";\n\n/**\n * Set this meta on a transaction to let it create tables inside table cells\n * (the nesting guard leaves it alone), e.g. when loading legacy content\n * through a transaction that does not replace the whole document.\n */\nexport const ALLOW_NESTED_TABLES_META = \"allowNestedTables\";\n\nexport const tableNestingPluginKey = new PluginKey(\"tableNesting\");\n\nconst roleOf = (node: ProsemirrorNode) => node.type.spec.tableRole as string | undefined;\nconst isTableNode = (node: ProsemirrorNode) => roleOf(node) === \"table\";\n\n/** Depth of the outermost table around `$pos`, or `-1` outside tables. */\nexport function outermostTableDepth($pos: ResolvedPos): number {\n for (let d = 1; d <= $pos.depth; d++) if (isTableNode($pos.node(d))) return d;\n return -1;\n}\n\n/** Whether `$pos` lies inside a table cell or header cell. */\nexport function isInTableCell($pos: ResolvedPos): boolean {\n for (let d = $pos.depth; d > 0; d--) {\n const role = roleOf($pos.node(d));\n if (role === \"cell\" || role === \"header_cell\") return true;\n }\n return false;\n}\n\n/** Whether a slice or fragment contains a table node at any depth. */\nexport function sliceContainsTable(content: Slice | Fragment): boolean {\n const fragment = content instanceof Slice ? content.content : content;\n let found = false;\n fragment.descendants((node) => {\n if (found) return false;\n if (isTableNode(node)) found = true;\n return !found;\n });\n return found;\n}\n\n/**\n * Inserts `slice` right after the outermost table around `from` instead of\n * inside the cell, deleting `from`–`to` first when both lie in that table.\n * Returns the position right after the inserted content, or `null` (and\n * leaves `tr` unchanged) when `from` is not in a table.\n */\nexport function insertSliceAfterTable(tr: Transaction, from: number, to: number, slice: Slice): number | null {\n const $from = tr.doc.resolve(from);\n const depth = outermostTableDepth($from);\n if (depth < 0) return null;\n const tableStart = $from.before(depth);\n const tableEnd = $from.after(depth);\n if (to > from && to < tableEnd) {\n if (tr.selection instanceof CellSelection && tr.selection.from === from && tr.selection.to === to) {\n tr.deleteSelection();\n } else {\n tr.delete(from, to);\n }\n }\n const table = tr.doc.nodeAt(tableStart);\n if (!table) return null;\n const after = tableStart + table.nodeSize;\n const before = tr.doc.content.size;\n // A closed slice: the content becomes blocks of its own after the table\n // instead of merging into whatever follows it.\n tr.replace(after, after, new Slice(slice.content, 0, 0));\n return after + (tr.doc.content.size - before);\n}\n\n/**\n * Paste handling for slices that contain a table while the selection is in a\n * table: a cell selection or a pasted table (rows, cells) fills the cells from\n * the cursor (prosemirror-tables), and anything else that contains a table is\n * inserted after the outermost table, with the cursor at its end. Returns\n * `false` when the paste needs no special handling.\n */\nexport function handleTablePasteWithoutNesting(view: EditorView, event: ClipboardEvent | null, slice: Slice): boolean {\n const { state } = view;\n const { selection } = state;\n if (outermostTableDepth(selection.$from) < 0) return false;\n if (selection instanceof CellSelection || __pastedCells(slice)) {\n if (handleTablePaste(view, event as ClipboardEvent, slice)) return true;\n }\n if (!sliceContainsTable(slice)) return false;\n const tr = state.tr;\n const end = insertSliceAfterTable(tr, selection.from, selection.to, slice);\n if (end === null) return false;\n tr.setSelection(Selection.near(tr.doc.resolve(end), -1));\n view.dispatch(tr.scrollIntoView().setMeta(\"paste\", true).setMeta(\"uiEvent\", \"paste\"));\n return true;\n}\n\n/**\n * Ranges of the final document that `transactions` changed, leaving out the\n * changes of skipped transactions (their steps still map the other ranges).\n */\nfunction changedRanges(transactions: readonly Transaction[], skip: (tr: Transaction) => boolean): [number, number][] {\n let ranges: [number, number][] = [];\n for (const tr of transactions) {\n const skipped = skip(tr);\n for (const step of tr.steps) {\n const map = step.getMap();\n // Content that later (skipped) steps insert at a range's edge is not\n // part of it; pure deletions leave nothing to check.\n ranges = ranges\n .map(([from, to]): [number, number] => [map.map(from, 1), map.map(to, -1)])\n .filter(([from, to]) => to > from);\n if (skipped) continue;\n map.forEach((_oldStart, _oldEnd, newStart, newEnd) => {\n if (newEnd > newStart) ranges.push([newStart, newEnd]);\n });\n }\n }\n return ranges;\n}\n\n/** Tables starting inside `ranges` that sit in a table cell. */\nfunction findNestedTables(doc: ProsemirrorNode, ranges: [number, number][]): number[] {\n const found = new Set<number>();\n for (const [from, to] of ranges) {\n doc.nodesBetween(from, to, (node, pos) => {\n if (!isTableNode(node) || pos < from) return true;\n if (isInTableCell(doc.resolve(pos))) {\n found.add(pos);\n return false;\n }\n return true;\n });\n }\n // A table inside another found table moves with it.\n const sorted = [...found].sort((a, b) => a - b);\n const outer: number[] = [];\n for (const pos of sorted) {\n const last = outer[outer.length - 1];\n if (last === undefined || pos >= last + doc.nodeAt(last)!.nodeSize) outer.push(pos);\n }\n return outer;\n}\n\n/**\n * Moves tables that sit in table cells (at positions in `ranges`) to right\n * after their outermost table, keeping their content, and repeats for tables\n * nested in the moved ones. A cell left without content gets an empty\n * paragraph. Returns whether `tr` changed.\n */\nexport function unnestTables(tr: Transaction, ranges: [number, number][]): boolean {\n let changed = false;\n for (let round = 0; round < 32 && ranges.length; round++) {\n const nested = findNestedTables(tr.doc, ranges);\n if (!nested.length) break;\n // Group by outermost table; handle later tables first so earlier\n // positions stay valid.\n const groups = new Map<number, number[]>();\n for (const pos of nested) {\n const $pos = tr.doc.resolve(pos);\n const outer = $pos.before(outermostTableDepth($pos));\n groups.set(outer, [...(groups.get(outer) ?? []), pos]);\n }\n const next: [number, number][] = [];\n for (const outer of [...groups.keys()].sort((a, b) => b - a)) {\n const positions = groups.get(outer)!;\n const nodes = positions.map((pos) => tr.doc.nodeAt(pos)!);\n for (let i = positions.length - 1; i >= 0; i--) {\n const pos = positions[i];\n const node = nodes[i];\n const $pos = tr.doc.resolve(pos);\n const parent = $pos.parent;\n const filler = parent.childCount === 1 ? parent.type.contentMatch.defaultType?.createAndFill() : null;\n if (filler) tr.replaceWith(pos, pos + node.nodeSize, filler);\n else tr.delete(pos, pos + node.nodeSize);\n }\n const table = tr.doc.nodeAt(outer)!;\n const after = outer + table.nodeSize;\n const fragment = Fragment.fromArray(nodes);\n tr.insert(after, fragment);\n // Later groups are before this one, so this range stays valid.\n next.push([after, after + fragment.size]);\n changed = true;\n }\n ranges = next;\n }\n return changed;\n}\n\n/**\n * Whether a transaction replaces the whole document (`setContent`, loading):\n * existing documents keep their nested tables.\n */\nfunction replacesDocument(tr: Transaction): boolean {\n return tr.steps.some((step, i) => {\n const { from, to } = step as unknown as { from?: number; to?: number };\n return from === 0 && to !== undefined && to >= tr.docs[i].content.size;\n });\n}\n\nconst skip = (tr: Transaction) =>\n !tr.docChanged ||\n tr.getMeta(ALLOW_NESTED_TABLES_META) === true ||\n // Undo/redo and remote collaborative changes restore what was there.\n !!tr.getMeta(\"history$\") ||\n !!tr.getMeta(\"y-sync$\") ||\n // Other plugins' housekeeping, e.g. Track Changes putting a deleted\n // (nested) table back so the deletion can be reviewed.\n !!tr.getMeta(\"appendedTransaction\") ||\n replacesDocument(tr);\n\n/**\n * Keeps tables out of table cells: paste handling (see\n * `handleTablePasteWithoutNesting`) plus a guard that moves any table a\n * local edit puts into a cell (`insertContent`, `insertTable`, drops) to\n * right after the outermost table. Documents that already contain nested\n * tables (initial content, `setContent`, undo/redo, collaboration, Track\n * Changes restoring a deleted table) are left as they are.\n */\nexport function createTableNestingPlugin(): Plugin {\n return new Plugin({\n key: tableNestingPluginKey,\n props: {\n handlePaste: (view, event, slice) => handleTablePasteWithoutNesting(view, event, slice),\n },\n appendTransaction(transactions, _oldState, newState) {\n if (transactions.every(skip)) return null;\n const ranges = changedRanges(transactions, skip);\n if (!ranges.length) return null;\n const tr = newState.tr;\n if (!unnestTables(tr, ranges)) return null;\n return tr;\n },\n });\n}\n","// Portions ported from wordcraft/crates/engine/src/cmd/find_pattern.rs and crates/engine/src/cmd/edit.rs (MIT OR Apache-2.0, © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.\n/**\n * Word's Find and Replace patterns: special characters (`^p`, `^t`, `^#` …),\n * the \"Use wildcards\" language (`?`, `*`, `[a-z]`, `[!x]`, `{n,m}`, `@`, `<`,\n * `>`, `( )`) and a raw regular-expression mode.\n *\n * Special and wildcard patterns are compiled to a small program run by a\n * Pike VM, which takes time linear in the text for a given pattern, so no\n * Find text can backtrack catastrophically (JavaScript's `RegExp` would). The\n * raw regex mode uses the native `RegExp` engine; it rejects nested\n * repetition and is bounded by the search budget between matches only.\n *\n * Pure TypeScript: no ProseMirror or DOM.\n */\n\n/** A paragraph mark in the searched text (`^p`). */\nexport const FIND_PARAGRAPH_MARK = \"\\r\";\n/** Longest Find what text, in characters. */\nexport const MAX_FIND_PATTERN_LENGTH = 1024;\n/** Largest count in `{n,m}`. */\nconst MAX_COUNT = 1000;\n/** Largest compiled program (instructions). Larger patterns are `too_complex`. */\nconst MAX_PROGRAM_SIZE = 20_000;\n\nexport interface FindOptions {\n matchCase?: boolean;\n /** Find whole words only (ignored with wildcards, like Word). */\n wholeWord?: boolean;\n /** The match must start a word. */\n matchPrefix?: boolean;\n /** The match must end a word. */\n matchSuffix?: boolean;\n /** Skip punctuation between the characters of the Find text. */\n ignorePunctuation?: boolean;\n /** Skip spaces and tabs between the characters of the Find text. */\n ignoreWhitespace?: boolean;\n /** Word's \"Use wildcards\". Always matches case. */\n wildcards?: boolean;\n /** A JavaScript regular expression (wins over `wildcards`). Replace text is literal. */\n regex?: boolean;\n /** Read the Find and Replace text literally: no `^` codes. */\n literal?: boolean;\n}\n\nexport type FindPatternErrorCode = \"too_long\" | \"invalid_pattern\" | \"too_complex\";\n\n/** Why a Find text cannot be used. Commands report it; they never throw it. */\nexport interface FindPatternError {\n code: FindPatternErrorCode;\n message: string;\n}\n\n/** One match in a searched string (UTF-16 offsets). */\nexport interface PatternMatch {\n start: number;\n end: number;\n /** Text of each group; index 0 is the whole match, unmatched groups are `undefined`. */\n groups: (string | undefined)[];\n}\n\n/** Shared limit on the work one search may do. */\nexport interface SearchBudget {\n /** `performance.now()`/`Date.now()` value after which the search stops. */\n deadline: number;\n /** VM steps left. */\n steps: number;\n /** Set once the budget ran out. */\n exhausted: boolean;\n}\n\nexport interface SearchBudgetOptions {\n /** Wall-clock limit in milliseconds (default 250). */\n timeLimitMs?: number;\n /** Pike VM thread steps (default 50 million). */\n maxSteps?: number;\n}\n\nconst now = (): number =>\n typeof performance !== \"undefined\" && typeof performance.now === \"function\"\n ? performance.now()\n : Date.now();\n\nexport function createSearchBudget(options: SearchBudgetOptions = {}): SearchBudget {\n return {\n deadline: now() + (options.timeLimitMs ?? 250),\n steps: options.maxSteps ?? 50_000_000,\n exhausted: false,\n };\n}\n\nexport interface CompiledFindPattern {\n mode: \"special\" | \"wildcards\" | \"regex\";\n /** The pattern can match a paragraph mark, so paragraphs must be read together. */\n spansParagraphs: boolean;\n caseInsensitive: boolean;\n /** Number of capture groups (not counting the whole match). */\n groupCount: number;\n /**\n * The leftmost match in `hay[start, end)`; text outside the range is\n * context for word assertions. `\"budget\"` when the budget ran out.\n */\n exec(hay: string, start: number, end: number, budget: SearchBudget): PatternMatch | null | \"budget\";\n}\n\nexport type CompileFindPatternResult =\n | { ok: true; pattern: CompiledFindPattern }\n | { ok: false; error: FindPatternError };\n\n// ---------------------------------------------------------------------------\n// Character tests\n// ---------------------------------------------------------------------------\n\n/** Tests a code point (and its case fold when matching ignores case). */\ntype CharTest = (cp: number, folded: number) => boolean;\n\nconst PARA = 13; // \"\\r\"\nconst ANY: CharTest = (cp) => cp !== PARA;\n\nconst LETTER = /\\p{L}/u;\nconst PUNCT = /\\p{P}/u;\nconst WORD = /[\\p{L}\\p{M}\\p{Nd}\\p{Pc}]/u;\n\nconst foldCache = new Map<number, number>();\n/** Simple (one code point to one code point) lower-case fold. */\nexport function foldCodePoint(cp: number): number {\n if (cp < 128) return cp >= 65 && cp <= 90 ? cp + 32 : cp;\n const cached = foldCache.get(cp);\n if (cached !== undefined) return cached;\n const lower = String.fromCodePoint(cp).toLowerCase();\n const folded = [...lower].length === 1 ? lower.codePointAt(0)! : cp;\n if (foldCache.size < 4096) foldCache.set(cp, folded);\n return folded;\n}\n\nfunction isWordChar(cp: number): boolean {\n if (cp < 0) return false;\n if (cp < 128) {\n return (cp >= 48 && cp <= 57) || (cp >= 65 && cp <= 90) || (cp >= 97 && cp <= 122) || cp === 95;\n }\n return WORD.test(String.fromCodePoint(cp));\n}\n\nconst isLetter = (cp: number) =>\n cp < 128 ? (cp >= 65 && cp <= 90) || (cp >= 97 && cp <= 122) : LETTER.test(String.fromCodePoint(cp));\n\nfunction isPunct(cp: number): boolean {\n if (cp < 128) {\n return (cp >= 33 && cp <= 47) || (cp >= 58 && cp <= 64) || (cp >= 91 && cp <= 96) || (cp >= 123 && cp <= 126);\n }\n return (cp >= 0x2010 && cp <= 0x2027) || cp === 0xa1 || cp === 0xbf || cp === 0xab || cp === 0xbb || PUNCT.test(String.fromCodePoint(cp));\n}\n\nconst isSpace = (cp: number) => cp === 32 || cp === 9 || cp === 0xa0;\n\n/** Code point before `pos` in `hay` (-1 at the start). */\nfunction cpBefore(hay: string, pos: number): number {\n if (pos <= 0) return -1;\n const low = hay.charCodeAt(pos - 1);\n if (low >= 0xdc00 && low <= 0xdfff && pos >= 2) {\n const high = hay.charCodeAt(pos - 2);\n if (high >= 0xd800 && high <= 0xdbff) return hay.codePointAt(pos - 2)!;\n }\n return low;\n}\n\nconst cpAt = (hay: string, pos: number): number => (pos < hay.length ? hay.codePointAt(pos)! : -1);\n\n// ---------------------------------------------------------------------------\n// Pattern AST\n// ---------------------------------------------------------------------------\n\ntype AssertKind = \"boundary\" | \"wordStart\" | \"wordEnd\";\n\ntype Node =\n | { k: \"char\"; test: CharTest }\n | { k: \"cat\"; items: Node[] }\n | { k: \"group\"; index: number; body: Node }\n | { k: \"rep\"; body: Node; min: number; max: number; lazy: boolean } // max -1 = unbounded\n | { k: \"assert\"; kind: AssertKind };\n\nclass PatternError extends Error {\n constructor(\n readonly code: FindPatternErrorCode,\n message: string,\n ) {\n super(message);\n }\n}\n\nconst charNode = (test: CharTest): Node => ({ k: \"char\", test });\nconst exact = (cp: number): Node => charNode((c) => c === cp);\nconst literalNode = (cp: number, caseInsensitive: boolean): Node => {\n if (!caseInsensitive) return exact(cp);\n const f = foldCodePoint(cp);\n return charNode((_c, folded) => folded === f);\n};\nconst star = (body: Node, lazy: boolean): Node => ({ k: \"rep\", body, min: 0, max: -1, lazy });\n\n/** What a `^` code stands for in Find what. */\nfunction findCode(c: string): Node | null {\n switch (c) {\n case \"p\": return exact(PARA);\n case \"t\": return exact(9);\n case \"?\": return charNode(ANY);\n case \"#\": return charNode((cp) => cp >= 48 && cp <= 57);\n case \"$\": return charNode((cp) => isLetter(cp));\n case \"^\": return exact(94);\n case \"l\": return exact(10);\n case \"m\": return exact(0x0c);\n case \"n\": return exact(0x0e);\n case \"+\": return exact(0x2014);\n case \"=\": return exact(0x2013);\n case \"s\": return exact(0xa0);\n case \"~\": return exact(0x2011);\n case \"-\": return exact(0xad);\n case \"w\": return { k: \"rep\", body: charNode((cp) => isSpace(cp)), min: 1, max: -1, lazy: false };\n case \"g\": return exact(0xfffc);\n case \"%\": return exact(0xa7);\n case \"v\": return exact(0xb6);\n default: return null;\n }\n}\n\n/** What a `^` code stands for in Replace with. */\nfunction replaceCode(c: string): string | null {\n switch (c) {\n case \"p\": return FIND_PARAGRAPH_MARK;\n case \"t\": return \"\\t\";\n case \"^\": return \"^\";\n case \"l\": return \"\\n\";\n case \"m\": return \"\\u000c\";\n case \"n\": return \"\\u000e\";\n case \"+\": return \"\\u2014\";\n case \"=\": return \"\\u2013\";\n case \"s\": return \"\\u00a0\";\n case \"~\": return \"\\u2011\";\n case \"-\": return \"\\u00ad\";\n case \"%\": return \"\\u00a7\";\n case \"v\": return \"\\u00b6\";\n default: return null;\n }\n}\n\n/** A character code (`^13`, `^0151`, `^u8212`) as the character it stands for. */\nfunction codeChar(n: number): number | null {\n switch (n) {\n case 13: return PARA;\n case 11: return 10;\n case 12: return 0x0c;\n case 14: return 0x0e;\n case 30: return 0x2011;\n case 31: return 0xad;\n }\n if (n > 0x10ffff || (n >= 0xd800 && n <= 0xdfff)) return null;\n // Control characters other than tab stand for nothing here.\n if ((n < 32 && n !== 9) || (n >= 0x7f && n < 0xa0)) return null;\n return n;\n}\n\n/** A numeric code after `^` starting at `chars[i]`: the code point and characters used. */\nfunction numericCode(chars: string[], i: number): { cp: number; used: number } | null {\n const unicode = chars[i] === \"u\";\n const start = unicode ? i + 1 : i;\n const max = unicode ? 5 : 4;\n let digits = \"\";\n for (let j = start; j < chars.length && digits.length < max && /[0-9]/.test(chars[j]); j++) digits += chars[j];\n if (!digits) return null;\n const cp = codeChar(parseInt(digits, 10));\n return cp === null ? null : { cp, used: start - i + digits.length };\n}\n\nconst toChars = (s: string): string[] => Array.from(s);\nconst cpOf = (ch: string): number => ch.codePointAt(0)!;\n\n/** Normal search: literal text with `^` codes, optionally skipping punctuation and white space. */\nfunction parseSpecial(query: string, o: FindOptions, caseInsensitive: boolean): { node: Node; spans: boolean } {\n const chars = toChars(query);\n const atoms: Node[] = [];\n let spans = false;\n let i = 0;\n while (i < chars.length) {\n const c = chars[i++];\n if (c === \"^\" && !o.literal && i < chars.length) {\n const n = chars[i];\n const code = findCode(n);\n if (code) {\n if (n === \"p\") spans = true;\n atoms.push(code);\n i++;\n continue;\n }\n const num = numericCode(chars, i);\n if (num) {\n if (num.cp === PARA) spans = true;\n atoms.push(literalNode(num.cp, caseInsensitive));\n i += num.used;\n continue;\n }\n // Not a code: the caret itself.\n }\n const cp = cpOf(c);\n if ((o.ignorePunctuation && isPunct(cp)) || (o.ignoreWhitespace && isSpace(cp))) continue;\n atoms.push(literalNode(cp, caseInsensitive));\n }\n const filler: CharTest | null =\n o.ignorePunctuation && o.ignoreWhitespace\n ? (cp) => isPunct(cp) || isSpace(cp)\n : o.ignorePunctuation\n ? (cp) => isPunct(cp)\n : o.ignoreWhitespace\n ? (cp) => isSpace(cp)\n : null;\n const items: Node[] = [];\n atoms.forEach((atom, index) => {\n if (index > 0 && filler) items.push(star(charNode(filler), false));\n items.push(atom);\n });\n return { node: { k: \"cat\", items }, spans };\n}\n\n/** `{n}`, `{n,}`, `{n,m}` (and `{,m}`). */\nfunction parseCount(body: string): { min: number; max: number } {\n const bad = () => new PatternError(\"invalid_pattern\", `{${body}} is not a valid count`);\n const num = (s: string): number | null => {\n const t = s.trim();\n if (!t) return null;\n if (!/^[0-9]+$/.test(t)) throw bad();\n const n = parseInt(t, 10);\n if (n > MAX_COUNT) throw new PatternError(\"invalid_pattern\", `counts go up to ${MAX_COUNT}`);\n return n;\n };\n const sep = body.search(/[,;]/);\n if (sep < 0) {\n const n = num(body);\n if (n === null) throw bad();\n return { min: n, max: n };\n }\n const a = num(body.slice(0, sep)) ?? 0;\n const b = num(body.slice(sep + 1));\n if (b !== null && b < a) throw bad();\n return { min: a, max: b ?? -1 };\n}\n\n/** `[abc]`, `[a-z]`, `[!x]`: the characters inside are literal. */\nfunction parseClass(inner: string[]): CharTest {\n let negated = false;\n if (inner[0] === \"!\") {\n negated = true;\n inner = inner.slice(1);\n }\n if (inner.length === 0) throw new PatternError(\"invalid_pattern\", \"[ ] needs at least one character\");\n const singles = new Set<number>();\n const ranges: [number, number][] = [];\n let i = 0;\n while (i < inner.length) {\n let c = inner[i];\n if (c === \"\\\\\" && i + 1 < inner.length) c = inner[++i];\n i++;\n if (inner[i] === \"-\" && i + 1 < inner.length) {\n const hi = inner[i + 1];\n if (cpOf(hi) < cpOf(c)) throw new PatternError(\"invalid_pattern\", `[${c}-${hi}] is not in ascending order`);\n ranges.push([cpOf(c), cpOf(hi)]);\n i += 2;\n } else {\n singles.add(cpOf(c));\n }\n }\n const inSet = (cp: number) => singles.has(cp) || ranges.some(([lo, hi]) => cp >= lo && cp <= hi);\n return negated ? (cp) => cp !== PARA && !inSet(cp) : (cp) => inSet(cp);\n}\n\n/** \"Use wildcards\" search. */\nfunction parseWildcards(query: string): { node: Node; spans: boolean; groups: number } {\n const chars = toChars(query);\n const stack: { items: Node[]; group: number }[] = [{ items: [], group: 0 }];\n let groups = 0;\n let spans = false;\n const top = () => stack[stack.length - 1].items;\n const quantify = (min: number, max: number, what: string) => {\n const items = top();\n const last = items[items.length - 1];\n if (!last || last.k === \"assert\" || last.k === \"rep\") {\n throw new PatternError(\"invalid_pattern\", `${what} needs something to repeat before it`);\n }\n items[items.length - 1] = { k: \"rep\", body: last, min, max, lazy: false };\n };\n let i = 0;\n while (i < chars.length) {\n const c = chars[i++];\n switch (c) {\n case \"?\":\n top().push(charNode(ANY));\n break;\n case \"*\":\n top().push(star(charNode(ANY), true));\n break;\n case \"@\":\n quantify(1, -1, \"@\");\n break;\n case \"<\":\n top().push({ k: \"assert\", kind: \"wordStart\" });\n break;\n case \">\":\n top().push({ k: \"assert\", kind: \"wordEnd\" });\n break;\n case \"(\":\n stack.push({ items: [], group: ++groups });\n break;\n case \")\": {\n if (stack.length === 1) throw new PatternError(\"invalid_pattern\", \"a ) has no opening (\");\n const frame = stack.pop()!;\n top().push({ k: \"group\", index: frame.group, body: { k: \"cat\", items: frame.items } });\n break;\n }\n case \"{\": {\n const end = chars.indexOf(\"}\", i);\n if (end < 0) throw new PatternError(\"invalid_pattern\", \"a { needs a closing }\");\n const { min, max } = parseCount(chars.slice(i, end).join(\"\"));\n quantify(min, max, `{${chars.slice(i, end).join(\"\")}}`);\n i = end + 1;\n break;\n }\n case \"[\": {\n const end = chars.indexOf(\"]\", i);\n if (end < 0) throw new PatternError(\"invalid_pattern\", \"a [ needs a closing ]\");\n top().push(charNode(parseClass(chars.slice(i, end))));\n i = end + 1;\n break;\n }\n case \"\\\\\": {\n if (i >= chars.length) {\n top().push(exact(92));\n } else if (/[0-9]/.test(chars[i])) {\n throw new PatternError(\"invalid_pattern\", \"back-references (\\\\1) work in Replace with, not in Find what\");\n } else {\n top().push(exact(cpOf(chars[i++])));\n }\n break;\n }\n case \"^\": {\n if (i >= chars.length) {\n top().push(exact(94));\n break;\n }\n const n = chars[i];\n const code = findCode(n);\n if (code) {\n if (n === \"p\") spans = true;\n top().push(code);\n i++;\n break;\n }\n const num = numericCode(chars, i);\n if (num) {\n if (num.cp === PARA) spans = true;\n top().push(exact(num.cp));\n i += num.used;\n } else {\n top().push(exact(94));\n }\n break;\n }\n default:\n top().push(exact(cpOf(c)));\n }\n }\n if (stack.length > 1) throw new PatternError(\"invalid_pattern\", \"a ( needs a closing )\");\n return { node: { k: \"cat\", items: stack[0].items }, spans, groups };\n}\n\n// ---------------------------------------------------------------------------\n// Program and Pike VM\n// ---------------------------------------------------------------------------\n\nenum Op {\n Char,\n Split,\n Jmp,\n Save,\n Assert,\n Match,\n}\n\ntype Inst =\n | { op: Op.Char; test: CharTest }\n | { op: Op.Split; x: number; y: number }\n | { op: Op.Jmp; x: number }\n | { op: Op.Save; n: number }\n | { op: Op.Assert; kind: AssertKind }\n | { op: Op.Match };\n\nfunction compileProgram(node: Node): Inst[] {\n const prog: Inst[] = [];\n const push = (inst: Inst): number => {\n if (prog.length >= MAX_PROGRAM_SIZE) {\n throw new PatternError(\"too_complex\", \"the pattern is too complex (too many repeats)\");\n }\n prog.push(inst);\n return prog.length - 1;\n };\n const emit = (n: Node): void => {\n switch (n.k) {\n case \"char\":\n push({ op: Op.Char, test: n.test });\n return;\n case \"cat\":\n n.items.forEach(emit);\n return;\n case \"group\":\n push({ op: Op.Save, n: 2 * n.index });\n emit(n.body);\n push({ op: Op.Save, n: 2 * n.index + 1 });\n return;\n case \"assert\":\n push({ op: Op.Assert, kind: n.kind });\n return;\n case \"rep\": {\n for (let k = 0; k < n.min; k++) emit(n.body);\n if (n.max < 0) {\n const split = push({ op: Op.Split, x: 0, y: 0 });\n emit(n.body);\n push({ op: Op.Jmp, x: split });\n const exit = prog.length;\n const inst = prog[split] as { op: Op.Split; x: number; y: number };\n inst.x = n.lazy ? exit : split + 1;\n inst.y = n.lazy ? split + 1 : exit;\n return;\n }\n const splits: number[] = [];\n for (let k = n.min; k < n.max; k++) {\n splits.push(push({ op: Op.Split, x: 0, y: 0 }));\n emit(n.body);\n }\n const exit = prog.length;\n for (const s of splits) {\n const inst = prog[s] as { op: Op.Split; x: number; y: number };\n inst.x = n.lazy ? exit : s + 1;\n inst.y = n.lazy ? s + 1 : exit;\n }\n return;\n }\n }\n };\n push({ op: Op.Save, n: 0 });\n emit(node);\n push({ op: Op.Save, n: 1 });\n push({ op: Op.Match });\n return prog;\n}\n\nfunction checkAssert(kind: AssertKind, hay: string, pos: number): boolean {\n const before = isWordChar(cpBefore(hay, pos));\n const after = isWordChar(cpAt(hay, pos));\n switch (kind) {\n case \"boundary\": return before !== after;\n case \"wordStart\": return !before && after;\n case \"wordEnd\": return before && !after;\n }\n}\n\n/**\n * Leftmost-first search (Perl/Rust priorities: greedy, lazy) with a Pike VM:\n * every position is visited once per live instruction, so time is\n * O(text × program) whatever the pattern.\n */\nfunction pikeExec(\n prog: Inst[],\n groupCount: number,\n caseInsensitive: boolean,\n hay: string,\n start: number,\n end: number,\n budget: SearchBudget,\n): PatternMatch | null | \"budget\" {\n const ncap = 2 * (groupCount + 1);\n const mark = new Int32Array(prog.length);\n let gen = 1;\n let clistPc: number[] = [];\n let clistCaps: Int32Array[] = [];\n let nlistPc: number[] = [];\n let nlistCaps: Int32Array[] = [];\n const stackPc: number[] = [];\n const stackCaps: Int32Array[] = [];\n let matched: Int32Array | null = null;\n const initial = new Int32Array(ncap).fill(-1);\n\n const add = (listPc: number[], listCaps: Int32Array[], pc0: number, caps0: Int32Array, pos: number) => {\n stackPc.push(pc0);\n stackCaps.push(caps0);\n while (stackPc.length) {\n const pc = stackPc.pop()!;\n const caps = stackCaps.pop()!;\n if (mark[pc] === gen) continue;\n mark[pc] = gen;\n const inst = prog[pc];\n switch (inst.op) {\n case Op.Jmp:\n stackPc.push(inst.x);\n stackCaps.push(caps);\n break;\n case Op.Split:\n stackPc.push(inst.y, inst.x);\n stackCaps.push(caps, caps);\n break;\n case Op.Save: {\n const next = caps.slice();\n next[inst.n] = pos;\n stackPc.push(pc + 1);\n stackCaps.push(next);\n break;\n }\n case Op.Assert:\n if (checkAssert(inst.kind, hay, pos)) {\n stackPc.push(pc + 1);\n stackCaps.push(caps);\n }\n break;\n default:\n listPc.push(pc);\n listCaps.push(caps);\n }\n }\n };\n\n let i = start;\n if (budget.steps <= 0 || now() > budget.deadline) {\n budget.exhausted = true;\n return \"budget\";\n }\n let steps = 0;\n for (;;) {\n if (!matched) add(clistPc, clistCaps, 0, initial, i);\n const cp = i < end ? hay.codePointAt(i)! : -1;\n const width = cp > 0xffff ? 2 : 1;\n if (clistPc.length === 0) {\n // Nothing alive here (e.g. an assertion failed at the start): move on.\n if (matched || i >= end) break;\n gen++;\n i += width;\n continue;\n }\n const folded = cp >= 0 && caseInsensitive ? foldCodePoint(cp) : cp;\n gen++;\n nlistPc = [];\n nlistCaps = [];\n for (let t = 0; t < clistPc.length; t++) {\n if (++steps >= 4096) {\n budget.steps -= steps;\n steps = 0;\n if (budget.steps <= 0 || now() > budget.deadline) {\n budget.exhausted = true;\n return \"budget\";\n }\n }\n const inst = prog[clistPc[t]];\n if (inst.op === Op.Char) {\n if (cp >= 0 && inst.test(cp, folded)) add(nlistPc, nlistCaps, clistPc[t] + 1, clistCaps[t], i + width);\n } else if (inst.op === Op.Match) {\n matched = clistCaps[t];\n // Lower-priority threads lose to this match.\n break;\n }\n }\n clistPc = nlistPc;\n clistCaps = nlistCaps;\n if (i >= end) break;\n i += width;\n }\n budget.steps -= steps;\n if (!matched) return null;\n const groups: (string | undefined)[] = [];\n for (let g = 0; g <= groupCount; g++) {\n const a = matched[2 * g];\n const b = matched[2 * g + 1];\n groups.push(a >= 0 && b >= 0 ? hay.slice(a, b) : undefined);\n }\n return { start: matched[0], end: matched[1], groups };\n}\n\n// ---------------------------------------------------------------------------\n// Raw regex mode\n// ---------------------------------------------------------------------------\n\nconst WORD_CLASS = \"[\\\\p{L}\\\\p{M}\\\\p{Nd}\\\\p{Pc}]\";\nconst REGEX_BOUNDARY = `(?:(?<=${WORD_CLASS})(?!${WORD_CLASS})|(?<!${WORD_CLASS})(?=${WORD_CLASS}))`;\n\n/**\n * Rejects a repeated group that itself contains a repeat (`(a+)+`, `(\\w*)*`),\n * the shape behind most catastrophic backtracking in `RegExp`.\n */\nfunction hasNestedRepeat(source: string): boolean {\n /** The quantifier at `i`: whether it repeats at all, and whether more than once. */\n const quantifierAt = (i: number): { repeats: boolean; many: boolean } => {\n const c = source[i];\n if (c === \"*\" || c === \"+\") return { repeats: true, many: true };\n if (c === \"{\") {\n const m = /^\\{(\\d*)(,?)(\\d*)\\}/.exec(source.slice(i));\n if (m) {\n const max = m[2] ? (m[3] ? Number(m[3]) : Infinity) : Number(m[1]);\n return { repeats: max > 1, many: max > 1 };\n }\n }\n return { repeats: false, many: false };\n };\n // For each open group: whether it contains a repeat.\n const stack: boolean[] = [];\n let inClass = false;\n for (let i = 0; i < source.length; i++) {\n const c = source[i];\n if (c === \"\\\\\") {\n i++;\n continue;\n }\n if (inClass) {\n if (c === \"]\") inClass = false;\n continue;\n }\n if (c === \"[\") {\n inClass = true;\n } else if (c === \"(\") {\n stack.push(false);\n } else if (c === \")\") {\n const inner = stack.pop() ?? false;\n const q = quantifierAt(i + 1);\n if (inner && q.many) return true;\n if (stack.length && (inner || q.repeats)) stack[stack.length - 1] = true;\n } else if (stack.length && quantifierAt(i).repeats) {\n stack[stack.length - 1] = true;\n }\n }\n return false;\n}\n\nfunction compileRegex(query: string, o: FindOptions): CompiledFindPattern {\n if (hasNestedRepeat(query)) {\n throw new PatternError(\n \"too_complex\",\n \"a repeated group containing a repeat, like (a+)+, can take exponential time; rewrite it without nesting\",\n );\n }\n let source = query;\n if (o.wholeWord || (o.matchPrefix && o.matchSuffix)) source = `${REGEX_BOUNDARY}(?:${query})${REGEX_BOUNDARY}`;\n else if (o.matchPrefix) source = `${REGEX_BOUNDARY}(?:${query})`;\n else if (o.matchSuffix) source = `(?:${query})${REGEX_BOUNDARY}`;\n let re: RegExp;\n try {\n re = new RegExp(source, o.matchCase ? \"gu\" : \"giu\");\n } catch (error) {\n throw new PatternError(\"invalid_pattern\", `bad pattern: ${error instanceof Error ? error.message : String(error)}`);\n }\n let slicedFor: { hay: string; end: number; text: string } | null = null;\n return {\n mode: \"regex\",\n spansParagraphs: false,\n caseInsensitive: !o.matchCase,\n groupCount: 0,\n exec(hay, start, end, budget) {\n if (now() > budget.deadline) {\n budget.exhausted = true;\n return \"budget\";\n }\n let text = hay;\n if (end < hay.length) {\n if (!slicedFor || slicedFor.hay !== hay || slicedFor.end !== end) {\n slicedFor = { hay, end, text: hay.slice(0, end) };\n }\n text = slicedFor.text;\n }\n re.lastIndex = start;\n const m = re.exec(text);\n if (!m) return null;\n return { start: m.index, end: m.index + m[0].length, groups: Array.from(m) };\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/** Translates Word's Find what text. Never throws: invalid text returns `{ ok: false, error }`. */\nexport function compileFindPattern(query: string, options: FindOptions = {}): CompileFindPatternResult {\n try {\n if (Array.from(query).length > MAX_FIND_PATTERN_LENGTH) {\n throw new PatternError(\"too_long\", `the Find what text is longer than ${MAX_FIND_PATTERN_LENGTH} characters`);\n }\n if (options.regex) return { ok: true, pattern: compileRegex(query, options) };\n\n const wildcards = !!options.wildcards && !options.literal;\n // Word's wildcard search always matches case.\n const caseInsensitive = !options.matchCase && !wildcards;\n let node: Node;\n let spans: boolean;\n let groups = 0;\n if (wildcards) {\n ({ node, spans, groups } = parseWildcards(query));\n } else {\n ({ node, spans } = parseSpecial(query, options, caseInsensitive));\n const before = options.wholeWord || options.matchPrefix;\n const after = options.wholeWord || options.matchSuffix;\n if (before || after) {\n const items: Node[] = [];\n if (before) items.push({ k: \"assert\", kind: \"boundary\" });\n items.push(node);\n if (after) items.push({ k: \"assert\", kind: \"boundary\" });\n node = { k: \"cat\", items };\n }\n }\n const prog = compileProgram(node);\n return {\n ok: true,\n pattern: {\n mode: wildcards ? \"wildcards\" : \"special\",\n spansParagraphs: spans,\n caseInsensitive,\n groupCount: groups,\n exec: (hay, start, end, budget) => pikeExec(prog, groups, caseInsensitive, hay, start, end, budget),\n },\n };\n } catch (error) {\n if (error instanceof PatternError) return { ok: false, error: { code: error.code, message: error.message } };\n return { ok: false, error: { code: \"invalid_pattern\", message: error instanceof Error ? error.message : String(error) } };\n }\n}\n\nexport interface FindAllOptions {\n /**\n * Offsets where the live text breaks (e.g. where tracked-deleted text was\n * skipped): no match spans a cut.\n */\n cuts?: readonly number[];\n budget?: SearchBudget;\n /** Stop after this many matches (default 10 000). */\n maxMatches?: number;\n}\n\nexport interface FindAllResult {\n matches: PatternMatch[];\n /** The search stopped early (match cap or time budget). */\n truncated: boolean;\n}\n\n/**\n * Every non-empty match in `hay`, left to right, without overlaps. Empty\n * matches are stepped past so the search always moves on.\n */\nexport function findAllMatches(\n pattern: CompiledFindPattern,\n hay: string,\n options: FindAllOptions = {},\n): FindAllResult {\n const budget = options.budget ?? createSearchBudget();\n const maxMatches = options.maxMatches ?? 10_000;\n const cuts = [...(options.cuts ?? []), hay.length].sort((a, b) => a - b);\n const matches: PatternMatch[] = [];\n let from = 0;\n for (const cut of cuts) {\n if (cut <= from) continue;\n let pos = from;\n from = cut;\n for (;;) {\n const m = pattern.exec(hay, pos, cut, budget);\n if (m === \"budget\") return { matches, truncated: true };\n if (!m) break;\n const empty = m.end === m.start;\n const next = empty ? m.end + (cpAt(hay, m.end) > 0xffff ? 2 : 1) : m.end;\n if (next > cut) break;\n pos = next;\n if (empty) continue;\n matches.push(m);\n if (matches.length >= maxMatches) return { matches, truncated: true };\n }\n }\n return { matches, truncated: false };\n}\n\n/** A piece of Replace with text. */\nexport type ReplacePiece =\n | { type: \"text\"; text: string }\n /** `^&`: the text found. */\n | { type: \"found\" }\n /** `\\n` with wildcards: group `n`. */\n | { type: \"group\"; index: number }\n /** `^c`: the clipboard. */\n | { type: \"clipboard\" };\n\n/** Reads Replace with text: `^` codes (unless `literal`), and `\\1`–`\\9` with wildcards. Regex mode is literal. */\nexport function parseReplacement(replacement: string, options: FindOptions = {}): ReplacePiece[] {\n if (options.literal || options.regex) return replacement ? [{ type: \"text\", text: replacement }] : [];\n const chars = toChars(replacement);\n const out: ReplacePiece[] = [];\n let cur = \"\";\n const flush = () => {\n if (cur) out.push({ type: \"text\", text: cur });\n cur = \"\";\n };\n let i = 0;\n while (i < chars.length) {\n const c = chars[i++];\n if (c === \"\\\\\" && options.wildcards && i < chars.length) {\n const d = chars[i];\n if (/[1-9]/.test(d)) {\n flush();\n out.push({ type: \"group\", index: Number(d) });\n } else {\n cur += d;\n }\n i++;\n continue;\n }\n if (c === \"^\" && i < chars.length) {\n const n = chars[i];\n if (n === \"&\" || n === \"c\") {\n flush();\n out.push(n === \"&\" ? { type: \"found\" } : { type: \"clipboard\" });\n i++;\n continue;\n }\n const code = replaceCode(n);\n if (code !== null) {\n cur += code;\n i++;\n continue;\n }\n const num = numericCode(chars, i);\n if (num) {\n cur += String.fromCodePoint(num.cp);\n i += num.used;\n continue;\n }\n }\n cur += c;\n }\n flush();\n return out;\n}\n\n/** Fills in Replace with text for one match. Paragraph marks in the result are `\\r`. */\nexport function expandReplacement(pieces: readonly ReplacePiece[], match: PatternMatch, clipboardText = \"\"): string {\n let out = \"\";\n for (const piece of pieces) {\n switch (piece.type) {\n case \"text\":\n out += piece.text;\n break;\n case \"found\":\n out += match.groups[0] ?? \"\";\n break;\n case \"group\":\n out += match.groups[piece.index] ?? \"\";\n break;\n case \"clipboard\":\n out += clipboardText.replace(/\\r\\n/g, \"\\r\").replace(/\\n/g, \"\\r\");\n break;\n }\n }\n return out;\n}\n","// Portions ported from wordcraft/crates/engine/src/cmd/edit.rs (MIT OR Apache-2.0, © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.\nimport type { Mark as ProsemirrorMark, Node as ProsemirrorNode, Schema } from \"@tiptap/pm/model\";\nimport type { Transaction } from \"@tiptap/pm/state\";\nimport {\n FIND_PARAGRAPH_MARK,\n compileFindPattern,\n createSearchBudget,\n expandReplacement,\n findAllMatches,\n parseReplacement,\n type FindOptions,\n type FindPatternError,\n} from \"./pattern\";\n\n/** Name of the tracked-deletion mark (see `track-changes.ts`); deleted text is not searched. */\nconst DELETION_MARK = \"deletion\";\n/** Review marks the replacement text does not inherit from the found text. */\nconst DROPPED_REPLACEMENT_MARKS = new Set([DELETION_MARK, \"formatChange\"]);\n/** Stands for an inline node other than text or a hard break (`^g`). */\nconst OBJECT_CHAR = \"\\ufffc\";\n\nexport interface FindMatch {\n /** Document position of the first matched character. */\n from: number;\n /** Document position after the last matched character. */\n to: number;\n /** The matched text (`\\r` for paragraph marks, `\\n` for hard breaks). */\n text: string;\n /** The Replace with text for this match (`\\r` splits paragraphs). */\n replacement: string;\n}\n\nexport interface DocumentSearchOptions {\n /** Replace with text (`^&`, `^c`, `\\1`…). */\n replacement?: string;\n /** Text of `^c` in the replacement. */\n clipboardText?: string;\n /** Wall-clock budget for the whole search (default 250 ms). */\n timeLimitMs?: number;\n /** Match cap (default 10 000). */\n maxMatches?: number;\n}\n\nexport interface DocumentSearchResult {\n matches: FindMatch[];\n /** The search stopped early at the match cap or time budget. */\n truncated: boolean;\n error: FindPatternError | null;\n}\n\ninterface Block {\n node: ProsemirrorNode;\n pos: number;\n parent: ProsemirrorNode | null;\n index: number;\n}\n\n/**\n * Finds `query` in a document. Each textblock is read as text without\n * tracked-deleted runs (a deletion \"cuts\" the text, so no match spans it, but\n * word boundaries see the live text on both sides); a pattern that can match\n * `^p` reads runs of sibling textblocks as one text with `\\r` between them.\n */\nexport function searchDocument(\n doc: ProsemirrorNode,\n query: string,\n options: FindOptions = {},\n searchOptions: DocumentSearchOptions = {},\n): DocumentSearchResult {\n if (!query) return { matches: [], truncated: false, error: null };\n const compiled = compileFindPattern(query, options);\n if (!compiled.ok) return { matches: [], truncated: false, error: compiled.error };\n const pattern = compiled.pattern;\n const pieces = parseReplacement(searchOptions.replacement ?? \"\", options);\n const budget = createSearchBudget({ timeLimitMs: searchOptions.timeLimitMs });\n const maxMatches = searchOptions.maxMatches ?? 10_000;\n\n const blocks: Block[] = [];\n doc.descendants((node, pos, parent, index) => {\n if (!node.isTextblock) return true;\n blocks.push({ node, pos, parent, index });\n return false;\n });\n\n // Textblocks read as one text: consecutive siblings when the pattern spans paragraphs.\n const chunks: Block[][] = [];\n blocks.forEach((block, i) => {\n const prev = blocks[i - 1];\n const joins =\n pattern.spansParagraphs && prev && prev.parent === block.parent && prev.index + 1 === block.index;\n if (joins) chunks[chunks.length - 1].push(block);\n else chunks.push([block]);\n });\n\n const matches: FindMatch[] = [];\n let truncated = false;\n for (const chunk of chunks) {\n let hay = \"\";\n // Document position of each hay offset, and the position after it.\n const posOf: number[] = [];\n const endOf: number[] = [];\n const cuts: number[] = [];\n chunk.forEach((block, k) => {\n const contentStart = block.pos + 1;\n block.node.forEach((child, offset) => {\n const at = contentStart + offset;\n if (child.marks.some((m) => m.type.name === DELETION_MARK)) {\n if (cuts[cuts.length - 1] !== hay.length) cuts.push(hay.length);\n return;\n }\n if (child.isText) {\n const text = child.text ?? \"\";\n for (let j = 0; j < text.length; j++) {\n posOf.push(at + j);\n endOf.push(at + j + 1);\n }\n hay += text;\n } else {\n posOf.push(at);\n endOf.push(at + child.nodeSize);\n hay += child.type.name === \"hardBreak\" ? \"\\n\" : OBJECT_CHAR;\n }\n });\n const next = chunk[k + 1];\n if (next) {\n posOf.push(contentStart + block.node.content.size);\n endOf.push(next.pos + 1);\n hay += FIND_PARAGRAPH_MARK;\n }\n });\n if (!hay) continue;\n const result = findAllMatches(pattern, hay, {\n cuts,\n budget,\n maxMatches: maxMatches - matches.length,\n });\n for (const m of result.matches) {\n matches.push({\n from: posOf[m.start],\n to: endOf[m.end - 1],\n text: m.groups[0] ?? hay.slice(m.start, m.end),\n replacement: expandReplacement(pieces, m, searchOptions.clipboardText ?? \"\"),\n });\n }\n if (result.truncated) {\n truncated = true;\n break;\n }\n }\n return { matches, truncated, error: null };\n}\n\n/** Marks the replacement for a match inherits: the found text's, minus tracked-change marks. */\nfunction replacementMarks(doc: ProsemirrorNode, from: number, to: number): readonly ProsemirrorMark[] {\n const $from = doc.resolve(from);\n const node = from < to ? $from.nodeAfter : null;\n const marks = node ? node.marks : $from.marks();\n return marks.filter((m) => !DROPPED_REPLACEMENT_MARKS.has(m.type.name));\n}\n\n/** Inline content for a piece of replacement text: `\\n` becomes a hard break when the schema has one. */\nfunction inlineContent(schema: Schema, text: string, marks: readonly ProsemirrorMark[]): ProsemirrorNode[] {\n const nodes: ProsemirrorNode[] = [];\n const hardBreak = schema.nodes.hardBreak;\n const parts = hardBreak ? text.split(\"\\n\") : [text];\n parts.forEach((part, i) => {\n if (i > 0) nodes.push(hardBreak.create(null, null, marks));\n if (part) nodes.push(schema.text(part, marks));\n });\n return nodes;\n}\n\n/**\n * Replaces matches in one transaction, last first so earlier positions stay\n * valid. A paragraph mark (`\\r` or U+2029) in a replacement splits the\n * paragraph. Returns the mapped end of each replacement (in match order).\n */\nexport function applyReplacements(tr: Transaction, matches: readonly FindMatch[]): number[] {\n const ends: number[] = new Array(matches.length);\n const schema = tr.doc.type.schema;\n for (let i = matches.length - 1; i >= 0; i--) {\n const { from, to, replacement } = matches[i];\n const marks = replacementMarks(tr.doc, from, to);\n const parts = replacement.split(/[\\r\\u2029]/);\n const stepsBefore = tr.steps.length;\n const first = inlineContent(schema, parts[0], marks);\n if (first.length) tr.replaceWith(from, to, first);\n else if (to > from) tr.delete(from, to);\n let pos = tr.mapping.slice(stepsBefore).map(to, 1);\n for (let k = 1; k < parts.length; k++) {\n tr.split(pos);\n pos += 2;\n const content = inlineContent(schema, parts[k], marks);\n if (content.length) {\n tr.insert(pos, content);\n pos += content.reduce((size, node) => size + node.nodeSize, 0);\n }\n }\n // Positions of later replacements were already mapped; record this one's end\n // and shift the later ends by what this replacement changed.\n const map = tr.mapping.slice(stepsBefore);\n for (let j = i + 1; j < matches.length; j++) ends[j] = map.map(ends[j], 1);\n ends[i] = pos;\n }\n return ends;\n}\n","import { getHTMLFromFragment, type Extensions } from \"@tiptap/core\";\nimport { Fragment, type Node as ProsemirrorNode } from \"@tiptap/pm/model\";\nimport * as _Table from \"@tiptap/extension-table\";\nimport * as _TableRow from \"@tiptap/extension-table-row\";\nimport * as _TableHeader from \"@tiptap/extension-table-header\";\nimport * as _TableCell from \"@tiptap/extension-table-cell\";\nimport { createTableNestingPlugin } from \"./nesting\";\n\nconst resolveExt = (mod: any, name: string) =>\n mod?.[name] || mod?.default?.[name] || mod?.default?.default || mod?.default || mod;\n\nconst BaseTable = resolveExt(_Table, \"Table\");\nconst BaseTableRow = resolveExt(_TableRow, \"TableRow\");\nconst BaseTableHeader = resolveExt(_TableHeader, \"TableHeader\");\nconst BaseTableCell = resolveExt(_TableCell, \"TableCell\");\n\n/** Horizontal alignment of a table cell (`align` attribute). */\nexport type TableCellAlignment = \"left\" | \"center\" | \"right\" | \"justify\";\n\nconst ALIGNMENTS = new Set<TableCellAlignment>([\"left\", \"center\", \"right\", \"justify\"]);\n\n/** Returns a valid cell alignment, or `null`. */\nexport function normalizeTableCellAlignment(value: unknown): TableCellAlignment | null {\n const v = typeof value === \"string\" ? value.trim().toLowerCase() : \"\";\n return ALIGNMENTS.has(v as TableCellAlignment) ? (v as TableCellAlignment) : null;\n}\n\n/**\n * Color values allowed as a cell background: hex, `rgb()/rgba()/hsl()/hsla()`\n * with numeric arguments, or a CSS color keyword. Anything else (e.g.\n * `url(...)`, `expression(...)`, `;`) is rejected because the value ends up in\n * a `style` attribute.\n */\nconst COLOR_REGEX =\n /^(?:#[0-9a-f]{3,8}|(?:rgb|rgba|hsl|hsla)\\(\\s*[-0-9.%\\s,/deg]+\\)|[a-z]{3,20})$/i;\n\n/** Returns a safe CSS color for a cell background, or `null`. */\nexport function normalizeTableCellColor(value: unknown): string | null {\n const v = typeof value === \"string\" ? value.trim() : \"\";\n if (!v || v.length > 64 || !COLOR_REGEX.test(v)) return null;\n if (/^(?:inherit|initial|unset|revert|transparent)$/i.test(v)) return null;\n return v;\n}\n\n/** Cell attributes added on top of TipTap's `colspan` / `rowspan` / `colwidth`. */\nconst cellAttributes = () => ({\n align: {\n default: null,\n parseHTML: (element: HTMLElement) =>\n normalizeTableCellAlignment(element.style?.textAlign || element.getAttribute(\"align\")),\n renderHTML: (attrs: Record<string, any>) => {\n const align = normalizeTableCellAlignment(attrs.align);\n return align ? { style: `text-align: ${align}` } : {};\n },\n },\n backgroundColor: {\n default: null,\n parseHTML: (element: HTMLElement) =>\n normalizeTableCellColor(\n element.getAttribute(\"data-background-color\") ||\n element.style?.backgroundColor ||\n element.getAttribute(\"bgcolor\"),\n ),\n renderHTML: (attrs: Record<string, any>) => {\n const color = normalizeTableCellColor(attrs.backgroundColor);\n return color ? { style: `background-color: ${color}`, \"data-background-color\": color } : {};\n },\n },\n});\n\n// ---------------------------------------------------------------------------\n// Markdown (tiptap-markdown)\n// ---------------------------------------------------------------------------\n\nconst children = (node: ProsemirrorNode) => {\n const list: ProsemirrorNode[] = [];\n node.forEach((child) => list.push(child));\n return list;\n};\n\nconst hasSpan = (cell: ProsemirrorNode) => (cell.attrs.colspan ?? 1) > 1 || (cell.attrs.rowspan ?? 1) > 1;\n\n/**\n * Whether a table can be written as a GFM pipe table: the first row is all\n * header cells, the other rows have none, no cell spans rows or columns, and\n * every cell holds a single paragraph.\n */\nexport function isGfmTable(node: ProsemirrorNode): boolean {\n const rows = children(node);\n if (rows.length === 0) return false;\n const width = rows[0].childCount;\n return rows.every(\n (row, r) =>\n row.childCount === width &&\n children(row).every(\n (cell) =>\n (r === 0 ? cell.type.name === \"tableHeader\" : cell.type.name === \"tableCell\") &&\n !hasSpan(cell) &&\n cell.childCount === 1 &&\n cell.firstChild!.type.name === \"paragraph\",\n ),\n );\n}\n\nconst DELIMITERS: Record<string, string> = { left: \":---\", center: \":---:\", right: \"---:\" };\n\n/**\n * tiptap-markdown serializer for tables: GFM pipe tables (with column\n * alignment from the header cells and `|` escaped) when `isGfmTable`, HTML\n * otherwise (spans, header columns, multi-paragraph cells).\n */\nfunction serializeTableMarkdown(state: any, node: ProsemirrorNode) {\n if (!isGfmTable(node)) {\n const html = getHTMLFromFragment(Fragment.from(node), node.type.schema);\n // An HTML block must start on its own line and contain no blank lines.\n state.write(html.replace(/\\n{2,}/g, \"\\n\"));\n state.closeBlock(node);\n return;\n }\n const previous = state.inTable;\n state.inTable = true;\n children(node).forEach((row, r) => {\n if (r) state.ensureNewLine();\n state.write(\"| \");\n children(row).forEach((cell, c) => {\n if (c) state.write(\" | \");\n const paragraph = cell.firstChild!;\n // Render in place (mid-line, so no block prefix is added), then escape\n // the cell's pipes and line breaks, which would end the cell or row.\n const start = state.out.length;\n if (paragraph.childCount) state.renderInline(paragraph);\n const text: string = state.out.slice(start);\n state.out = state.out.slice(0, start) + text.replace(/\\n/g, \" \").replace(/\\|/g, \"\\\\|\");\n });\n state.write(\" |\");\n if (r === 0) {\n const delimiter = children(row).map((cell) => DELIMITERS[cell.attrs.align] ?? \"---\");\n state.ensureNewLine();\n state.write(`| ${delimiter.join(\" | \")} |`);\n }\n });\n state.inTable = previous;\n state.closeBlock(node);\n}\n\n// ---------------------------------------------------------------------------\n// Extensions\n// ---------------------------------------------------------------------------\n\nexport interface RichTextTableOptions {\n /** Drag column borders to resize columns (stored as `colwidth`). Default `true`. */\n resizable: boolean;\n /** Width of the resize handle in pixels. Default 5. */\n handleWidth: number;\n /** Minimum cell width in pixels. Default 25. */\n cellMinWidth: number;\n /** Whether the last column can be resized. Default `true`. */\n lastColumnResizable: boolean;\n /** Allow selecting the whole table as a node (click its border, Esc from a cell selection). Default `true`. */\n allowTableNodeSelection: boolean;\n /** HTML attributes of the `<table>` element. */\n HTMLAttributes: Record<string, any>;\n /** HTML attributes of `<td>` elements. */\n cellHTMLAttributes: Record<string, any>;\n /** HTML attributes of `<th>` elements. */\n headerHTMLAttributes: Record<string, any>;\n /** HTML attributes of `<tr>` elements. */\n rowHTMLAttributes: Record<string, any>;\n}\n\nexport const DEFAULT_TABLE_OPTIONS: RichTextTableOptions = {\n resizable: true,\n handleWidth: 5,\n cellMinWidth: 25,\n lastColumnResizable: true,\n allowTableNodeSelection: true,\n HTMLAttributes: { class: \"pixerate-table\" },\n cellHTMLAttributes: {},\n headerHTMLAttributes: {},\n rowHTMLAttributes: {},\n};\n\n/**\n * TipTap's `Table` with the GFM-aware markdown serializer and the nesting\n * guard (`createTableNestingPlugin`): tables are never pasted, imported or\n * inserted into table cells.\n */\nexport const Table = BaseTable.extend({\n addStorage() {\n return { markdown: { serialize: serializeTableMarkdown } };\n },\n addProseMirrorPlugins() {\n return [...(this.parent?.() ?? []), createTableNestingPlugin()];\n },\n});\n\nexport const TableRow = BaseTableRow;\n\n/** TipTap's `TableCell` plus `align` and `backgroundColor` attributes. */\nexport const TableCell = BaseTableCell.extend({\n addAttributes() {\n return { ...this.parent?.(), ...cellAttributes() };\n },\n});\n\n/** TipTap's `TableHeader` plus `align` and `backgroundColor` attributes. */\nexport const TableHeader = BaseTableHeader.extend({\n addAttributes() {\n return { ...this.parent?.(), ...cellAttributes() };\n },\n});\n\n/**\n * The table extensions (`table`, `tableRow`, `tableHeader`, `tableCell`)\n * configured for rich documents: resizable columns, header rows, columns and\n * cells, `colspan` / `rowspan` from imported HTML, cell alignment and\n * background, table node selection and GFM markdown. `createRichTextPreset`\n * adds them unless `table: false`.\n */\nexport function createTableExtensions(options: Partial<RichTextTableOptions> = {}): Extensions {\n const o = { ...DEFAULT_TABLE_OPTIONS, ...options };\n return [\n Table.configure({\n resizable: o.resizable,\n handleWidth: o.handleWidth,\n cellMinWidth: o.cellMinWidth,\n lastColumnResizable: o.lastColumnResizable,\n allowTableNodeSelection: o.allowTableNodeSelection,\n HTMLAttributes: o.HTMLAttributes,\n }),\n TableRow.configure({ HTMLAttributes: o.rowHTMLAttributes }),\n TableHeader.configure({ HTMLAttributes: o.headerHTMLAttributes }),\n TableCell.configure({ HTMLAttributes: o.cellHTMLAttributes }),\n ];\n}\n","import type { Editor } from \"@tiptap/core\";\nimport type { EditorState } from \"@tiptap/pm/state\";\nimport { CellSelection, isInTable, selectedRect } from \"@tiptap/pm/tables\";\nimport { isTrackChangesEnabled } from \"../track-changes\";\nimport {\n normalizeTableCellAlignment,\n normalizeTableCellColor,\n type TableCellAlignment,\n} from \"./extension\";\n\n/** Table operations shared by the command registry, the toolbars and agent tools. */\nexport type TableAction =\n | \"insertTable\"\n | \"addRowBefore\"\n | \"addRowAfter\"\n | \"deleteRow\"\n | \"addColumnBefore\"\n | \"addColumnAfter\"\n | \"deleteColumn\"\n | \"deleteTable\"\n | \"mergeCells\"\n | \"splitCell\"\n | \"toggleHeaderRow\"\n | \"toggleHeaderColumn\"\n | \"toggleHeaderCell\"\n | \"goToNextCell\"\n | \"goToPreviousCell\"\n | \"setCellAlignment\"\n | \"setCellBackground\";\n\n/** Parameters of `insertTable`, `setCellAlignment` and `setCellBackground`. */\nexport interface TableActionParams {\n /** `insertTable`: number of rows (1–100, default 3). */\n rows?: number;\n /** `insertTable`: number of columns (1–50, default 3). */\n cols?: number;\n /** `insertTable`: make the first row a header row (default `true`). */\n withHeaderRow?: boolean;\n /** `setCellAlignment`: `left`, `center`, `right`, `justify`, or `null` to clear. */\n align?: TableCellAlignment | null;\n /** `setCellBackground`: a CSS color, or `null` to clear. */\n color?: string | null;\n}\n\nexport interface TableActionInfo {\n action: TableAction;\n label: string;\n description: string;\n keywords: readonly string[];\n}\n\n/** Every table action with its label, in toolbar order. */\nexport const TABLE_ACTIONS: readonly TableActionInfo[] = [\n { action: \"insertTable\", label: \"Insert Table\", description: \"Inserts a table (rows, cols, withHeaderRow) at the cursor.\", keywords: [\"table\", \"grid\", \"new\"] },\n { action: \"addRowBefore\", label: \"Insert Row Above\", description: \"Adds a row above the current row.\", keywords: [\"row\", \"add\", \"above\"] },\n { action: \"addRowAfter\", label: \"Insert Row Below\", description: \"Adds a row below the current row.\", keywords: [\"row\", \"add\", \"below\"] },\n { action: \"deleteRow\", label: \"Delete Row\", description: \"Deletes the selected rows.\", keywords: [\"row\", \"remove\"] },\n { action: \"addColumnBefore\", label: \"Insert Column Left\", description: \"Adds a column left of the current column.\", keywords: [\"column\", \"add\", \"left\", \"before\"] },\n { action: \"addColumnAfter\", label: \"Insert Column Right\", description: \"Adds a column right of the current column.\", keywords: [\"column\", \"add\", \"right\", \"after\"] },\n { action: \"deleteColumn\", label: \"Delete Column\", description: \"Deletes the selected columns.\", keywords: [\"column\", \"remove\"] },\n { action: \"deleteTable\", label: \"Delete Table\", description: \"Deletes the table around the cursor.\", keywords: [\"table\", \"remove\"] },\n { action: \"mergeCells\", label: \"Merge Cells\", description: \"Merges the selected cells into one.\", keywords: [\"combine\", \"join\", \"span\"] },\n { action: \"splitCell\", label: \"Split Cell\", description: \"Splits a merged cell back into single cells.\", keywords: [\"unmerge\", \"span\"] },\n { action: \"toggleHeaderRow\", label: \"Toggle Header Row\", description: \"Turns the first row into header cells, or back.\", keywords: [\"header\", \"row\", \"th\"] },\n { action: \"toggleHeaderColumn\", label: \"Toggle Header Column\", description: \"Turns the first column into header cells, or back.\", keywords: [\"header\", \"column\", \"th\"] },\n { action: \"toggleHeaderCell\", label: \"Toggle Header Cell\", description: \"Turns the selected cells into header cells, or back.\", keywords: [\"header\", \"cell\", \"th\"] },\n { action: \"goToNextCell\", label: \"Next Cell\", description: \"Moves the cursor to the next cell.\", keywords: [\"tab\", \"navigate\"] },\n { action: \"goToPreviousCell\", label: \"Previous Cell\", description: \"Moves the cursor to the previous cell.\", keywords: [\"shift tab\", \"navigate\"] },\n { action: \"setCellAlignment\", label: \"Align Cells…\", description: \"Sets the horizontal alignment (align: left | center | right | justify | null) of the selected cells.\", keywords: [\"align\", \"left\", \"center\", \"right\"] },\n { action: \"setCellBackground\", label: \"Cell Background…\", description: \"Sets the background color (color: CSS color or null) of the selected cells.\", keywords: [\"shading\", \"fill\", \"color\"] },\n];\n\n/** A button of the table toolbars (`TableToolbar` in React and Svelte). */\nexport interface TableToolbarItem {\n /** Unique id (also the button's `data-action`). */\n id: string;\n action: TableAction;\n params?: TableActionParams;\n /** Short button text. */\n label: string;\n /** Accessible name and tooltip. */\n title: string;\n /** Items of one group are separated from the next group. */\n group: string;\n /** Toggle buttons: whether the button shows as pressed. */\n active?: (state: TableState) => boolean;\n}\n\n/** The default table toolbar: rows, columns, cells, headers, alignment, delete. */\nexport const DEFAULT_TABLE_TOOLBAR: readonly TableToolbarItem[] = [\n { id: \"addRowBefore\", action: \"addRowBefore\", label: \"+ Row ↑\", title: \"Insert row above\", group: \"rows\" },\n { id: \"addRowAfter\", action: \"addRowAfter\", label: \"+ Row ↓\", title: \"Insert row below\", group: \"rows\" },\n { id: \"deleteRow\", action: \"deleteRow\", label: \"− Row\", title: \"Delete row\", group: \"rows\" },\n { id: \"addColumnBefore\", action: \"addColumnBefore\", label: \"+ Col ←\", title: \"Insert column left\", group: \"columns\" },\n { id: \"addColumnAfter\", action: \"addColumnAfter\", label: \"+ Col →\", title: \"Insert column right\", group: \"columns\" },\n { id: \"deleteColumn\", action: \"deleteColumn\", label: \"− Col\", title: \"Delete column\", group: \"columns\" },\n { id: \"mergeCells\", action: \"mergeCells\", label: \"Merge\", title: \"Merge cells\", group: \"cells\" },\n { id: \"splitCell\", action: \"splitCell\", label: \"Split\", title: \"Split cell\", group: \"cells\" },\n { id: \"toggleHeaderRow\", action: \"toggleHeaderRow\", label: \"Header row\", title: \"Toggle header row\", group: \"headers\", active: (s) => s.headerRow },\n { id: \"toggleHeaderColumn\", action: \"toggleHeaderColumn\", label: \"Header col\", title: \"Toggle header column\", group: \"headers\", active: (s) => s.headerColumn },\n { id: \"toggleHeaderCell\", action: \"toggleHeaderCell\", label: \"Header cell\", title: \"Toggle header cell\", group: \"headers\", active: (s) => s.headerCell },\n { id: \"alignLeft\", action: \"setCellAlignment\", params: { align: \"left\" }, label: \"Left\", title: \"Align cell left\", group: \"align\", active: (s) => s.cellAlignment === \"left\" },\n { id: \"alignCenter\", action: \"setCellAlignment\", params: { align: \"center\" }, label: \"Center\", title: \"Align cell center\", group: \"align\", active: (s) => s.cellAlignment === \"center\" },\n { id: \"alignRight\", action: \"setCellAlignment\", params: { align: \"right\" }, label: \"Right\", title: \"Align cell right\", group: \"align\", active: (s) => s.cellAlignment === \"right\" },\n { id: \"deleteTable\", action: \"deleteTable\", label: \"Delete table\", title: \"Delete table\", group: \"table\" },\n];\n\nexport const MAX_TABLE_ROWS = 100;\nexport const MAX_TABLE_COLUMNS = 50;\n\nconst live = (editor: Editor | null | undefined): editor is Editor => !!editor && !editor.isDestroyed;\n\n/** Whether the editor's schema has the table nodes (`createRichTextPreset({ table })`). */\nexport function isTableEnabled(editor: Editor | null | undefined): boolean {\n return live(editor) && !!editor.schema.nodes.table && !!editor.schema.nodes.tableRow;\n}\n\n/** Whether the selection (cursor, text or cell selection) is inside a table. */\nexport function isSelectionInTable(state: EditorState): boolean {\n if (!state.schema.nodes.table) return false;\n return state.selection instanceof CellSelection || isInTable(state);\n}\n\n/**\n * `shouldShow` for a table bubble menu (TipTap's `BubbleMenuPlugin`): shown\n * while an editable editor's selection is in a table, even a collapsed cursor.\n */\nexport function shouldShowTableBubbleMenu({ editor, state }: { editor: Editor; state: EditorState }): boolean {\n return editor.isEditable && isSelectionInTable(state);\n}\n\nconst isInt = (value: unknown, min: number, max: number) =>\n typeof value === \"number\" && Number.isInteger(value) && value >= min && value <= max;\n\nconst can = (editor: Editor, run: (chain: any) => any): boolean => {\n try {\n return !!run(editor.can().chain()).run();\n } catch {\n return false;\n }\n};\n\n/**\n * Whether a table action can run: `true`, or the reason it cannot (e.g.\n * \"Place the cursor in a table first.\").\n */\nexport function getTableActionState(\n editor: Editor | null | undefined,\n action: TableAction,\n params: TableActionParams = {},\n): true | string {\n if (!live(editor)) return \"The editor is not available.\";\n if (!isTableEnabled(editor)) return \"Tables are not enabled in this editor.\";\n if (!editor.isEditable) return \"The editor is read-only.\";\n const state = editor.state;\n const inTable = isSelectionInTable(state);\n\n if (action === \"insertTable\") {\n if (inTable) return \"Tables cannot be nested: move the cursor out of the table first.\";\n if (params.rows !== undefined && !isInt(params.rows, 1, MAX_TABLE_ROWS)) {\n return `Rows must be a whole number from 1 to ${MAX_TABLE_ROWS}.`;\n }\n if (params.cols !== undefined && !isInt(params.cols, 1, MAX_TABLE_COLUMNS)) {\n return `Columns must be a whole number from 1 to ${MAX_TABLE_COLUMNS}.`;\n }\n return can(editor, (c) => c.insertTable({ rows: 1, cols: 1 })) ? true : \"A table cannot be inserted here.\";\n }\n\n if (!inTable) return \"Place the cursor in a table first.\";\n\n switch (action) {\n case \"mergeCells\":\n case \"splitCell\": {\n if (isTrackChangesEnabled(editor)) {\n return `${action === \"mergeCells\" ? \"Merging\" : \"Splitting\"} cells cannot be tracked: turn off Track Changes first.`;\n }\n if (action === \"mergeCells\") {\n return can(editor, (c) => c.mergeCells()) ? true : \"Select two or more adjacent cells to merge.\";\n }\n return can(editor, (c) => c.splitCell()) ? true : \"Only a merged cell can be split.\";\n }\n case \"deleteRow\":\n case \"deleteColumn\": {\n // prosemirror-tables only refuses to delete every row/column when dispatching.\n const rect = selectedRect(state);\n const all = action === \"deleteRow\"\n ? rect.top === 0 && rect.bottom === rect.map.height\n : rect.left === 0 && rect.right === rect.map.width;\n const what = action === \"deleteRow\" ? \"rows\" : \"columns\";\n if (all || !can(editor, (c) => c[action]())) return `These are all the ${what}: delete the table instead.`;\n return true;\n }\n case \"goToNextCell\":\n return can(editor, (c) => c.goToNextCell()) ? true : \"This is the last cell.\";\n case \"goToPreviousCell\":\n return can(editor, (c) => c.goToPreviousCell()) ? true : \"This is the first cell.\";\n case \"setCellAlignment\":\n if (params.align !== undefined && params.align !== null && !normalizeTableCellAlignment(params.align)) {\n return 'Alignment must be \"left\", \"center\", \"right\", \"justify\" or null.';\n }\n if (!editor.schema.nodes.tableCell?.spec.attrs?.align) return \"Cell alignment is not supported by this schema.\";\n return true;\n case \"setCellBackground\":\n if (params.color !== undefined && params.color !== null && !normalizeTableCellColor(params.color)) {\n return \"Color must be a CSS color such as #fde68a, rgb(…) or a color name, or null.\";\n }\n if (!editor.schema.nodes.tableCell?.spec.attrs?.backgroundColor) return \"Cell backgrounds are not supported by this schema.\";\n return true;\n default:\n return can(editor, (c) => c[action]()) ? true : \"This table action is not available here.\";\n }\n}\n\nexport interface RunTableActionOptions {\n /** Focus the editor (toolbars). Default `false`. */\n focus?: boolean;\n}\n\n/**\n * Runs a table action. Returns `false` (and changes nothing) when it cannot\n * run; check `getTableActionState` for the reason.\n */\nexport function runTableAction(\n editor: Editor | null | undefined,\n action: TableAction,\n params: TableActionParams = {},\n options: RunTableActionOptions = {},\n): boolean {\n if (getTableActionState(editor, action, params) !== true) return false;\n const ed = editor as Editor;\n let chain: any = ed.chain();\n if (options.focus) chain = chain.focus();\n switch (action) {\n case \"insertTable\":\n chain = chain.insertTable({\n rows: params.rows ?? 3,\n cols: params.cols ?? 3,\n withHeaderRow: params.withHeaderRow ?? true,\n });\n break;\n case \"setCellAlignment\":\n chain = chain.setCellAttribute(\"align\", normalizeTableCellAlignment(params.align));\n break;\n case \"setCellBackground\":\n chain = chain.setCellAttribute(\"backgroundColor\", normalizeTableCellColor(params.color));\n break;\n default:\n chain = chain[action]();\n }\n return !!chain.run();\n}\n\nexport interface TableActionStatus {\n enabled: boolean;\n /** Why the action cannot run (only when `enabled` is false). */\n reason?: string;\n}\n\n/** The table at the selection and what can be done there. */\nexport interface TableState {\n /** The schema has tables. */\n enabled: boolean;\n /** The selection is inside a table. */\n inTable: boolean;\n /** Cells are selected (a `CellSelection`). */\n cellSelection: boolean;\n /** Size of the table (0 outside a table). */\n rows: number;\n columns: number;\n /** Row and column (0-based) of the selection's first cell, or -1. */\n row: number;\n column: number;\n /** The first row / first column are all header cells. */\n headerRow: boolean;\n headerColumn: boolean;\n /** The cell at the selection is a header cell. */\n headerCell: boolean;\n /** Alignment / background of the cell at the selection. */\n cellAlignment: TableCellAlignment | null;\n cellBackground: string | null;\n /** Enablement of every action (with the default params). */\n actions: Record<TableAction, TableActionStatus>;\n}\n\nconst NO_ACTIONS = Object.fromEntries(\n TABLE_ACTIONS.map(({ action }) => [action, { enabled: false, reason: \"The editor is not available.\" }]),\n) as Record<TableAction, TableActionStatus>;\n\nexport const EMPTY_TABLE_STATE: TableState = Object.freeze({\n enabled: false,\n inTable: false,\n cellSelection: false,\n rows: 0,\n columns: 0,\n row: -1,\n column: -1,\n headerRow: false,\n headerColumn: false,\n headerCell: false,\n cellAlignment: null,\n cellBackground: null,\n actions: NO_ACTIONS,\n}) as TableState;\n\n/** Computes the table state at the editor's selection. */\nexport function getTableState(editor: Editor | null | undefined): TableState {\n if (!live(editor)) return EMPTY_TABLE_STATE;\n const actions = Object.fromEntries(\n TABLE_ACTIONS.map(({ action }) => {\n const result = getTableActionState(editor, action);\n return [action, result === true ? { enabled: true } : { enabled: false, reason: result }];\n }),\n ) as Record<TableAction, TableActionStatus>;\n const state = editor.state;\n const base: TableState = { ...EMPTY_TABLE_STATE, enabled: isTableEnabled(editor), actions };\n if (!base.enabled || !isSelectionInTable(state)) return base;\n try {\n const rect = selectedRect(state);\n const { map, table } = rect;\n const cellAt = (row: number, col: number) => table.nodeAt(map.map[row * map.width + col]);\n const allHeaders = (positions: number[]) =>\n positions.length > 0 && positions.every((pos) => table.nodeAt(pos)?.type.name === \"tableHeader\");\n const firstRow = map.cellsInRect({ left: 0, right: map.width, top: 0, bottom: 1 });\n const firstColumn = map.cellsInRect({ left: 0, right: 1, top: 0, bottom: map.height });\n const cell = cellAt(rect.top, rect.left);\n return {\n ...base,\n inTable: true,\n cellSelection: state.selection instanceof CellSelection,\n rows: map.height,\n columns: map.width,\n row: rect.top,\n column: rect.left,\n headerRow: allHeaders(firstRow),\n headerColumn: allHeaders(firstColumn),\n headerCell: cell?.type.name === \"tableHeader\",\n cellAlignment: normalizeTableCellAlignment(cell?.attrs.align),\n cellBackground: normalizeTableCellColor(cell?.attrs.backgroundColor),\n };\n } catch {\n return { ...base, inTable: true };\n }\n}\n\nconst stateKey = (state: TableState) => JSON.stringify(state);\n\nexport interface TableStore {\n getSnapshot(): TableState;\n subscribe(listener: () => void): () => void;\n destroy(): void;\n}\n\n/**\n * An external store of `getTableState(editor)` for UI bindings (React's\n * `useSyncExternalStore`, Svelte runes). The snapshot object only changes\n * when the state does, and the store listens to the editor only while it\n * has subscribers.\n */\nexport function createTableStore(editor: Editor | null | undefined): TableStore {\n const listeners = new Set<() => void>();\n let snapshot = getTableState(editor);\n let key = stateKey(snapshot);\n\n const update = () => {\n const next = getTableState(editor);\n const nextKey = stateKey(next);\n if (nextKey === key) return;\n snapshot = next;\n key = nextKey;\n listeners.forEach((listener) => listener());\n };\n const detach = () => {\n editor?.off(\"transaction\", update);\n editor?.off(\"update\", update);\n editor?.off(\"focus\", update);\n editor?.off(\"destroy\", update);\n };\n\n return {\n getSnapshot: () => {\n if (!listeners.size) {\n const next = getTableState(editor);\n const nextKey = stateKey(next);\n if (nextKey !== key) {\n snapshot = next;\n key = nextKey;\n }\n }\n return snapshot;\n },\n subscribe(listener) {\n if (!listeners.size && editor) {\n update();\n editor.on(\"transaction\", update);\n // `setEditable` emits `update` without a transaction.\n editor.on(\"update\", update);\n editor.on(\"focus\", update);\n editor.on(\"destroy\", update);\n }\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n if (!listeners.size) detach();\n };\n },\n destroy() {\n detach();\n listeners.clear();\n },\n };\n}\n"],"mappings":"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","names":["skip","exit","Fragment","Fragment","CellSelection","CellSelection"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/chunk-TXXNBDQX.cjs","../src/export/images.ts","../src/export/units.ts","../src/export/xml.ts","../src/export/zip-writer.ts","../src/export/docx.ts","../src/export/controller.ts"],"names":["attrs","format","document"],"mappings":"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","file":"/home/runner/work/editor/editor/packages/core/dist/chunk-TXXNBDQX.cjs","sourcesContent":[null,"/** Image types Word displays without a fallback, by MIME type → file extension. */\nexport const DOCX_IMAGE_TYPES: Record<string, string> = {\n \"image/png\": \"png\",\n \"image/jpeg\": \"jpeg\",\n \"image/jpg\": \"jpeg\",\n \"image/gif\": \"gif\",\n \"image/bmp\": \"bmp\",\n \"image/webp\": \"webp\",\n \"image/tiff\": \"tiff\",\n};\n\n/** Content types of the image extensions above. */\nexport const DOCX_IMAGE_CONTENT_TYPES: Record<string, string> = {\n png: \"image/png\",\n jpeg: \"image/jpeg\",\n gif: \"image/gif\",\n bmp: \"image/bmp\",\n webp: \"image/webp\",\n tiff: \"image/tiff\",\n};\n\nexport interface DecodedDataUrl {\n mime: string;\n bytes: Uint8Array;\n}\n\n/** Largest data URL decoded (characters), so a huge attribute cannot exhaust memory twice. */\nconst MAX_DATA_URL = 64 * 1024 * 1024;\n\n/** Decodes a base64 `data:` URL. Returns `null` for anything else or malformed input. */\nexport function decodeDataUrl(src: string): DecodedDataUrl | null {\n if (src.length > MAX_DATA_URL) return null;\n const comma = src.indexOf(\",\");\n if (comma === -1) return null;\n const header = /^data:([a-z0-9.+-]+\\/[a-z0-9.+-]+)((?:;[a-z0-9-]+=[^;,]*)*);base64$/i.exec(src.slice(0, comma));\n if (!header) return null;\n const payload = src.slice(comma + 1).replace(/\\s+/g, \"\");\n if (!/^[A-Za-z0-9+/]*={0,2}$/.test(payload)) return null;\n try {\n const binary = atob(payload);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return { mime: header[1].toLowerCase(), bytes };\n } catch {\n return null;\n }\n}\n\nconst u16be = (b: Uint8Array, i: number) => (b[i] << 8) | b[i + 1];\nconst u16le = (b: Uint8Array, i: number) => b[i] | (b[i + 1] << 8);\nconst u32be = (b: Uint8Array, i: number) => ((b[i] << 24) | (b[i + 1] << 16) | (b[i + 2] << 8) | b[i + 3]) >>> 0;\nconst i32le = (b: Uint8Array, i: number) => b[i] | (b[i + 1] << 8) | (b[i + 2] << 16) | (b[i + 3] << 24);\n\n/** Pixel size read from a PNG, GIF, JPEG, BMP or WebP header, or `null`. */\nexport function imagePixelSize(b: Uint8Array): { width: number; height: number } | null {\n const ok = (width: number, height: number) =>\n width > 0 && height > 0 && width < 1e6 && height < 1e6 ? { width, height } : null;\n if (b.length >= 24 && b[0] === 0x89 && b[1] === 0x50 && b[2] === 0x4e && b[3] === 0x47) {\n return ok(u32be(b, 16), u32be(b, 20));\n }\n if (b.length >= 10 && b[0] === 0x47 && b[1] === 0x49 && b[2] === 0x46) return ok(u16le(b, 6), u16le(b, 8));\n if (b.length >= 26 && b[0] === 0x42 && b[1] === 0x4d) return ok(Math.abs(i32le(b, 18)), Math.abs(i32le(b, 22)));\n if (b.length >= 30 && b[0] === 0x52 && b[1] === 0x49 && b[8] === 0x57 && b[9] === 0x45) {\n const chunk = String.fromCharCode(b[12], b[13], b[14], b[15]);\n if (chunk === \"VP8 \") return ok(u16le(b, 26) & 0x3fff, u16le(b, 28) & 0x3fff);\n if (chunk === \"VP8L\") {\n const bits = b[21] | (b[22] << 8) | (b[23] << 16) | (b[24] << 24);\n return ok((bits & 0x3fff) + 1, ((bits >>> 14) & 0x3fff) + 1);\n }\n if (chunk === \"VP8X\") return ok((b[24] | (b[25] << 8) | (b[26] << 16)) + 1, (b[27] | (b[28] << 8) | (b[29] << 16)) + 1);\n return null;\n }\n if (b.length >= 4 && b[0] === 0xff && b[1] === 0xd8) {\n // Walk the JPEG segments to the first start-of-frame marker.\n let i = 2;\n while (i + 9 < b.length) {\n if (b[i] !== 0xff) return null;\n const marker = b[i + 1];\n if (marker === 0xd8 || marker === 0x01 || (marker >= 0xd0 && marker <= 0xd7)) {\n i += 2;\n continue;\n }\n const length = u16be(b, i + 2);\n if (marker >= 0xc0 && marker <= 0xcf && marker !== 0xc4 && marker !== 0xc8 && marker !== 0xcc) {\n return ok(u16be(b, i + 7), u16be(b, i + 5));\n }\n if (length < 2) return null;\n i += 2 + length;\n }\n }\n return null;\n}\n\n/** A CSS pixel size from a node attribute (`320`, `\"320\"`, `\"320px\"`), or `undefined`. */\nexport function pixelAttr(value: unknown): number | undefined {\n if (typeof value === \"number\") return Number.isFinite(value) && value > 0 ? value : undefined;\n if (typeof value !== \"string\") return undefined;\n const match = /^\\s*(\\d+(?:\\.\\d+)?)\\s*(px)?\\s*$/i.exec(value);\n return match ? Number(match[1]) || undefined : undefined;\n}\n","// Portions ported from wordcraft/crates/docx/src/units.rs (MIT OR Apache-2.0, © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.\n\n/** Base font size (points) that `em` / `rem` / `%` lengths are relative to: Word's default 11 pt. */\nexport const DOCX_BASE_FONT_PT = 11;\n/** Largest length accepted, in points (22 inches, Word's page limit). */\nconst MAX_LEN_PT = 1584;\n\nconst UNIT_PT: Record<string, number> = {\n pt: 1,\n px: 0.75,\n in: 72,\n cm: 72 / 2.54,\n mm: 72 / 25.4,\n pc: 12,\n};\n\n/**\n * Converts a CSS length (`12pt`, `16px`, `1.5em`, `120%`, `0.5in`) to points.\n * Unit-less numbers are pixels. Returns `undefined` for anything else\n * (`calc()`, `var()`, keywords) and clamps to ±1584 pt.\n */\nexport function cssLengthToPt(value: unknown, basePt = DOCX_BASE_FONT_PT): number | undefined {\n if (typeof value === \"number\") return Number.isFinite(value) ? clampPt(value * UNIT_PT.px) : undefined;\n if (typeof value !== \"string\") return undefined;\n const match = /^\\s*(-?\\d+(?:\\.\\d+)?|-?\\.\\d+)\\s*([a-z%]*)\\s*$/i.exec(value);\n if (!match) return undefined;\n const n = Number(match[1]);\n const unit = match[2].toLowerCase() || \"px\";\n let pt: number | undefined;\n if (unit === \"em\" || unit === \"rem\") pt = n * basePt;\n else if (unit === \"%\") pt = (n / 100) * basePt;\n else if (unit in UNIT_PT) pt = n * UNIT_PT[unit];\n return pt === undefined || !Number.isFinite(pt) ? undefined : clampPt(pt);\n}\n\nfunction clampPt(pt: number): number {\n return Math.max(-MAX_LEN_PT, Math.min(MAX_LEN_PT, pt));\n}\n\n/** Points → twentieths of a point (twips), as an integer. */\nexport const ptToTwips = (pt: number): number => Math.round(pt * 20);\n/** Points → half-points (`w:sz`), at least 1. */\nexport const ptToHalfPoints = (pt: number): number => Math.max(1, Math.min(3276, Math.round(pt * 2)));\n/** CSS pixels (96 dpi) → English Metric Units (images). */\nexport const pxToEmu = (px: number): number => Math.round(px * 9525);\n/** CSS pixels (96 dpi) → twips. */\nexport const pxToTwips = (px: number): number => Math.round(px * 15);\n\n/** Formats points for CSS, e.g. `12pt` or `10.5pt`. */\nexport function ptToCss(pt: number): string {\n return `${Math.round(pt * 100) / 100}pt`;\n}\n\nconst NAMED_COLORS: Record<string, string> = {\n black: \"000000\",\n white: \"FFFFFF\",\n red: \"FF0000\",\n green: \"008000\",\n lime: \"00FF00\",\n blue: \"0000FF\",\n yellow: \"FFFF00\",\n cyan: \"00FFFF\",\n aqua: \"00FFFF\",\n magenta: \"FF00FF\",\n fuchsia: \"FF00FF\",\n gray: \"808080\",\n grey: \"808080\",\n silver: \"C0C0C0\",\n maroon: \"800000\",\n navy: \"000080\",\n olive: \"808000\",\n purple: \"800080\",\n teal: \"008080\",\n orange: \"FFA500\",\n pink: \"FFC0CB\",\n};\n\n/**\n * A CSS colour (`#abc`, `#aabbcc`, `#aabbccdd`, `rgb()` / `rgba()`, a few\n * names) as six upper-case hex digits, or `undefined`.\n */\nexport function cssColorToHex(value: unknown): string | undefined {\n if (typeof value !== \"string\") return undefined;\n const color = value.trim().toLowerCase();\n if (color in NAMED_COLORS) return NAMED_COLORS[color];\n let match = /^#([0-9a-f]{3,4})$/.exec(color);\n if (match) return match[1].slice(0, 3).split(\"\").map((c) => c + c).join(\"\").toUpperCase();\n match = /^#([0-9a-f]{6})(?:[0-9a-f]{2})?$/.exec(color);\n if (match) return match[1].toUpperCase();\n match = /^rgba?\\(\\s*(\\d{1,3})\\s*[, ]\\s*(\\d{1,3})\\s*[, ]\\s*(\\d{1,3})\\s*(?:[,/]\\s*[\\d.]+%?\\s*)?\\)$/.exec(color);\n if (match) {\n return match\n .slice(1, 4)\n .map((n) => Math.min(255, Number(n)).toString(16).padStart(2, \"0\"))\n .join(\"\")\n .toUpperCase();\n }\n return undefined;\n}\n\n/** Word's highlight colours (`w:highlight`), by their RGB value. */\nexport const WORD_HIGHLIGHTS: Record<string, string> = {\n FFFF00: \"yellow\",\n \"00FF00\": \"green\",\n \"00FFFF\": \"cyan\",\n FF00FF: \"magenta\",\n \"0000FF\": \"blue\",\n FF0000: \"red\",\n \"000080\": \"darkBlue\",\n \"008080\": \"darkCyan\",\n \"008000\": \"darkGreen\",\n \"800080\": \"darkMagenta\",\n \"800000\": \"darkRed\",\n \"808000\": \"darkYellow\",\n \"808080\": \"darkGray\",\n C0C0C0: \"lightGray\",\n \"000000\": \"black\",\n FFFFFF: \"white\",\n};\n","// Portions ported from wordcraft/crates/docx/src/xml.rs (MIT OR Apache-2.0, © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.\n\n/**\n * Characters XML 1.0 cannot carry (C0 controls other than tab / LF / CR,\n * lone surrogates, U+FFFE / U+FFFF). They are dropped, never escaped:\n * `` is not well-formed XML 1.0 either.\n */\nconst INVALID_XML_CHARS = /[^\\t\\n\\r --�\\u{10000}-\\u{10FFFF}]/gu;\n\n/** Removes characters that are not allowed in XML 1.0 documents. */\nexport function stripInvalidXmlChars(value: string): string {\n return value.replace(INVALID_XML_CHARS, \"\");\n}\n\n/** Escapes text for XML element content (`&`, `<`, `>`), dropping invalid characters. */\nexport function escapeXmlText(value: string): string {\n return stripInvalidXmlChars(value).replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\");\n}\n\n/**\n * Escapes a value for a double- or single-quoted XML attribute. White space\n * other than spaces is written as character references, because attribute\n * value normalisation would otherwise turn tabs and newlines into spaces.\n */\nexport function escapeXmlAttr(value: string): string {\n return escapeXmlText(value)\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\")\n .replace(/\\t/g, \"	\")\n .replace(/\\n/g, \" \")\n .replace(/\\r/g, \" \");\n}\n\nexport type XmlAttrs = Record<string, string | number | undefined | null | false>;\n\nfunction attrs(values: XmlAttrs | undefined): string {\n if (!values) return \"\";\n let out = \"\";\n for (const [name, value] of Object.entries(values)) {\n if (value === undefined || value === null || value === false) continue;\n out += ` ${name}=\"${escapeXmlAttr(String(value))}\"`;\n }\n return out;\n}\n\n/**\n * A small string-building XML writer; every attribute value and text node is\n * escaped. Element names are trusted (always literals in this codebase).\n */\nexport class XmlWriter {\n private parts: string[];\n\n /** `declaration: false` writes a fragment (e.g. one paragraph). */\n constructor(declaration = true) {\n this.parts = declaration ? ['<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\\n'] : [];\n }\n\n open(name: string, values?: XmlAttrs): this {\n this.parts.push(`<${name}${attrs(values)}>`);\n return this;\n }\n\n empty(name: string, values?: XmlAttrs): this {\n this.parts.push(`<${name}${attrs(values)}/>`);\n return this;\n }\n\n close(name: string): this {\n this.parts.push(`</${name}>`);\n return this;\n }\n\n text(value: string): this {\n this.parts.push(escapeXmlText(value));\n return this;\n }\n\n /** `<name attrs>text</name>`. */\n leaf(name: string, values: XmlAttrs | undefined, text: string): this {\n return this.open(name, values).text(text).close(name);\n }\n\n /** `<name w:val=\"value\"/>`. */\n val(name: string, value: string | number): this {\n return this.empty(name, { \"w:val\": value });\n }\n\n /** Appends markup produced by another writer. */\n raw(markup: string): this {\n this.parts.push(markup);\n return this;\n }\n\n toString(): string {\n return this.parts.join(\"\");\n }\n}\n","import { zipCrc32 } from \"../import/zip\";\n\n/**\n * Minimal, dependency-free ZIP writer (the counterpart of `readZip`), used by\n * the DOCX export. Entries are deflated with the platform\n * `CompressionStream(\"deflate-raw\")` when it exists (modern browsers,\n * Node ≥ 18) and stored otherwise, or when deflating does not make them\n * smaller. Names are written as UTF-8 (flag bit 11). No ZIP64: archives are\n * limited to 65 535 entries and 4 GiB.\n */\n\nexport interface ZipWriteEntry {\n /** Entry path with `/` separators; must be relative and free of `..`. */\n name: string;\n /** Strings are encoded as UTF-8. */\n data: Uint8Array | string;\n}\n\nexport interface ZipWriteOptions {\n /**\n * `\"auto\"` (default) deflates when `CompressionStream` is available,\n * `\"store\"` never compresses.\n */\n compression?: \"auto\" | \"store\";\n /**\n * Modification time written for every entry (default 1980-01-01, the DOS\n * epoch, so the output is deterministic).\n */\n modified?: Date;\n}\n\nconst encoder = new TextEncoder();\nconst MAX_SIZE = 0xffffffff;\n\nasync function readAll(readable: ReadableStream<Uint8Array>): Promise<Uint8Array> {\n const reader = readable.getReader();\n const chunks: Uint8Array[] = [];\n let length = 0;\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n length += value.length;\n }\n const out = new Uint8Array(length);\n let pos = 0;\n for (const chunk of chunks) {\n out.set(chunk, pos);\n pos += chunk.length;\n }\n return out;\n}\n\n/** Raw deflate with `CompressionStream`, or `null` when it is unavailable. */\nexport async function deflateRaw(data: Uint8Array): Promise<Uint8Array | null> {\n const Stream = (globalThis as { CompressionStream?: typeof CompressionStream }).CompressionStream;\n if (typeof Stream !== \"function\") return null;\n let stream: CompressionStream;\n try {\n stream = new Stream(\"deflate-raw\" as CompressionFormat);\n } catch {\n return null;\n }\n // Plain stream APIs only: jsdom's Blob has no `stream()` (see GOTCHAS).\n const writer = stream.writable.getWriter();\n const written = writer\n .write(data as unknown as BufferSource)\n .then(() => writer.close())\n .catch(() => {});\n const out = await readAll(stream.readable as ReadableStream<Uint8Array>);\n await written;\n return out;\n}\n\nfunction dosDateTime(date: Date): { time: number; date: number } {\n const year = Math.min(Math.max(date.getUTCFullYear(), 1980), 2107);\n return {\n time: (date.getUTCHours() << 11) | (date.getUTCMinutes() << 5) | Math.floor(date.getUTCSeconds() / 2),\n date: ((year - 1980) << 9) | ((date.getUTCMonth() + 1) << 5) | date.getUTCDate(),\n };\n}\n\nclass ByteSink {\n private chunks: Uint8Array[] = [];\n length = 0;\n\n bytes(data: Uint8Array): void {\n this.chunks.push(data);\n this.length += data.length;\n }\n\n header(fields: [number, 2 | 4][]): void {\n const size = fields.reduce((n, [, width]) => n + width, 0);\n const buffer = new Uint8Array(size);\n const view = new DataView(buffer.buffer);\n let pos = 0;\n for (const [value, width] of fields) {\n if (width === 2) view.setUint16(pos, value, true);\n else view.setUint32(pos, value >>> 0, true);\n pos += width;\n }\n this.bytes(buffer);\n }\n\n toUint8Array(): Uint8Array {\n const out = new Uint8Array(this.length);\n let pos = 0;\n for (const chunk of this.chunks) {\n out.set(chunk, pos);\n pos += chunk.length;\n }\n return out;\n }\n}\n\n/** Writes a ZIP archive. Throws on unsafe or duplicate names and oversized archives. */\nexport async function writeZip(entries: readonly ZipWriteEntry[], options: ZipWriteOptions = {}): Promise<Uint8Array> {\n if (entries.length > 0xffff) throw new RangeError(\"Too many ZIP entries (no ZIP64 support).\");\n const { time, date } = dosDateTime(options.modified ?? new Date(Date.UTC(1980, 0, 1)));\n const out = new ByteSink();\n const central = new ByteSink();\n const seen = new Set<string>();\n for (const entry of entries) {\n const name = entry.name;\n if (!name || name.startsWith(\"/\") || name.includes(\"\\\\\") || name.split(\"/\").includes(\"..\") || name.includes(\"\\0\")) {\n throw new Error(`Unsafe ZIP entry name: ${JSON.stringify(name)}`);\n }\n if (seen.has(name)) throw new Error(`Duplicate ZIP entry name: ${JSON.stringify(name)}`);\n seen.add(name);\n const raw = typeof entry.data === \"string\" ? encoder.encode(entry.data) : entry.data;\n const deflated = options.compression === \"store\" || raw.length === 0 ? null : await deflateRaw(raw);\n const useDeflate = !!deflated && deflated.length < raw.length;\n const body = useDeflate ? deflated! : raw;\n const method = useDeflate ? 8 : 0;\n const nameBytes = encoder.encode(name);\n const crc = zipCrc32(raw);\n const offset = out.length;\n if (body.length > MAX_SIZE || raw.length > MAX_SIZE || offset > MAX_SIZE) {\n throw new RangeError(\"ZIP archive too large (no ZIP64 support).\");\n }\n const flags = 0x0800;\n out.header([\n [0x04034b50, 4], [20, 2], [flags, 2], [method, 2], [time, 2], [date, 2],\n [crc, 4], [body.length, 4], [raw.length, 4], [nameBytes.length, 2], [0, 2],\n ]);\n out.bytes(nameBytes);\n out.bytes(body);\n central.header([\n [0x02014b50, 4], [20, 2], [20, 2], [flags, 2], [method, 2], [time, 2], [date, 2],\n [crc, 4], [body.length, 4], [raw.length, 4], [nameBytes.length, 2], [0, 2], [0, 2],\n [0, 2], [0, 2], [0, 4], [offset, 4],\n ]);\n central.bytes(nameBytes);\n }\n const cdOffset = out.length;\n const cd = central.toUint8Array();\n out.bytes(cd);\n out.header([\n [0x06054b50, 4], [0, 2], [0, 2], [entries.length, 2], [entries.length, 2],\n [cd.length, 4], [cdOffset, 4], [0, 2],\n ]);\n return out.toUint8Array();\n}\n","// Portions ported from wordcraft/crates/docx/src/write/mod.rs, wordcraft/crates/docx/src/write/story.rs, wordcraft/crates/docx/src/write/props.rs and wordcraft/crates/docx/src/package.rs (MIT OR Apache-2.0, © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.\nimport type { CommentThread, ReviewAuthor, SerializedComments } from \"../extensions/comment-store\";\nimport {\n DEFAULT_STYLES,\n isValidStyleId,\n NORMAL_STYLE_ID,\n type CharacterFormat,\n type ParagraphFormat,\n type StyleDefaults,\n type StyleDefinition,\n type StyleRegistry,\n type StyleRegistryJSON,\n} from \"../extensions/paragraph-styles/registry\";\nimport { DOCX_IMAGE_CONTENT_TYPES, DOCX_IMAGE_TYPES, decodeDataUrl, imagePixelSize, pixelAttr } from \"./images\";\nimport {\n cssColorToHex,\n cssLengthToPt,\n ptToHalfPoints,\n ptToTwips,\n pxToEmu,\n pxToTwips,\n WORD_HIGHLIGHTS,\n} from \"./units\";\nimport { XmlWriter, type XmlAttrs } from \"./xml\";\nimport { writeZip, type ZipWriteEntry } from \"./zip-writer\";\n\n/**\n * Dependency-free DOCX (WordprocessingML) export of TipTap documents.\n *\n * Takes an editor (anything with `getJSON()`) or its JSON and writes a\n * minimal, valid package: `[Content_Types].xml`, `_rels/.rels`,\n * `word/document.xml` (+ relationships), `styles.xml` (from the paragraph\n * style registry, with `basedOn` / `next` / `link`), `numbering.xml` (one\n * `w:num` per list), `settings.xml`, `comments.xml` +\n * `commentsExtended.xml` (replies and resolved state) + `people.xml` (author\n * ids), `docProps/core.xml` and `docProps/app.xml`, plus embedded images.\n *\n * Tracked insertions, deletions, moves (`w:moveFrom` / `w:moveTo` with\n * named move ranges), formatting changes (`w:rPrChange`) and block changes\n * (`w:pPrChange`, paragraph-mark `w:ins` / `w:del`) keep their authors and\n * dates. Anything that cannot be written is listed in the returned report.\n */\n\nexport const DOCX_EXPORT_MIME_TYPE = \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\";\n\n/** A ProseMirror / TipTap JSON node (`editor.getJSON()`). */\nexport interface DocxJSONNode {\n type?: string;\n attrs?: Record<string, any>;\n content?: DocxJSONNode[];\n marks?: DocxJSONMark[];\n text?: string;\n}\n\nexport interface DocxJSONMark {\n type: string;\n attrs?: Record<string, any>;\n}\n\n/** Anything with `getJSON()`, e.g. a TipTap `Editor`. Its comment store and style registry are used by default. */\nexport interface DocxExportEditorLike {\n getJSON(): DocxJSONNode;\n storage?: unknown;\n}\n\n/** A comment store (`CommentStore`), its `toJSON()` output, or a thread list. */\nexport type DocxCommentSource =\n | { toJSON(): SerializedComments }\n | { getSnapshot(): { threads: readonly CommentThread[] } }\n | SerializedComments\n | readonly CommentThread[];\n\nexport interface DocxExportOptions {\n /**\n * Paragraph and character styles written to `styles.xml`. Defaults to the\n * editor's registry (`ParagraphStyles` extension), else the built-in styles.\n */\n styles?: StyleRegistry | StyleRegistryJSON | readonly StyleDefinition[];\n /** Comment threads. Defaults to the editor's comment store (`Comments` extension). */\n comments?: DocxCommentSource | null;\n /**\n * The document's author (`dc:creator`) and the author of tracked changes\n * and comments that name none.\n */\n author?: string | ReviewAuthor;\n /**\n * `\"strip-authors\"` writes every comment, reply and tracked change as\n * \"Author\" (initials \"A\"), leaves out `people.xml`, the creator and last\n * modified by, and sets `w:removePersonalInformation` so Word keeps doing\n * so. Default `\"keep\"`.\n */\n privacy?: \"keep\" | \"strip-authors\";\n /** `dc:title` of the document. */\n title?: string;\n /**\n * Images with `http(s)` URLs: `\"skip\"` (default, reported) or `\"link\"`\n * (an external relationship Word may load when the file is opened).\n */\n remoteImages?: \"skip\" | \"link\";\n /** Time written as created / modified (default: now). */\n now?: () => Date;\n /** ZIP compression (default `\"auto\"`: deflate when `CompressionStream` exists). */\n compression?: \"auto\" | \"store\";\n}\n\nexport type DocxExportIssueKind = \"node\" | \"mark\" | \"image\" | \"link\" | \"comment\" | \"style\";\n\n/** Something the export left out or simplified, counted per kind, name and reason. */\nexport interface DocxExportIssue {\n kind: DocxExportIssueKind;\n /** Node / mark type, style id, image or link URL (truncated), or comment thread id. */\n name: string;\n reason: string;\n count: number;\n}\n\nexport interface DocxExportReport {\n /** Content that was dropped or simplified. Empty when everything was written. */\n dropped: DocxExportIssue[];\n /** Counts of what was written. */\n written: {\n paragraphs: number;\n tables: number;\n images: number;\n comments: number;\n replies: number;\n trackedChanges: number;\n };\n}\n\nexport interface DocxExportResult {\n /** The `.docx` file. */\n data: Uint8Array;\n report: DocxExportReport;\n}\n\nexport interface DocxPackagePart {\n name: string;\n data: Uint8Array | string;\n}\n\nconst NS = {\n w: \"http://schemas.openxmlformats.org/wordprocessingml/2006/main\",\n r: \"http://schemas.openxmlformats.org/officeDocument/2006/relationships\",\n wp: \"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\",\n a: \"http://schemas.openxmlformats.org/drawingml/2006/main\",\n pic: \"http://schemas.openxmlformats.org/drawingml/2006/picture\",\n mc: \"http://schemas.openxmlformats.org/markup-compatibility/2006\",\n w14: \"http://schemas.microsoft.com/office/word/2010/wordml\",\n w15: \"http://schemas.microsoft.com/office/word/2012/wordml\",\n};\n\nconst BODY_NS: XmlAttrs = {\n \"xmlns:w\": NS.w,\n \"xmlns:r\": NS.r,\n \"xmlns:wp\": NS.wp,\n \"xmlns:a\": NS.a,\n \"xmlns:pic\": NS.pic,\n \"xmlns:mc\": NS.mc,\n \"xmlns:w14\": NS.w14,\n \"xmlns:w15\": NS.w15,\n \"mc:Ignorable\": \"w14 w15\",\n};\n\nconst REL = {\n officeDocument: \"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument\",\n core: \"http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties\",\n app: \"http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties\",\n styles: \"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\",\n numbering: \"http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering\",\n settings: \"http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings\",\n comments: \"http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments\",\n commentsExtended: \"http://schemas.microsoft.com/office/2011/relationships/commentsExtended\",\n people: \"http://schemas.microsoft.com/office/2011/relationships/people\",\n image: \"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image\",\n hyperlink: \"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink\",\n};\n\nconst CT_WML = \"application/vnd.openxmlformats-officedocument.wordprocessingml.\";\n\n/** Text width of a US Letter page with 1\" margins, in twips (6.5\"). */\nconst CONTENT_WIDTH_TWIPS = 9360;\n/** Widest image, in CSS pixels (6.5\" at 96 dpi). */\nconst MAX_IMAGE_WIDTH_PX = 624;\n/** Indent per list or quote level, in twips (0.5\"). */\nconst INDENT_STEP = 720;\n/** Name written for every author with `privacy: \"strip-authors\"` (as Word does). */\nexport const DOCX_ANONYMOUS_AUTHOR = \"Author\";\nconst ANONYMOUS_INITIALS = \"A\";\nconst MAX_DEPTH = 64;\n\n/** Bullet characters per list level. */\nconst BULLETS = [\"•\", \"◦\", \"▪\"];\nconst BULLET_FONTS = [\"Symbol\", \"Courier New\", \"Wingdings\"];\nconst TASK_UNCHECKED = \"☐\";\nconst TASK_CHECKED = \"☒\";\n\n/** Formatting marks whose `rPr` is written; the rest are reported. */\nconst FORMAT_MARKS = new Set([\n \"bold\",\n \"italic\",\n \"underline\",\n \"strike\",\n \"subscript\",\n \"superscript\",\n \"code\",\n \"textStyle\",\n \"highlight\",\n \"characterStyle\",\n]);\n/** Marks handled separately (links, review) or that carry no formatting. */\nconst STRUCTURAL_MARKS = new Set([\"link\", \"insertion\", \"deletion\", \"formatChange\", \"comment\", \"bookmark\"]);\n\ninterface RunFormat {\n charStyle?: string;\n font?: string;\n bold?: boolean;\n italic?: boolean;\n strike?: boolean;\n color?: string;\n halfPoints?: number;\n highlight?: string;\n shading?: string;\n underline?: boolean;\n vertAlign?: \"superscript\" | \"subscript\";\n}\n\ninterface Revision {\n kind: \"ins\" | \"del\";\n attrs: Record<string, any>;\n moveId?: string;\n}\n\ntype PieceKind = \"text\" | \"tab\" | \"br\" | \"image\";\n\ninterface Piece {\n kind: PieceKind;\n text?: string;\n node: DocxJSONNode;\n /** Last piece produced by `node` (comment range ends go after it). */\n last: boolean;\n marks: DocxJSONMark[];\n}\n\ninterface BlockContext {\n depth: number;\n quoteLevel: number;\n list?: { numId: number; level: number; task?: boolean; checked?: boolean };\n /** The list item's first paragraph gets the number; later ones are indented. */\n listItemFirst?: boolean;\n}\n\ninterface BlockChangeRecord {\n changeId?: string;\n authorId?: string;\n authorName?: string;\n createdAt?: number;\n previous?: { type?: string; attrs?: Record<string, any> };\n operation?: \"insert\" | \"delete\";\n}\n\nconst isEditorLike = (value: unknown): value is DocxExportEditorLike =>\n !!value && typeof (value as DocxExportEditorLike).getJSON === \"function\";\n\n/** Threads from any supported comment source. */\nfunction threadsOf(source: DocxCommentSource | null | undefined): CommentThread[] {\n if (!source) return [];\n if (Array.isArray(source)) return [...source];\n const value = source as any;\n if (typeof value.toJSON === \"function\") return [...(value.toJSON()?.threads ?? [])];\n if (typeof value.getSnapshot === \"function\") return [...(value.getSnapshot()?.threads ?? [])];\n return Array.isArray(value.threads) ? [...value.threads] : [];\n}\n\nfunction stylesOf(source: DocxExportOptions[\"styles\"]): { styles: StyleDefinition[]; defaults: StyleDefaults } {\n if (!source) return { styles: DEFAULT_STYLES.map((s) => ({ ...s })), defaults: {} };\n if (Array.isArray(source)) return { styles: [...source], defaults: {} };\n const value = source as any;\n const json: StyleRegistryJSON = typeof value.toJSON === \"function\" ? value.toJSON() : value;\n return { styles: [...(json.styles ?? [])], defaults: json.defaults ?? {} };\n}\n\nfunction authorOf(author: DocxExportOptions[\"author\"]): ReviewAuthor | undefined {\n if (!author) return undefined;\n return typeof author === \"string\" ? { id: author, name: author } : author;\n}\n\n/** W3CDTF date without milliseconds, or `undefined` for missing / invalid times. */\nfunction isoDate(ms: unknown): string | undefined {\n const n = typeof ms === \"number\" ? ms : Number(ms);\n if (!Number.isFinite(n) || n <= 0) return undefined;\n const date = new Date(n);\n return Number.isNaN(date.getTime()) ? undefined : date.toISOString().replace(/\\.\\d{3}Z$/, \"Z\");\n}\n\nfunction initialsOf(name: string): string {\n const letters = name\n .split(/\\s+/)\n .filter(Boolean)\n .map((word) => Array.from(word)[0] ?? \"\")\n .join(\"\")\n .slice(0, 3)\n .toUpperCase();\n return letters || ANONYMOUS_INITIALS;\n}\n\n/** Word keeps built-in style names in lower case (`heading 1`) in `styles.xml`. */\nfunction fileStyleName(name: string): string {\n const heading = /^Heading ([1-9])$/.exec(name);\n return heading ? `heading ${heading[1]}` : name;\n}\n\nconst truncate = (value: string, max = 80) => (value.length > max ? `${value.slice(0, max - 1)}…` : value);\n\n/** Converts a mark list to run formatting. */\nfunction runFormatOf(marks: readonly DocxJSONMark[] | undefined): RunFormat {\n const format: RunFormat = {};\n for (const mark of marks ?? []) {\n const attrs = mark.attrs ?? {};\n switch (mark.type) {\n case \"bold\":\n format.bold = true;\n break;\n case \"italic\":\n format.italic = true;\n break;\n case \"underline\":\n format.underline = true;\n break;\n case \"strike\":\n format.strike = true;\n break;\n case \"subscript\":\n format.vertAlign = \"subscript\";\n break;\n case \"superscript\":\n format.vertAlign = \"superscript\";\n break;\n case \"code\":\n format.font = \"Consolas\";\n break;\n case \"textStyle\": {\n const color = cssColorToHex(attrs.color);\n if (color) format.color = color;\n const pt = cssLengthToPt(attrs.fontSize);\n if (pt !== undefined && pt > 0) format.halfPoints = ptToHalfPoints(pt);\n if (typeof attrs.fontFamily === \"string\" && attrs.fontFamily.trim()) {\n format.font = attrs.fontFamily.split(\",\")[0].trim().replace(/^[\"']|[\"']$/g, \"\");\n }\n break;\n }\n case \"highlight\": {\n const color = attrs.color ? cssColorToHex(attrs.color) : \"FFFF00\";\n if (color && WORD_HIGHLIGHTS[color]) format.highlight = WORD_HIGHLIGHTS[color];\n else if (color) format.shading = color;\n break;\n }\n case \"characterStyle\":\n if (isValidStyleId(attrs.styleId)) format.charStyle = attrs.styleId;\n break;\n case \"link\":\n format.charStyle ??= \"Hyperlink\";\n break;\n default:\n break;\n }\n }\n return format;\n}\n\n/** `w:rPr` children in CT_RPr order. */\nfunction writeRunProps(w: XmlWriter, f: RunFormat): void {\n if (f.charStyle) w.val(\"w:rStyle\", f.charStyle);\n if (f.font) w.empty(\"w:rFonts\", { \"w:ascii\": f.font, \"w:hAnsi\": f.font, \"w:cs\": f.font, \"w:eastAsia\": f.font });\n if (f.bold) w.empty(\"w:b\");\n if (f.italic) w.empty(\"w:i\");\n if (f.strike) w.empty(\"w:strike\");\n if (f.color) w.val(\"w:color\", f.color);\n if (f.halfPoints) {\n w.val(\"w:sz\", f.halfPoints);\n w.val(\"w:szCs\", f.halfPoints);\n }\n if (f.highlight) w.val(\"w:highlight\", f.highlight);\n if (f.underline) w.val(\"w:u\", \"single\");\n if (f.shading) w.empty(\"w:shd\", { \"w:val\": \"clear\", \"w:color\": \"auto\", \"w:fill\": f.shading });\n if (f.vertAlign) w.val(\"w:vertAlign\", f.vertAlign);\n}\n\nconst hasRunProps = (f: RunFormat) => Object.values(f).some((v) => v !== undefined && v !== false);\n\nfunction characterFormatToRun(c: CharacterFormat | undefined): RunFormat {\n const f: RunFormat = {};\n if (!c) return f;\n if (c.fontFamily) f.font = c.fontFamily.split(\",\")[0].trim().replace(/^[\"']|[\"']$/g, \"\");\n if (c.bold) f.bold = true;\n if (c.italic) f.italic = true;\n if (c.underline) f.underline = true;\n if (c.strike) f.strike = true;\n const color = cssColorToHex(c.color);\n if (color) f.color = color;\n const pt = cssLengthToPt(c.fontSize);\n if (pt !== undefined && pt > 0) f.halfPoints = ptToHalfPoints(pt);\n const background = cssColorToHex(c.backgroundColor);\n if (background) f.shading = background;\n return f;\n}\n\n/** `w:pPr` content of a style's paragraph format (spacing, indentation, alignment). */\nfunction writeParagraphFormat(w: XmlWriter, p: ParagraphFormat | undefined, outline?: number): void {\n if (!p && outline === undefined) return;\n const before = cssLengthToPt(p?.spaceBefore);\n const after = cssLengthToPt(p?.spaceAfter);\n const lineValue = p?.lineHeight;\n let line: number | undefined;\n let lineRule: string | undefined;\n if (typeof lineValue === \"string\" && /^\\s*\\d+(\\.\\d+)?\\s*$/.test(lineValue)) {\n line = Math.round(Number(lineValue) * 240);\n lineRule = \"auto\";\n } else if (lineValue) {\n const pt = cssLengthToPt(lineValue);\n if (pt !== undefined && pt > 0) {\n line = ptToTwips(pt);\n lineRule = \"atLeast\";\n }\n }\n if (before !== undefined || after !== undefined || line !== undefined) {\n w.empty(\"w:spacing\", {\n \"w:before\": before !== undefined ? Math.max(0, ptToTwips(before)) : undefined,\n \"w:after\": after !== undefined ? Math.max(0, ptToTwips(after)) : undefined,\n \"w:line\": line,\n \"w:lineRule\": lineRule,\n });\n }\n const left = cssLengthToPt(p?.indentLeft);\n const right = cssLengthToPt(p?.indentRight);\n const first = cssLengthToPt(p?.indentFirstLine);\n if (left !== undefined || right !== undefined || first !== undefined) {\n w.empty(\"w:ind\", {\n \"w:left\": left !== undefined ? ptToTwips(left) : undefined,\n \"w:right\": right !== undefined ? ptToTwips(right) : undefined,\n \"w:firstLine\": first !== undefined && first >= 0 ? ptToTwips(first) : undefined,\n \"w:hanging\": first !== undefined && first < 0 ? ptToTwips(-first) : undefined,\n });\n }\n const jc = alignment(p?.textAlign);\n if (jc) w.val(\"w:jc\", jc);\n if (outline !== undefined) w.val(\"w:outlineLvl\", outline);\n}\n\nfunction alignment(value: unknown): string | undefined {\n switch (value) {\n case \"left\":\n return \"left\";\n case \"center\":\n return \"center\";\n case \"right\":\n return \"right\";\n case \"justify\":\n return \"both\";\n default:\n return undefined;\n }\n}\n\nclass Relationships {\n private list: { id: string; type: string; target: string; external: boolean }[] = [];\n private index = new Map<string, string>();\n\n add(type: string, target: string, external = false): string {\n const key = `${type}\\n${target}\\n${external}`;\n const existing = this.index.get(key);\n if (existing) return existing;\n const id = `rId${this.list.length + 1}`;\n this.list.push({ id, type, target, external });\n this.index.set(key, id);\n return id;\n }\n\n get size(): number {\n return this.list.length;\n }\n\n xml(): string {\n const w = new XmlWriter();\n w.open(\"Relationships\", { xmlns: \"http://schemas.openxmlformats.org/package/2006/relationships\" });\n for (const rel of this.list) {\n w.empty(\"Relationship\", {\n Id: rel.id,\n Type: rel.type,\n Target: rel.target,\n TargetMode: rel.external ? \"External\" : undefined,\n });\n }\n w.close(\"Relationships\");\n return w.toString();\n }\n}\n\ninterface CommentEntry {\n thread: CommentThread;\n /** File id of the thread's comment, then of each reply. */\n ids: number[];\n started: boolean;\n ended: boolean;\n}\n\nclass DocxBuilder {\n readonly report: DocxExportReport = {\n dropped: [],\n written: { paragraphs: 0, tables: 0, images: 0, comments: 0, replies: 0, trackedChanges: 0 },\n };\n private rels = new Relationships();\n private media: { name: string; bytes: Uint8Array }[] = [];\n private mediaTypes = new Set<string>();\n private nums: { numId: number; abstractId: number; start?: number; level: number }[] = [];\n private revisionId = 0;\n private docPrId = 0;\n private paraIdCounter = 0x10000000;\n private comments = new Map<string, CommentEntry>();\n /** Thread id → JSON node carrying its last comment mark. */\n private commentEnds = new Map<string, DocxJSONNode>();\n /** JSON node → threads whose range ends after it (so ends are found in O(1) per node). */\n private endsByNode = new Map<DocxJSONNode, string[]>();\n private people = new Map<string, string>();\n private styleIds: Set<string>;\n private extraStyles = new Set<string>();\n private readonly anonymous: boolean;\n private readonly defaultAuthor: ReviewAuthor | undefined;\n\n constructor(\n private readonly doc: DocxJSONNode,\n private readonly options: DocxExportOptions,\n private readonly threads: CommentThread[],\n private readonly styles: { styles: StyleDefinition[]; defaults: StyleDefaults },\n ) {\n this.anonymous = options.privacy === \"strip-authors\";\n this.defaultAuthor = authorOf(options.author);\n this.styleIds = new Set(styles.styles.filter((s) => isValidStyleId(s.id)).map((s) => s.id));\n }\n\n drop(kind: DocxExportIssueKind, name: string, reason: string): void {\n const issue = this.report.dropped.find((i) => i.kind === kind && i.name === name && i.reason === reason);\n if (issue) issue.count++;\n else this.report.dropped.push({ kind, name: truncate(name), reason, count: 1 });\n }\n\n // -- Authors and revisions ------------------------------------------------\n\n private authorName(name: unknown, id: unknown): string {\n if (this.anonymous) return DOCX_ANONYMOUS_AUTHOR;\n const author =\n (typeof name === \"string\" && name.trim()) ||\n (typeof id === \"string\" && id.trim()) ||\n this.defaultAuthor?.name ||\n \"Unknown\";\n const authorId = (typeof id === \"string\" && id.trim()) || this.defaultAuthor?.id;\n if (authorId && authorId !== author && !this.people.has(author)) this.people.set(author, authorId);\n return author;\n }\n\n private changeAttrs(attrs: Record<string, any>): XmlAttrs {\n return {\n \"w:id\": ++this.revisionId,\n \"w:author\": this.authorName(attrs.authorName, attrs.authorId),\n \"w:date\": isoDate(attrs.createdAt),\n };\n }\n\n // -- Comments ---------------------------------------------------------------\n\n private prepareComments(): void {\n const marked = new Set<string>();\n const visit = (node: DocxJSONNode, depth: number) => {\n if (depth > MAX_DEPTH) return;\n for (const mark of node.marks ?? []) {\n if (mark.type === \"comment\" && typeof mark.attrs?.commentId === \"string\") {\n marked.add(mark.attrs.commentId);\n this.commentEnds.set(mark.attrs.commentId, node);\n }\n }\n node.content?.forEach((child) => visit(child, depth + 1));\n };\n visit(this.doc, 0);\n let next = 0;\n for (const thread of this.threads) {\n if (!thread || typeof thread.id !== \"string\") continue;\n if (!marked.has(thread.id)) {\n this.drop(\"comment\", thread.id, \"comment text is not in the document\");\n continue;\n }\n if (!thread.body?.trim()) {\n this.drop(\"comment\", thread.id, \"draft comment without text\");\n this.commentEnds.delete(thread.id);\n continue;\n }\n const replies = (thread.replies ?? []).filter((reply) => reply && reply.body?.trim());\n const ids = [next++, ...replies.map(() => next++)];\n this.comments.set(thread.id, { thread: { ...thread, replies }, ids, started: false, ended: false });\n }\n for (const [threadId, node] of this.commentEnds) {\n if (!this.comments.has(threadId)) continue;\n const list = this.endsByNode.get(node) ?? [];\n list.push(threadId);\n this.endsByNode.set(node, list);\n }\n }\n\n // -- Document ---------------------------------------------------------------\n\n documentXml(): string {\n this.prepareComments();\n const body = new XmlWriter(false);\n const blocks = this.doc.type === \"doc\" || !this.doc.type ? (this.doc.content ?? []) : [this.doc];\n this.blocks(body, blocks, { depth: 0, quoteLevel: 0 });\n // Word wants a paragraph before the section properties.\n if (!blocks.length || blocks[blocks.length - 1].type === \"table\") body.empty(\"w:p\");\n // Ranges whose end was never written (e.g. text in a dropped node) are closed here.\n for (const [id, entry] of this.comments) if (entry.started && !entry.ended) this.endComment(body, id);\n const w = new XmlWriter();\n w.open(\"w:document\", BODY_NS).open(\"w:body\").raw(body.toString());\n w.open(\"w:sectPr\")\n .empty(\"w:pgSz\", { \"w:w\": 12240, \"w:h\": 15840 })\n .empty(\"w:pgMar\", {\n \"w:top\": 1440,\n \"w:right\": 1440,\n \"w:bottom\": 1440,\n \"w:left\": 1440,\n \"w:header\": 720,\n \"w:footer\": 720,\n \"w:gutter\": 0,\n })\n .close(\"w:sectPr\");\n w.close(\"w:body\").close(\"w:document\");\n return w.toString();\n }\n\n private blocks(w: XmlWriter, nodes: readonly DocxJSONNode[], ctx: BlockContext): void {\n if (ctx.depth > MAX_DEPTH) {\n this.drop(\"node\", \"nesting\", `content nested deeper than ${MAX_DEPTH} levels`);\n return;\n }\n let first = true;\n nodes.forEach((node, i) => {\n const itemCtx: BlockContext = { ...ctx, depth: ctx.depth + 1, listItemFirst: ctx.list ? first : undefined };\n this.block(w, node, itemCtx);\n if (node.type !== \"bulletList\" && node.type !== \"orderedList\" && node.type !== \"taskList\") first = false;\n // Two tables in a row would merge into one in Word, so a paragraph separates them.\n if (node.type === \"table\" && nodes[i + 1]?.type === \"table\") w.empty(\"w:p\");\n });\n }\n\n private block(w: XmlWriter, node: DocxJSONNode, ctx: BlockContext): void {\n const type = node.type ?? \"\";\n switch (type) {\n case \"paragraph\":\n this.paragraph(w, node, ctx);\n return;\n case \"heading\":\n this.paragraph(w, node, ctx, { heading: Math.max(1, Math.min(6, Number(node.attrs?.level) || 1)) });\n return;\n case \"codeBlock\":\n this.paragraph(w, node, ctx, { code: true });\n return;\n case \"blockquote\":\n this.blocks(w, node.content ?? [], { ...ctx, quoteLevel: ctx.quoteLevel + 1 });\n return;\n case \"bulletList\":\n case \"orderedList\":\n case \"taskList\":\n this.list(w, node, ctx);\n return;\n case \"table\":\n this.table(w, node, ctx);\n return;\n case \"horizontalRule\":\n w.open(\"w:p\").open(\"w:pPr\").open(\"w:pBdr\");\n w.empty(\"w:bottom\", { \"w:val\": \"single\", \"w:sz\": 6, \"w:space\": 1, \"w:color\": \"auto\" });\n w.close(\"w:pBdr\").close(\"w:pPr\").close(\"w:p\");\n this.report.written.paragraphs++;\n return;\n case \"pageBreak\":\n w.open(\"w:p\").open(\"w:r\").empty(\"w:br\", { \"w:type\": \"page\" }).close(\"w:r\").close(\"w:p\");\n return;\n case \"image\":\n this.paragraph(w, { type: \"paragraph\", content: [node] }, ctx);\n return;\n default:\n break;\n }\n // Unknown blocks: inline content becomes a paragraph, block content is flattened.\n const content = node.content ?? [];\n if (content.some((child) => child.type === \"text\" || isInlineType(child.type))) {\n this.drop(\"node\", type || \"unknown\", \"written as a plain paragraph\");\n this.paragraph(w, { type: \"paragraph\", content }, ctx);\n } else if (content.length) {\n this.drop(\"node\", type || \"unknown\", \"container flattened\");\n this.blocks(w, content, ctx);\n } else {\n this.drop(\"node\", type || \"unknown\", \"unsupported node\");\n }\n }\n\n // -- Lists --------------------------------------------------------------------\n\n private list(w: XmlWriter, node: DocxJSONNode, ctx: BlockContext): void {\n const level = Math.min(8, ctx.list ? ctx.list.level + 1 : 0);\n const abstractId = node.type === \"orderedList\" ? 2 : node.type === \"taskList\" ? 3 : 1;\n const numId = this.nums.length + 1;\n const start = node.type === \"orderedList\" ? Number(node.attrs?.start ?? 1) : undefined;\n this.nums.push({ numId, abstractId, level, start: start !== undefined && start !== 1 && Number.isFinite(start) ? start : undefined });\n for (const item of node.content ?? []) {\n const task = item.type === \"taskItem\";\n this.blocks(w, item.content ?? [], {\n ...ctx,\n list: { numId, level, task, checked: task ? !!item.attrs?.checked : undefined },\n });\n }\n }\n\n // -- Paragraphs -----------------------------------------------------------------\n\n private styleFor(node: DocxJSONNode, ctx: BlockContext, opts: { heading?: number; code?: boolean }): string | undefined {\n const own = node.attrs?.styleId;\n if (own) {\n if (isValidStyleId(own) && this.styleIds.has(own)) return own;\n this.drop(\"style\", String(own), \"style is not in the registry\");\n }\n if (opts.heading) return this.needStyle(`Heading${opts.heading}`);\n if (opts.code) return this.needStyle(\"Code\");\n if (ctx.quoteLevel > 0) return this.needStyle(\"BlockText\");\n if (ctx.list) return this.needStyle(\"ListParagraph\");\n return undefined;\n }\n\n /** Uses a style the registry may not define (it is then written with defaults). */\n private needStyle(id: string): string {\n if (!this.styleIds.has(id)) this.extraStyles.add(id);\n return id;\n }\n\n private previousStyle(previous: BlockChangeRecord[\"previous\"]): string | undefined {\n if (!previous) return undefined;\n const id = previous.attrs?.styleId;\n if (isValidStyleId(id) && this.styleIds.has(id)) return id;\n if (previous.type === \"heading\") return this.needStyle(`Heading${Math.max(1, Math.min(6, Number(previous.attrs?.level) || 1))}`);\n if (previous.type === \"codeBlock\") return this.needStyle(\"Code\");\n return undefined;\n }\n\n private paragraph(\n w: XmlWriter,\n node: DocxJSONNode,\n ctx: BlockContext,\n opts: { heading?: number; code?: boolean } = {},\n ): void {\n this.report.written.paragraphs++;\n const style = this.styleFor(node, ctx, opts);\n const change = (node.attrs?.blockChange ?? null) as BlockChangeRecord | null;\n const operation = change?.operation;\n const list = ctx.list;\n const numbered = list && ctx.listItemFirst;\n const indent = ctx.quoteLevel * INDENT_STEP + (list && !numbered ? (list.level + 1) * INDENT_STEP : 0);\n const jc = alignment(node.attrs?.textAlign);\n\n w.open(\"w:p\");\n const ppr = new XmlWriter(false);\n if (style) ppr.val(\"w:pStyle\", style);\n if (numbered) {\n ppr.open(\"w:numPr\").val(\"w:ilvl\", list!.level).val(\"w:numId\", list!.numId).close(\"w:numPr\");\n }\n if (indent && !(ctx.quoteLevel > 0 && !list && ctx.quoteLevel === 1)) ppr.empty(\"w:ind\", { \"w:left\": indent });\n if (jc) ppr.val(\"w:jc\", jc);\n if (change && operation) {\n ppr.open(\"w:rPr\").empty(operation === \"insert\" ? \"w:ins\" : \"w:del\", this.changeAttrs(change)).close(\"w:rPr\");\n this.report.written.trackedChanges++;\n } else if (change?.previous) {\n ppr.open(\"w:pPrChange\", this.changeAttrs(change)).open(\"w:pPr\");\n const old = this.previousStyle(change.previous);\n if (old) ppr.val(\"w:pStyle\", old);\n const oldJc = alignment(change.previous.attrs?.textAlign);\n if (oldJc) ppr.val(\"w:jc\", oldJc);\n ppr.close(\"w:pPr\").close(\"w:pPrChange\");\n this.report.written.trackedChanges++;\n }\n const pprXml = ppr.toString();\n if (pprXml) w.open(\"w:pPr\").raw(pprXml).close(\"w:pPr\");\n\n if (list?.task && numbered) {\n // Word has no checklist numbering: the box is the first character.\n w.open(\"w:r\").leaf(\"w:t\", { \"xml:space\": \"preserve\" }, `${list.checked ? TASK_CHECKED : TASK_UNCHECKED} `).close(\"w:r\");\n }\n const synthetic: Revision | undefined =\n change && operation ? { kind: operation === \"insert\" ? \"ins\" : \"del\", attrs: change } : undefined;\n this.inline(w, this.pieces(node.content ?? [], opts.code === true), synthetic);\n w.close(\"w:p\");\n }\n\n /** Flattens inline content into runs of text, tabs, breaks and images. */\n private pieces(nodes: readonly DocxJSONNode[], code: boolean, out: Piece[] = [], depth = 0): Piece[] {\n if (depth > MAX_DEPTH) return out;\n for (const node of nodes) {\n const marks = node.marks ?? [];\n switch (node.type) {\n case \"text\": {\n const text = node.text ?? \"\";\n const parts = text.split(/(\\t|\\r\\n|\\n|\\r)/);\n const pieces: Piece[] = [];\n for (const part of parts) {\n if (!part) continue;\n if (part === \"\\t\") pieces.push({ kind: \"tab\", node, last: false, marks });\n else if (part === \"\\n\" || part === \"\\r\\n\" || part === \"\\r\") pieces.push({ kind: \"br\", node, last: false, marks });\n else pieces.push({ kind: \"text\", text: part, node, last: false, marks });\n }\n if (!pieces.length) pieces.push({ kind: \"text\", text: \"\", node, last: false, marks });\n pieces[pieces.length - 1].last = true;\n out.push(...pieces);\n break;\n }\n case \"hardBreak\":\n out.push({ kind: \"br\", node, last: true, marks });\n break;\n case \"image\":\n out.push({ kind: \"image\", node, last: true, marks });\n break;\n case \"mention\": {\n const label = node.attrs?.label ?? node.attrs?.id ?? \"\";\n out.push({ kind: \"text\", text: label ? `@${label}` : \"\", node, last: true, marks });\n break;\n }\n default:\n if (node.content?.length) {\n this.pieces(node.content, code, out, depth + 1);\n } else if (typeof node.attrs?.label === \"string\" || typeof node.attrs?.text === \"string\") {\n this.drop(\"node\", node.type ?? \"unknown\", \"written as text\");\n out.push({ kind: \"text\", text: String(node.attrs.label ?? node.attrs.text), node, last: true, marks });\n } else {\n this.drop(\"node\", node.type ?? \"unknown\", \"unsupported inline node\");\n }\n }\n }\n return out;\n }\n\n private revisionsOf(marks: readonly DocxJSONMark[], synthetic?: Revision): Revision[] {\n const out: Revision[] = [];\n const ins = marks.find((m) => m.type === \"insertion\");\n const del = marks.find((m) => m.type === \"deletion\");\n if (ins) out.push({ kind: \"ins\", attrs: ins.attrs ?? {}, moveId: ins.attrs?.moveId || undefined });\n if (del) out.push({ kind: \"del\", attrs: del.attrs ?? {}, moveId: del.attrs?.moveId || undefined });\n if (!out.length && synthetic) out.push(synthetic);\n return out;\n }\n\n private linkOf(marks: readonly DocxJSONMark[]): string | undefined {\n const link = marks.find((m) => m.type === \"link\");\n const href = typeof link?.attrs?.href === \"string\" ? link.attrs.href.trim() : \"\";\n if (!href) return undefined;\n if (href.startsWith(\"#\") || /^(https?|mailto|tel|ftp):/i.test(href) || !/^[a-z][a-z0-9+.-]*:/i.test(href)) return href;\n this.drop(\"link\", href, \"unsafe URL scheme\");\n return undefined;\n }\n\n /** Writes pieces grouped into hyperlinks (outer) and tracked-change wrappers (inner). */\n private inline(w: XmlWriter, pieces: Piece[], synthetic?: Revision): void {\n let openLink: string | undefined;\n type OpenRevisions = { key: string; tags: string[]; moveRanges: { tag: string; id: number }[] };\n let openRevs: OpenRevisions | null = null;\n const closeRevs = () => {\n const open = openRevs as OpenRevisions | null;\n if (!open) return;\n for (const tag of [...open.tags].reverse()) w.close(tag);\n for (const range of open.moveRanges) w.empty(range.tag, { \"w:id\": range.id });\n openRevs = null;\n };\n const closeLink = () => {\n closeRevs();\n if (openLink !== undefined) w.close(\"w:hyperlink\");\n openLink = undefined;\n };\n for (const piece of pieces) {\n const href = this.linkOf(piece.marks);\n if (href !== openLink) {\n closeLink();\n if (href !== undefined) {\n if (href.startsWith(\"#\")) w.open(\"w:hyperlink\", { \"w:anchor\": href.slice(1), \"w:history\": 1 });\n else w.open(\"w:hyperlink\", { \"r:id\": this.rels.add(REL.hyperlink, href, true), \"w:history\": 1 });\n openLink = href;\n }\n }\n const revs = this.revisionsOf(piece.marks, synthetic);\n const key = revs.map((r) => `${r.kind}:${r.attrs.changeId ?? \"\"}:${r.moveId ?? \"\"}:${r.attrs.authorName ?? \"\"}`).join(\"|\");\n if (key !== ((openRevs as OpenRevisions | null)?.key ?? \"\")) {\n closeRevs();\n if (revs.length) {\n const state: OpenRevisions = { key, tags: [], moveRanges: [] };\n for (const rev of revs) {\n const attrs = this.changeAttrs(rev.attrs);\n this.report.written.trackedChanges++;\n if (rev.moveId) {\n const rangeTag = rev.kind === \"ins\" ? \"w:moveToRange\" : \"w:moveFromRange\";\n const rangeId = ++this.revisionId;\n w.empty(`${rangeTag}Start`, { \"w:id\": rangeId, \"w:name\": rev.moveId, \"w:author\": attrs[\"w:author\"], \"w:date\": attrs[\"w:date\"] });\n state.moveRanges.push({ tag: `${rangeTag}End`, id: rangeId });\n }\n const tag = rev.moveId ? (rev.kind === \"ins\" ? \"w:moveTo\" : \"w:moveFrom\") : rev.kind === \"ins\" ? \"w:ins\" : \"w:del\";\n w.open(tag, attrs);\n state.tags.push(tag);\n }\n openRevs = state;\n }\n }\n this.commentStarts(w, piece.marks);\n this.run(w, piece, revs);\n if (piece.last) this.commentEndsAfter(w, piece.node);\n }\n closeLink();\n }\n\n private commentStarts(w: XmlWriter, marks: readonly DocxJSONMark[]): void {\n for (const mark of marks) {\n if (mark.type !== \"comment\") continue;\n const entry = this.comments.get(mark.attrs?.commentId);\n if (!entry || entry.started) continue;\n entry.started = true;\n for (const id of entry.ids) w.empty(\"w:commentRangeStart\", { \"w:id\": id });\n }\n }\n\n private commentEndsAfter(w: XmlWriter, node: DocxJSONNode): void {\n for (const threadId of this.endsByNode.get(node) ?? []) {\n const entry = this.comments.get(threadId);\n if (entry?.started && !entry.ended) this.endComment(w, threadId);\n }\n }\n\n private endComment(w: XmlWriter, threadId: string): void {\n const entry = this.comments.get(threadId)!;\n entry.ended = true;\n for (const id of entry.ids) {\n w.empty(\"w:commentRangeEnd\", { \"w:id\": id });\n w.open(\"w:r\").open(\"w:rPr\").val(\"w:rStyle\", \"CommentReference\").close(\"w:rPr\");\n w.empty(\"w:commentReference\", { \"w:id\": id }).close(\"w:r\");\n }\n this.needStyle(\"CommentReference\");\n this.needStyle(\"CommentText\");\n }\n\n private run(w: XmlWriter, piece: Piece, revs: Revision[]): void {\n for (const mark of piece.marks) {\n if (!FORMAT_MARKS.has(mark.type) && !STRUCTURAL_MARKS.has(mark.type)) this.drop(\"mark\", mark.type, \"formatting not supported\");\n if (mark.type === \"characterStyle\" && mark.attrs?.styleId && !this.styleIds.has(mark.attrs.styleId)) {\n this.drop(\"style\", String(mark.attrs.styleId), \"character style is not in the registry\");\n }\n }\n if (piece.kind === \"image\") {\n const drawing = this.image(piece.node);\n if (!drawing) return;\n w.open(\"w:r\");\n const format = runFormatOf(piece.marks);\n delete format.charStyle;\n if (hasRunProps(format)) {\n w.open(\"w:rPr\");\n writeRunProps(w, format);\n w.close(\"w:rPr\");\n }\n w.raw(drawing).close(\"w:r\");\n return;\n }\n const format = runFormatOf(piece.marks.filter((m) => m.type !== \"characterStyle\" || this.styleIds.has(m.attrs?.styleId)));\n if (format.charStyle === \"Hyperlink\") this.needStyle(\"Hyperlink\");\n const formatChange = piece.marks.find((m) => m.type === \"formatChange\");\n w.open(\"w:r\");\n if (hasRunProps(format) || formatChange) {\n w.open(\"w:rPr\");\n writeRunProps(w, format);\n if (formatChange) {\n const attrs = formatChange.attrs ?? {};\n w.open(\"w:rPrChange\", this.changeAttrs(attrs)).open(\"w:rPr\");\n writeRunProps(w, runFormatOf(Array.isArray(attrs.before) ? attrs.before : []));\n w.close(\"w:rPr\").close(\"w:rPrChange\");\n this.report.written.trackedChanges++;\n }\n w.close(\"w:rPr\");\n }\n // Deleted text is `w:delText`; text moved away stays `w:t` (ECMA-376 §17.13.5.22).\n const deleted = revs.some((r) => r.kind === \"del\" && !r.moveId);\n if (piece.kind === \"tab\") w.empty(\"w:tab\");\n else if (piece.kind === \"br\") w.empty(\"w:br\");\n else if (piece.text) w.leaf(deleted ? \"w:delText\" : \"w:t\", { \"xml:space\": \"preserve\" }, piece.text);\n w.close(\"w:r\");\n }\n\n // -- Images -----------------------------------------------------------------\n\n private image(node: DocxJSONNode): string | null {\n const src = typeof node.attrs?.src === \"string\" ? node.attrs.src.trim() : \"\";\n const alt = typeof node.attrs?.alt === \"string\" ? node.attrs.alt : \"\";\n const title = typeof node.attrs?.title === \"string\" ? node.attrs.title : \"\";\n let relId: string;\n let natural: { width: number; height: number } | null = null;\n let linked = false;\n if (src.startsWith(\"data:\")) {\n const decoded = decodeDataUrl(src);\n const ext = decoded ? DOCX_IMAGE_TYPES[decoded.mime] : undefined;\n if (!decoded || !ext) {\n this.drop(\"image\", decoded?.mime ?? \"data URL\", \"unsupported image type\");\n return null;\n }\n const name = `image${this.media.length + 1}.${ext}`;\n this.media.push({ name, bytes: decoded.bytes });\n this.mediaTypes.add(ext);\n relId = this.rels.add(REL.image, `media/${name}`);\n natural = imagePixelSize(decoded.bytes);\n } else if (/^https?:\\/\\//i.test(src)) {\n if (this.options.remoteImages !== \"link\") {\n this.drop(\"image\", src, \"remote image skipped (use remoteImages: \\\"link\\\")\");\n return null;\n }\n relId = this.rels.add(REL.image, src, true);\n linked = true;\n } else {\n this.drop(\"image\", src || \"image\", \"image source is neither a data URL nor http(s)\");\n return null;\n }\n let width = pixelAttr(node.attrs?.width) ?? natural?.width ?? 400;\n let height = pixelAttr(node.attrs?.height) ?? (natural ? (natural.height * width) / natural.width : 300);\n if (width > MAX_IMAGE_WIDTH_PX) {\n height = (height * MAX_IMAGE_WIDTH_PX) / width;\n width = MAX_IMAGE_WIDTH_PX;\n }\n const cx = pxToEmu(width);\n const cy = pxToEmu(height);\n const id = ++this.docPrId;\n this.report.written.images++;\n const w = new XmlWriter(false);\n w.open(\"w:drawing\").open(\"wp:inline\", { distT: 0, distB: 0, distL: 0, distR: 0 });\n w.empty(\"wp:extent\", { cx, cy }).empty(\"wp:effectExtent\", { l: 0, t: 0, r: 0, b: 0 });\n w.empty(\"wp:docPr\", { id, name: `Picture ${id}`, descr: alt || undefined, title: title || undefined });\n w.open(\"wp:cNvGraphicFramePr\").empty(\"a:graphicFrameLocks\", { noChangeAspect: 1 }).close(\"wp:cNvGraphicFramePr\");\n w.open(\"a:graphic\").open(\"a:graphicData\", { uri: \"http://schemas.openxmlformats.org/drawingml/2006/picture\" });\n w.open(\"pic:pic\").open(\"pic:nvPicPr\").empty(\"pic:cNvPr\", { id: 0, name: `Picture ${id}`, descr: alt || undefined });\n w.empty(\"pic:cNvPicPr\").close(\"pic:nvPicPr\");\n w.open(\"pic:blipFill\").empty(\"a:blip\", linked ? { \"r:link\": relId } : { \"r:embed\": relId });\n w.open(\"a:stretch\").empty(\"a:fillRect\").close(\"a:stretch\").close(\"pic:blipFill\");\n w.open(\"pic:spPr\").open(\"a:xfrm\").empty(\"a:off\", { x: 0, y: 0 }).empty(\"a:ext\", { cx, cy }).close(\"a:xfrm\");\n w.open(\"a:prstGeom\", { prst: \"rect\" }).empty(\"a:avLst\").close(\"a:prstGeom\").close(\"pic:spPr\");\n w.close(\"pic:pic\").close(\"a:graphicData\").close(\"a:graphic\").close(\"wp:inline\").close(\"w:drawing\");\n return w.toString();\n }\n\n // -- Tables -------------------------------------------------------------------\n\n private table(w: XmlWriter, node: DocxJSONNode, ctx: BlockContext): void {\n type Slot = { cell: DocxJSONNode; rowOffset: number; colOffset: number; colspan: number; rowspan: number } | null;\n const rows = (node.content ?? []).filter((row) => row.type === \"tableRow\" || row.content?.length);\n if (!rows.length) {\n this.drop(\"node\", \"table\", \"empty table\");\n return;\n }\n const grid: Slot[][] = rows.map(() => []);\n rows.forEach((row, r) => {\n let col = 0;\n for (const cell of row.content ?? []) {\n while (grid[r][col]) col++;\n const colspan = Math.max(1, Math.min(63, Number(cell.attrs?.colspan) || 1));\n const rowspan = Math.max(1, Math.min(rows.length - r, Number(cell.attrs?.rowspan) || 1));\n for (let i = 0; i < rowspan; i++) {\n for (let j = 0; j < colspan; j++) {\n grid[r + i][col + j] = { cell, rowOffset: i, colOffset: j, colspan, rowspan };\n }\n }\n col += colspan;\n }\n });\n const cols = Math.max(1, Math.min(63, ...grid.map((row) => row.length)));\n const widths: number[] = [];\n for (let c = 0; c < cols; c++) {\n const slot = grid[0][c];\n const colwidth = slot?.cell.attrs?.colwidth;\n const px = Array.isArray(colwidth) ? Number(colwidth[slot!.colOffset]) : NaN;\n widths.push(Number.isFinite(px) && px > 0 ? pxToTwips(px) : 0);\n }\n const known = widths.reduce((n, v) => n + v, 0);\n const unknown = widths.filter((v) => !v).length;\n const fill = unknown ? Math.max(360, Math.floor(Math.max(0, CONTENT_WIDTH_TWIPS - known) / unknown)) : 0;\n for (let c = 0; c < cols; c++) if (!widths[c]) widths[c] = fill;\n\n this.report.written.tables++;\n w.open(\"w:tbl\").open(\"w:tblPr\");\n w.empty(\"w:tblW\", { \"w:w\": 0, \"w:type\": \"auto\" });\n w.open(\"w:tblBorders\");\n for (const side of [\"top\", \"left\", \"bottom\", \"right\", \"insideH\", \"insideV\"]) {\n w.empty(`w:${side}`, { \"w:val\": \"single\", \"w:sz\": 4, \"w:space\": 0, \"w:color\": \"auto\" });\n }\n w.close(\"w:tblBorders\");\n w.empty(\"w:tblLook\", { \"w:val\": \"04A0\", \"w:firstRow\": 1, \"w:lastRow\": 0, \"w:firstColumn\": 1, \"w:lastColumn\": 0, \"w:noHBand\": 0, \"w:noVBand\": 1 });\n w.close(\"w:tblPr\");\n w.open(\"w:tblGrid\");\n widths.forEach((width) => w.empty(\"w:gridCol\", { \"w:w\": width }));\n w.close(\"w:tblGrid\");\n const cellCtx: BlockContext = { depth: ctx.depth + 1, quoteLevel: 0 };\n rows.forEach((row, r) => {\n w.open(\"w:tr\");\n const cells = row.content ?? [];\n if (cells.length && cells.every((cell) => cell.type === \"tableHeader\")) {\n w.open(\"w:trPr\").empty(\"w:tblHeader\").close(\"w:trPr\");\n }\n for (let c = 0; c < cols; c++) {\n const slot = grid[r][c];\n if (slot && slot.colOffset > 0) continue;\n const span = slot?.colspan ?? 1;\n const width = widths.slice(c, c + span).reduce((n, v) => n + v, 0);\n w.open(\"w:tc\").open(\"w:tcPr\").empty(\"w:tcW\", { \"w:w\": width, \"w:type\": \"dxa\" });\n if (span > 1) w.val(\"w:gridSpan\", span);\n if (slot && slot.rowspan > 1) {\n if (slot.rowOffset === 0) w.val(\"w:vMerge\", \"restart\");\n else w.empty(\"w:vMerge\");\n }\n w.close(\"w:tcPr\");\n const content = slot && slot.rowOffset === 0 ? (slot.cell.content ?? []) : [];\n if (content.length) this.blocks(w, content, cellCtx);\n // A cell must end with a paragraph.\n const lastType = content[content.length - 1]?.type;\n if (!content.length || lastType === \"table\") w.empty(\"w:p\");\n w.close(\"w:tc\");\n }\n w.close(\"w:tr\");\n });\n w.close(\"w:tbl\");\n }\n\n // -- Other parts --------------------------------------------------------------\n\n numberingXml(): string | null {\n if (!this.nums.length) return null;\n const w = new XmlWriter();\n w.open(\"w:numbering\", BODY_NS);\n const abstract = (id: number, kind: \"bullet\" | \"decimal\" | \"task\") => {\n w.open(\"w:abstractNum\", { \"w:abstractNumId\": id }).val(\"w:multiLevelType\", \"hybridMultilevel\");\n for (let level = 0; level < 9; level++) {\n w.open(\"w:lvl\", { \"w:ilvl\": level }).val(\"w:start\", 1);\n if (kind === \"decimal\") {\n const formats = [\"decimal\", \"lowerLetter\", \"lowerRoman\"];\n w.val(\"w:numFmt\", formats[level % 3]).val(\"w:lvlText\", `%${level + 1}.`);\n } else if (kind === \"bullet\") {\n w.val(\"w:numFmt\", \"bullet\").val(\"w:lvlText\", BULLETS[level % 3]);\n } else {\n w.val(\"w:numFmt\", \"none\").val(\"w:lvlText\", \"\");\n }\n w.val(\"w:lvlJc\", \"left\");\n w.open(\"w:pPr\").empty(\"w:ind\", { \"w:left\": (level + 1) * INDENT_STEP, \"w:hanging\": kind === \"task\" ? 0 : 360 }).close(\"w:pPr\");\n if (kind === \"bullet\") {\n const font = BULLET_FONTS[level % 3] === \"Symbol\" ? \"Arial\" : BULLET_FONTS[level % 3];\n w.open(\"w:rPr\").empty(\"w:rFonts\", { \"w:ascii\": font, \"w:hAnsi\": font, \"w:hint\": \"default\" }).close(\"w:rPr\");\n }\n w.close(\"w:lvl\");\n }\n w.close(\"w:abstractNum\");\n };\n abstract(1, \"bullet\");\n abstract(2, \"decimal\");\n abstract(3, \"task\");\n for (const num of this.nums) {\n w.open(\"w:num\", { \"w:numId\": num.numId }).val(\"w:abstractNumId\", num.abstractId);\n if (num.start !== undefined) {\n w.open(\"w:lvlOverride\", { \"w:ilvl\": num.level }).val(\"w:startOverride\", num.start).close(\"w:lvlOverride\");\n }\n w.close(\"w:num\");\n }\n w.close(\"w:numbering\");\n return w.toString();\n }\n\n stylesXml(): string {\n const w = new XmlWriter();\n w.open(\"w:styles\", BODY_NS);\n const defaults = this.styles.defaults;\n const defaultRun = characterFormatToRun(defaults.character);\n w.open(\"w:docDefaults\").open(\"w:rPrDefault\").open(\"w:rPr\");\n const font = defaultRun.font ?? \"Calibri\";\n w.empty(\"w:rFonts\", { \"w:ascii\": font, \"w:hAnsi\": font, \"w:eastAsia\": font, \"w:cs\": font });\n const size = defaultRun.halfPoints ?? 22;\n w.val(\"w:sz\", size).val(\"w:szCs\", size);\n w.val(\"w:lang\", \"en-US\");\n w.close(\"w:rPr\").close(\"w:rPrDefault\");\n w.open(\"w:pPrDefault\").open(\"w:pPr\");\n if (defaults.paragraph && Object.keys(defaults.paragraph).length) writeParagraphFormat(w, defaults.paragraph);\n else w.empty(\"w:spacing\", { \"w:after\": 160, \"w:line\": 259, \"w:lineRule\": \"auto\" });\n w.close(\"w:pPr\").close(\"w:pPrDefault\").close(\"w:docDefaults\");\n\n const byId = new Map(this.styles.styles.filter((s) => isValidStyleId(s.id)).map((s) => [s.id, s]));\n const written = new Set<string>();\n const blockOf = (style: StyleDefinition): StyleDefinition[\"block\"] => {\n let current: StyleDefinition | undefined = style;\n for (let i = 0; current && i < 32; i++) {\n if (current.block) return current.block;\n current = current.basedOn ? byId.get(current.basedOn) : undefined;\n }\n return null;\n };\n const writeStyle = (style: StyleDefinition) => {\n if (written.has(style.id)) return;\n written.add(style.id);\n const isNormal = style.kind === \"paragraph\" && style.id === NORMAL_STYLE_ID;\n w.open(\"w:style\", {\n \"w:type\": style.kind === \"character\" ? \"character\" : \"paragraph\",\n \"w:default\": isNormal ? 1 : undefined,\n \"w:customStyle\": style.builtin ? undefined : 1,\n \"w:styleId\": style.id,\n });\n w.val(\"w:name\", fileStyleName(style.name || style.id));\n const base = style.basedOn && byId.has(style.basedOn) && byId.get(style.basedOn)!.kind === style.kind ? style.basedOn : undefined;\n if (base) w.val(\"w:basedOn\", base);\n if (style.kind === \"paragraph\" && style.next && byId.get(style.next)?.kind === \"paragraph\") w.val(\"w:next\", style.next);\n if (style.linked && byId.has(style.linked)) w.val(\"w:link\", style.linked);\n if (style.priority !== undefined && Number.isFinite(style.priority)) w.val(\"w:uiPriority\", Math.max(0, Math.round(style.priority)));\n if (style.hidden) w.empty(\"w:semiHidden\").empty(\"w:unhideWhenUsed\");\n if (style.quick) w.empty(\"w:qFormat\");\n const block = style.kind === \"paragraph\" ? blockOf(style) : null;\n const ownBlock = style.kind === \"paragraph\" ? style.block : null;\n const outline = ownBlock?.type === \"heading\" ? Math.max(0, Math.min(8, (Number(ownBlock.attrs?.level) || 1) - 1)) : undefined;\n if (style.kind === \"paragraph\" && (style.paragraph || outline !== undefined)) {\n const p = new XmlWriter(false);\n writeParagraphFormat(p, style.paragraph, outline);\n const xml = p.toString();\n if (xml) w.open(\"w:pPr\").raw(xml).close(\"w:pPr\");\n }\n const run = characterFormatToRun(style.character);\n if (block?.type === \"codeBlock\" && !run.font) run.font = \"Consolas\";\n if (hasRunProps(run)) {\n w.open(\"w:rPr\");\n writeRunProps(w, run);\n w.close(\"w:rPr\");\n }\n w.close(\"w:style\");\n };\n // Base styles first, so Word never sees a `basedOn` before its target.\n const visit = (style: StyleDefinition, depth = 0) => {\n if (depth > 32 || written.has(style.id)) return;\n const base = style.basedOn ? byId.get(style.basedOn) : undefined;\n if (base) visit(base, depth + 1);\n writeStyle(style);\n };\n byId.forEach((style) => visit(style));\n for (const id of this.extraStyles) {\n if (written.has(id)) continue;\n const extra = EXTRA_STYLES[id] ?? { id, name: id, kind: \"paragraph\" as const, basedOn: NORMAL_STYLE_ID };\n byId.set(id, extra);\n writeStyle(extra);\n }\n w.close(\"w:styles\");\n return w.toString();\n }\n\n settingsXml(): string {\n const w = new XmlWriter();\n w.open(\"w:settings\", BODY_NS).empty(\"w:zoom\", { \"w:percent\": 100 });\n if (this.anonymous) w.empty(\"w:removePersonalInformation\");\n w.val(\"w:defaultTabStop\", 720);\n w.val(\"w:characterSpacingControl\", \"doNotCompress\");\n w.open(\"w:compat\").empty(\"w:compatSetting\", {\n \"w:name\": \"compatibilityMode\",\n \"w:uri\": \"http://schemas.microsoft.com/office/word\",\n \"w:val\": 15,\n });\n w.close(\"w:compat\").close(\"w:settings\");\n return w.toString();\n }\n\n commentParts(): { comments: string; extended: string } | null {\n if (!this.comments.size) return null;\n const w = new XmlWriter();\n const ext = new XmlWriter();\n w.open(\"w:comments\", BODY_NS);\n ext.open(\"w15:commentsEx\", { \"xmlns:w15\": NS.w15, \"xmlns:mc\": NS.mc, \"mc:Ignorable\": \"w15\" });\n for (const entry of this.comments.values()) {\n if (!entry.started) continue;\n const { thread } = entry;\n const parentPara = this.comment(w, entry.ids[0], thread.author, thread.createdAt, thread.body);\n ext.empty(\"w15:commentEx\", { \"w15:paraId\": parentPara, \"w15:done\": thread.resolved ? 1 : 0 });\n this.report.written.comments++;\n thread.replies.forEach((reply, i) => {\n const para = this.comment(w, entry.ids[i + 1], reply.author, reply.createdAt, reply.body);\n ext.empty(\"w15:commentEx\", { \"w15:paraId\": para, \"w15:paraIdParent\": parentPara, \"w15:done\": thread.resolved ? 1 : 0 });\n this.report.written.replies++;\n });\n }\n w.close(\"w:comments\");\n ext.close(\"w15:commentsEx\");\n return { comments: w.toString(), extended: ext.toString() };\n }\n\n private comment(w: XmlWriter, id: number, author: ReviewAuthor | undefined, createdAt: number, body: string): string {\n const name = this.authorName(author?.name, author?.id);\n w.open(\"w:comment\", {\n \"w:id\": id,\n \"w:author\": name,\n \"w:date\": isoDate(createdAt),\n \"w:initials\": this.anonymous ? ANONYMOUS_INITIALS : initialsOf(name),\n });\n const lines = String(body ?? \"\").replace(/\\r\\n?/g, \"\\n\").split(\"\\n\");\n let paraId = \"\";\n lines.forEach((line, i) => {\n const last = i === lines.length - 1;\n if (last) paraId = (this.paraIdCounter++).toString(16).toUpperCase().padStart(8, \"0\");\n w.open(\"w:p\", last ? { \"w14:paraId\": paraId, \"w14:textId\": \"77777777\" } : undefined);\n w.open(\"w:pPr\").val(\"w:pStyle\", \"CommentText\").close(\"w:pPr\");\n if (i === 0) {\n w.open(\"w:r\").open(\"w:rPr\").val(\"w:rStyle\", \"CommentReference\").close(\"w:rPr\").empty(\"w:annotationRef\").close(\"w:r\");\n }\n if (line) w.open(\"w:r\").leaf(\"w:t\", { \"xml:space\": \"preserve\" }, line).close(\"w:r\");\n w.close(\"w:p\");\n });\n w.close(\"w:comment\");\n return paraId;\n }\n\n peopleXml(): string | null {\n if (this.anonymous || !this.people.size) return null;\n const w = new XmlWriter();\n w.open(\"w15:people\", { \"xmlns:w15\": NS.w15, \"xmlns:mc\": NS.mc, \"mc:Ignorable\": \"w15\" });\n for (const [name, id] of this.people) {\n w.open(\"w15:person\", { \"w15:author\": name });\n w.empty(\"w15:presenceInfo\", { \"w15:providerId\": \"None\", \"w15:userId\": id });\n w.close(\"w15:person\");\n }\n w.close(\"w15:people\");\n return w.toString();\n }\n\n coreXml(now: Date): string {\n const w = new XmlWriter();\n w.open(\"cp:coreProperties\", {\n \"xmlns:cp\": \"http://schemas.openxmlformats.org/package/2006/metadata/core-properties\",\n \"xmlns:dc\": \"http://purl.org/dc/elements/1.1/\",\n \"xmlns:dcterms\": \"http://purl.org/dc/terms/\",\n \"xmlns:dcmitype\": \"http://purl.org/dc/dcmitype/\",\n \"xmlns:xsi\": \"http://www.w3.org/2001/XMLSchema-instance\",\n });\n if (this.options.title) w.leaf(\"dc:title\", undefined, this.options.title);\n const creator = this.anonymous ? undefined : this.defaultAuthor?.name;\n if (creator) w.leaf(\"dc:creator\", undefined, creator).leaf(\"cp:lastModifiedBy\", undefined, creator);\n const date = isoDate(now.getTime()) ?? \"2026-01-01T00:00:00Z\";\n w.leaf(\"dcterms:created\", { \"xsi:type\": \"dcterms:W3CDTF\" }, date);\n w.leaf(\"dcterms:modified\", { \"xsi:type\": \"dcterms:W3CDTF\" }, date);\n w.close(\"cp:coreProperties\");\n return w.toString();\n }\n\n /** Assembles every part; `[Content_Types].xml` first. */\n parts(now: Date): DocxPackagePart[] {\n const document = this.documentXml();\n const parts: DocxPackagePart[] = [];\n const overrides: [string, string][] = [];\n const add = (name: string, data: string, contentType: string) => {\n parts.push({ name, data });\n overrides.push([`/${name}`, contentType]);\n };\n this.rels.add(REL.styles, \"styles.xml\");\n this.rels.add(REL.settings, \"settings.xml\");\n const numbering = this.numberingXml();\n if (numbering) this.rels.add(REL.numbering, \"numbering.xml\");\n const comments = this.commentParts();\n if (comments) {\n this.rels.add(REL.comments, \"comments.xml\");\n this.rels.add(REL.commentsExtended, \"commentsExtended.xml\");\n }\n const people = this.peopleXml();\n if (people) this.rels.add(REL.people, \"people.xml\");\n // Styles last: the document and comments decide which extra styles are needed.\n const styles = this.stylesXml();\n\n add(\"word/document.xml\", document, `${CT_WML}document.main+xml`);\n add(\"word/styles.xml\", styles, `${CT_WML}styles+xml`);\n add(\"word/settings.xml\", this.settingsXml(), `${CT_WML}settings+xml`);\n if (numbering) add(\"word/numbering.xml\", numbering, `${CT_WML}numbering+xml`);\n if (comments) {\n add(\"word/comments.xml\", comments.comments, `${CT_WML}comments+xml`);\n add(\"word/commentsExtended.xml\", comments.extended, `${CT_WML}commentsExtended+xml`);\n }\n if (people) add(\"word/people.xml\", people, `${CT_WML}people+xml`);\n parts.push({ name: \"word/_rels/document.xml.rels\", data: this.rels.xml() });\n for (const file of this.media) parts.push({ name: `word/media/${file.name}`, data: file.bytes });\n add(\"docProps/core.xml\", this.coreXml(now), \"application/vnd.openxmlformats-package.core-properties+xml\");\n const app = new XmlWriter();\n app.open(\"Properties\", { xmlns: \"http://schemas.openxmlformats.org/officeDocument/2006/extended-properties\" });\n app.leaf(\"Application\", undefined, \"@pixerate/editor\").close(\"Properties\");\n add(\"docProps/app.xml\", app.toString(), \"application/vnd.openxmlformats-officedocument.extended-properties+xml\");\n\n const root = new Relationships();\n root.add(REL.officeDocument, \"word/document.xml\");\n root.add(REL.core, \"docProps/core.xml\");\n root.add(REL.app, \"docProps/app.xml\");\n\n const types = new XmlWriter();\n types.open(\"Types\", { xmlns: \"http://schemas.openxmlformats.org/package/2006/content-types\" });\n types.empty(\"Default\", { Extension: \"rels\", ContentType: \"application/vnd.openxmlformats-package.relationships+xml\" });\n types.empty(\"Default\", { Extension: \"xml\", ContentType: \"application/xml\" });\n for (const ext of this.mediaTypes) types.empty(\"Default\", { Extension: ext, ContentType: DOCX_IMAGE_CONTENT_TYPES[ext] });\n for (const [name, contentType] of overrides) types.empty(\"Override\", { PartName: name, ContentType: contentType });\n types.close(\"Types\");\n return [\n { name: \"[Content_Types].xml\", data: types.toString() },\n { name: \"_rels/.rels\", data: root.xml() },\n ...parts,\n ];\n }\n}\n\nconst isInlineType = (type: string | undefined) =>\n type === \"hardBreak\" || type === \"image\" || type === \"mention\" || type === \"text\";\n\n/** Styles written when the document uses them but the registry has no definition. */\nconst EXTRA_STYLES: Record<string, StyleDefinition> = {\n BlockText: {\n id: \"BlockText\",\n name: \"Block Text\",\n kind: \"paragraph\",\n basedOn: NORMAL_STYLE_ID,\n paragraph: { indentLeft: \"0.5in\", indentRight: \"0.5in\" },\n character: { italic: true },\n priority: 99,\n builtin: true,\n },\n ListParagraph: {\n id: \"ListParagraph\",\n name: \"List Paragraph\",\n kind: \"paragraph\",\n basedOn: NORMAL_STYLE_ID,\n paragraph: { indentLeft: \"0.5in\" },\n priority: 34,\n quick: true,\n builtin: true,\n },\n Code: {\n id: \"Code\",\n name: \"Code\",\n kind: \"paragraph\",\n basedOn: NORMAL_STYLE_ID,\n block: { type: \"codeBlock\" },\n character: { fontFamily: \"Consolas\", fontSize: \"10pt\" },\n paragraph: { spaceAfter: \"0pt\", lineHeight: \"1\" },\n priority: 30,\n },\n Hyperlink: {\n id: \"Hyperlink\",\n name: \"Hyperlink\",\n kind: \"character\",\n character: { color: \"#0563C1\", underline: true },\n priority: 99,\n hidden: true,\n builtin: true,\n },\n CommentReference: {\n id: \"CommentReference\",\n name: \"annotation reference\",\n kind: \"character\",\n character: { fontSize: \"8pt\" },\n priority: 99,\n hidden: true,\n builtin: true,\n },\n CommentText: {\n id: \"CommentText\",\n name: \"annotation text\",\n kind: \"paragraph\",\n basedOn: NORMAL_STYLE_ID,\n character: { fontSize: \"10pt\" },\n priority: 99,\n hidden: true,\n builtin: true,\n },\n};\nfor (let level = 1; level <= 6; level++) {\n EXTRA_STYLES[`Heading${level}`] = {\n id: `Heading${level}`,\n name: `Heading ${level}`,\n kind: \"paragraph\",\n basedOn: NORMAL_STYLE_ID,\n next: NORMAL_STYLE_ID,\n block: { type: \"heading\", attrs: { level } },\n character: { bold: true },\n priority: 9,\n quick: true,\n builtin: true,\n };\n}\n\nfunction resolveInput(\n input: DocxExportEditorLike | DocxJSONNode,\n options: DocxExportOptions,\n): { doc: DocxJSONNode; options: DocxExportOptions } {\n if (!isEditorLike(input)) return { doc: input, options };\n const storage = (input.storage ?? {}) as any;\n return {\n doc: input.getJSON(),\n options: {\n ...options,\n comments: options.comments !== undefined ? options.comments : (storage.comment?.store ?? null),\n styles: options.styles ?? storage.paragraphStyles?.registry ?? undefined,\n },\n };\n}\n\n/**\n * Builds the package parts of a DOCX file without zipping them (synchronous;\n * useful for inspection and tests). See {@link exportDocx}.\n */\nexport function createDocxParts(\n input: DocxExportEditorLike | DocxJSONNode,\n options: DocxExportOptions = {},\n): { parts: DocxPackagePart[]; report: DocxExportReport } {\n const resolved = resolveInput(input, options);\n const builder = new DocxBuilder(\n resolved.doc ?? { type: \"doc\", content: [] },\n resolved.options,\n threadsOf(resolved.options.comments),\n stylesOf(resolved.options.styles),\n );\n const parts = builder.parts(resolved.options.now?.() ?? new Date());\n return { parts, report: builder.report };\n}\n\n/**\n * Exports an editor (or its JSON) as a Word document. Resolves with the file\n * bytes and a report of what was dropped. Never fetches anything: remote\n * images are skipped (or linked with `remoteImages: \"link\"`).\n */\nexport async function exportDocx(\n input: DocxExportEditorLike | DocxJSONNode,\n options: DocxExportOptions = {},\n): Promise<DocxExportResult> {\n const { parts, report } = createDocxParts(input, options);\n const data = await writeZip(parts as ZipWriteEntry[], { compression: options.compression });\n return { data, report };\n}\n\n/** Like {@link exportDocx}, but resolves with a `Blob` of type {@link DOCX_EXPORT_MIME_TYPE}. */\nexport async function exportDocxBlob(\n input: DocxExportEditorLike | DocxJSONNode,\n options: DocxExportOptions = {},\n): Promise<{ blob: Blob; report: DocxExportReport }> {\n const { data, report } = await exportDocx(input, options);\n return { blob: new Blob([data as BlobPart], { type: DOCX_EXPORT_MIME_TYPE }), report };\n}\n","import {\n exportDocxBlob,\n type DocxExportEditorLike,\n type DocxExportOptions,\n type DocxExportReport,\n type DocxJSONNode,\n} from \"./docx\";\n\n/**\n * Saves a `Blob` as a file through a temporary `<a download>` link. Does\n * nothing (returns `false`) without a DOM.\n */\nexport function downloadBlob(blob: Blob, fileName: string): boolean {\n if (typeof document === \"undefined\" || typeof URL === \"undefined\" || typeof URL.createObjectURL !== \"function\") {\n return false;\n }\n const url = URL.createObjectURL(blob);\n const link = document.createElement(\"a\");\n link.href = url;\n link.download = fileName;\n link.rel = \"noopener\";\n link.style.display = \"none\";\n document.body.appendChild(link);\n link.click();\n link.remove();\n // Revoke after the click has been handled, or some browsers cancel the download.\n setTimeout(() => URL.revokeObjectURL(url), 0);\n return true;\n}\n\n/** `name.docx`, with characters that are invalid in file names replaced. */\nexport function docxFileName(name: string | undefined): string {\n const base = (name ?? \"\")\n .replace(/[\\u0000-\\u001f\\u007f<>:\"/\\\\|?*]+/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim()\n .replace(/\\.docx$/i, \"\")\n .slice(0, 120);\n return `${base || \"document\"}.docx`;\n}\n\nexport interface DocxExportState {\n isExporting: boolean;\n /** Last export error (cleared when a new export starts). */\n error: Error | null;\n /** Report of the most recent successful export. */\n lastReport: DocxExportReport | null;\n}\n\nexport interface DocxExportControllerOptions extends DocxExportOptions {\n /** Download file name (default: `title`, else `document`, plus `.docx`). */\n fileName?: string;\n /** Called after each successful export with its report. */\n onExport?: (report: DocxExportReport, blob: Blob) => void;\n /** Called when an export fails (the error is also kept in the state). */\n onError?: (error: Error) => void;\n}\n\n/**\n * Framework-agnostic state for an \"Export to Word\" button: tracks\n * `isExporting` / `error` / `lastReport` and downloads the `.docx` of the\n * editor returned by `getSource`. React's `useDocxExport` and Svelte's\n * `createDocxExport` wrap it.\n */\nexport class DocxExportController {\n private state: DocxExportState = { isExporting: false, error: null, lastReport: null };\n private readonly listeners = new Set<(state: DocxExportState) => void>();\n private pending = 0;\n\n constructor(\n private readonly getSource: () => DocxExportEditorLike | DocxJSONNode | null | undefined,\n private options: DocxExportControllerOptions = {},\n ) {}\n\n setOptions(options: DocxExportControllerOptions): void {\n this.options = options;\n }\n\n getState = (): DocxExportState => this.state;\n\n subscribe = (listener: (state: DocxExportState) => void): (() => void) => {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n };\n\n private setState(patch: Partial<DocxExportState>): void {\n this.state = { ...this.state, ...patch };\n this.listeners.forEach((listener) => listener(this.state));\n }\n\n /** Builds the `.docx` without downloading it. Resolves with `null` when there is no editor or it fails. */\n async exportBlob(): Promise<{ blob: Blob; report: DocxExportReport } | null> {\n const source = this.getSource();\n if (!source) return null;\n this.pending++;\n this.setState({ isExporting: true, error: null });\n try {\n const { fileName: _fileName, onExport: _onExport, onError: _onError, ...exportOptions } = this.options;\n const result = await exportDocxBlob(source, exportOptions);\n this.setState({ lastReport: result.report });\n this.options.onExport?.(result.report, result.blob);\n return result;\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n this.setState({ error: err });\n if (this.options.onError) this.options.onError(err);\n else console.error(\"[Editor] DOCX export failed:\", err);\n return null;\n } finally {\n this.pending--;\n if (this.pending === 0) this.setState({ isExporting: false });\n }\n }\n\n /** Exports and downloads the document. Resolves with the report, or `null`. */\n async download(fileName?: string): Promise<DocxExportReport | null> {\n const result = await this.exportBlob();\n if (!result) return null;\n downloadBlob(result.blob, docxFileName(fileName ?? this.options.fileName ?? this.options.title));\n return result.report;\n }\n}\n\nexport function createDocxExportController(\n getSource: () => DocxExportEditorLike | DocxJSONNode | null | undefined,\n options?: DocxExportControllerOptions,\n): DocxExportController {\n return new DocxExportController(getSource, options);\n}\n"]}
|