@office-open/xlsx 0.10.5 → 0.10.7

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.
@@ -1 +1 @@
1
- {"version":3,"file":"patch.mjs","names":["buildWorksheetXml"],"sources":["../src/patch.ts"],"sourcesContent":["/**\n * XLSX patching — replace placeholders in existing .xlsx files.\n *\n * Unlike DOCX/PPTX (paragraph-based), XLSX patching targets cell values:\n * - String-valued patches substitute the placeholder text in place (shared\n * strings table or inline strings).\n * - Non-string-valued patches (number / boolean / Date) whose placeholder is\n * the entire cell content rewrite the cell to a typed value with the correct\n * cell type (`t`), so the result is a real number/boolean/date cell — not a\n * stringified copy.\n *\n * @module\n */\nimport {\n OoxmlMimeType,\n appendContentType,\n appendOverride,\n appendRelationship,\n applyCorePropertiesOverride,\n getNextRelationshipIndex,\n nextNumericId,\n strFromU8,\n toJson,\n unzipSync,\n zipAndConvert,\n} from \"@office-open/core\";\nimport type {\n BasePatchOptions,\n CorePropertiesOptions,\n OutputByType,\n OutputType,\n} from \"@office-open/core\";\nimport { toUint8Array } from \"@office-open/core\";\nimport type { ReadContext, WriteContext } from \"@office-open/core/descriptor\";\nimport { js2xml } from \"@office-open/xml\";\nimport type { Element } from \"@office-open/xml\";\nimport { commentsDesc, vmlNotesDesc } from \"@parts/comments\";\nimport { SharedStrings, sharedStringsDesc } from \"@parts/shared-strings\";\nimport { buildWorksheetXml } from \"@parts/worksheet\";\nimport type { CommentOptions, WorksheetOptions } from \"@parts/worksheet\";\n\n/** Reusable TextEncoder (stateless, safe to share). */\nconst encoder = new TextEncoder();\n\n/** Scalar cell value accepted by {@link patchWorkbook}. */\nexport type ScalarValue = string | number | boolean | Date;\n\n/** A patch value is just a scalar. */\nexport type Patch = ScalarValue;\n\nexport interface PatchWorkbookOptions<\n T extends OutputType = OutputType,\n> extends BasePatchOptions<T> {\n /** Placeholder substitutions: `{{key}}` (per delimiters) → value. */\n placeholders?: Readonly<Record<string, ScalarValue>>;\n /** Literal find/replace: the find string → value (no delimiters added). */\n findReplace?: Readonly<Record<string, ScalarValue>>;\n /** Core-properties metadata override (merged over the existing docProps/core.xml). */\n coreProperties?: Partial<CorePropertiesOptions>;\n /**\n * Worksheet collection edits. The shared-strings table is rebuilt from the\n * template first, so appended/replaced worksheets continue indexing strings\n * at the correct offset. Cell styles are not supported on appended rows —\n * reference only styles already present in the template.\n */\n worksheets?: {\n /** Replace worksheets keyed by sheet name (as declared in workbook.xml). */\n replace?: Readonly<Record<string, WorksheetOptions>>;\n /** Append worksheets after the last existing sheet. */\n append?: Readonly<WorksheetOptions[]>;\n };\n /**\n * Cell comments (notes) to append per worksheet. Existing comments on the\n * target worksheet are merged — parsed, extended with the new entries, and\n * re-serialized. Keyed by worksheet name (as declared in workbook.xml).\n */\n comments?: Readonly<Record<string, CommentOptions[]>>;\n}\n\n// Excel serial-date epoch: 1899-12-30 accounts for the spurious 1900 leap year.\nconst EXCEL_EPOCH_MS = Date.UTC(1899, 11, 30);\nconst MS_PER_DAY = 86_400_000;\n\nconst WORKSHEET_CONTENT_TYPE =\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml\";\nconst WORKSHEET_REL_TYPE =\n \"http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet\";\nconst COMMENTS_REL_TYPE =\n \"http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments\";\nconst VML_REL_TYPE =\n \"http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing\";\nconst COMMENTS_CONTENT_TYPE =\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml\";\nconst VML_CONTENT_TYPE = \"application/vnd.openxmlformats-officedocument.vmlDrawing\";\n\n/**\n * sharedStringsDesc.parse ignores its context, but its signature requires a\n * {@link ReadContext}. This stub satisfies the type without pulling in parse\n * machinery the patch path does not need.\n */\nconst STUB_READ_CTX: ReadContext = {\n resolveRelationship: () => undefined,\n getPart: () => undefined,\n getRaw: () => undefined,\n};\n\nconst toExcelSerial = (date: Date): number => (date.getTime() - EXCEL_EPOCH_MS) / MS_PER_DAY;\n\n/** Human-readable form for string-substitution (mixed-text) fallback. */\nconst toDisplayString = (value: Exclude<ScalarValue, string>): string => {\n if (typeof value === \"boolean\") return value ? \"TRUE\" : \"FALSE\";\n if (value instanceof Date) return value.toISOString().split(\"T\")[0];\n return String(value);\n};\n\n/**\n * Patch an existing .xlsx workbook by replacing placeholder text in cells.\n *\n * @publicApi\n */\nexport const patchWorkbook = async <T extends OutputType = OutputType>({\n outputType,\n data,\n placeholders,\n findReplace,\n coreProperties,\n worksheets,\n comments,\n placeholderDelimiters = { start: \"{{\", end: \"}}\" } as const,\n}: PatchWorkbookOptions<T>): Promise<OutputByType[T]> => {\n const { start, end } = placeholderDelimiters;\n if (!start.trim() || !end.trim()) {\n throw new Error(\"Both start and end delimiters must be non-empty strings.\");\n }\n\n const zipContent = unzipSync(toUint8Array(data));\n\n const xmlMap = new Map<string, Element>();\n const binaryMap = new Map<string, Uint8Array>();\n // VML parts are text XML under a .vml extension — kept out of xmlMap (which\n // only holds .xml/.rels) and serialized as raw text at the end.\n const vmlFiles = new Map<string, string>();\n\n // Separate XML files from binary files\n for (const [key, value] of Object.entries(zipContent)) {\n if (key.endsWith(\".xml\") || key.endsWith(\".rels\")) {\n xmlMap.set(key, toJson(strFromU8(value)));\n } else {\n binaryMap.set(key, value);\n }\n }\n\n // Unified patch map: placeholders are delimiter-wrapped, findReplace keys are\n // literal strings. Both feed the same Pass A (typed cells) / Pass B (text) engine.\n const patchMap = new Map<string, ScalarValue>();\n if (placeholders) {\n for (const [key, value] of Object.entries(placeholders)) {\n patchMap.set(`${start}${key}${end}`, value);\n }\n }\n if (findReplace) {\n for (const [key, value] of Object.entries(findReplace)) {\n patchMap.set(key, value);\n }\n }\n\n const sharedStrings = xmlMap.get(\"xl/sharedStrings.xml\");\n const sharedTextByIndex = buildSharedTextIndex(sharedStrings);\n\n const worksheetKeys = Object.keys(zipContent).filter(\n (k) => k.startsWith(\"xl/worksheets/sheet\") && k.endsWith(\".xml\"),\n );\n\n // Pass A: rewrite pure placeholder cells to typed values (number / boolean / Date)\n for (const wsKey of worksheetKeys) {\n const ws = xmlMap.get(wsKey);\n if (ws) rewriteTypedCells(ws, patchMap, sharedTextByIndex);\n }\n\n // Pass B: text substitution in shared strings + inline strings\n // (string-valued patches, plus non-string patches embedded in mixed text)\n if (sharedStrings) patchSharedStrings(sharedStrings, patchMap);\n for (const wsKey of worksheetKeys) {\n const ws = xmlMap.get(wsKey);\n if (!ws) continue;\n patchWorksheetInlineStrings(ws, patchMap);\n // Pass C: print headers/footers (oddHeader/oddFooter/… literal text)\n patchHeaderFooter(ws, patchMap);\n }\n\n // Worksheet collection edits — rebuild shared strings first so appended/\n // replaced worksheets continue indexing at the right offset, then serialize.\n if (worksheets) {\n const sharedStrings = rebuildSharedStrings(xmlMap);\n if (worksheets.replace) {\n for (const [name, wsOpts] of Object.entries(worksheets.replace)) {\n replaceWorksheetInMap(xmlMap, name, wsOpts, sharedStrings);\n }\n }\n if (worksheets.append) {\n for (const wsOpts of worksheets.append) {\n appendWorksheetToMap(xmlMap, wsOpts, sharedStrings);\n }\n }\n rewriteSharedStrings(xmlMap, sharedStrings);\n }\n\n // Cell comments — append per worksheet, merging with any existing comments.\n if (comments) {\n for (const [sheetName, commentOpts] of Object.entries(comments)) {\n appendCommentsToMap(xmlMap, vmlFiles, sheetName, commentOpts);\n }\n }\n\n // Rebuild ZIP\n const files: Record<string, Uint8Array> = {};\n const XML_DECL = '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>';\n for (const [key, value] of xmlMap) {\n files[key] =\n key === \"docProps/core.xml\" && coreProperties\n ? encoder.encode(XML_DECL + applyCorePropertiesOverride(value, coreProperties))\n : encoder.encode(js2xml(value));\n }\n for (const [key, value] of binaryMap) {\n files[key] = value;\n }\n for (const [key, value] of vmlFiles) {\n files[key] = encoder.encode(value);\n }\n\n return await zipAndConvert(files, outputType, OoxmlMimeType.XLSX);\n};\n\n/** Map each `<si>` shared-string index to its flattened text. */\nfunction buildSharedTextIndex(sst: Element | undefined): Map<number, string> {\n const map = new Map<number, string>();\n if (!sst) return map;\n const root = sst.name ? sst : sst.elements?.[0];\n let idx = 0;\n for (const si of root?.elements ?? []) {\n if (si.name !== \"si\") continue;\n map.set(idx, flattenText(si));\n idx++;\n }\n return map;\n}\n\n/**\n * Pass A — for each cell whose entire text is a non-string placeholder, rewrite\n * the cell to a typed value cell (`<v>` with the correct `t`).\n */\nfunction rewriteTypedCells(\n ws: Element,\n patchMap: Map<string, ScalarValue>,\n sharedTextByIndex: Map<number, string>,\n): void {\n const root = ws.name ? ws : ws.elements?.[0];\n const sheetData = root && findLocalChild(root, \"sheetData\");\n if (!sheetData) return;\n\n for (const row of sheetData.elements ?? []) {\n if (localName(row) !== \"row\") continue;\n for (const cell of row.elements ?? []) {\n if (localName(cell) !== \"c\") continue;\n const text = effectiveCellText(cell, sharedTextByIndex);\n if (text === undefined) continue;\n\n for (const [placeholder, value] of patchMap) {\n if (typeof value === \"string\") continue; // Pass B handles string values\n if (text === placeholder) {\n rewriteCellToValue(cell, value);\n break; // a pure cell holds a single placeholder\n }\n }\n }\n }\n}\n\n/** Resolve the displayed text of a string/inline-string cell, else undefined. */\nfunction effectiveCellText(\n cell: Element,\n sharedTextByIndex: Map<number, string>,\n): string | undefined {\n const t = cell.attributes?.[\"t\"];\n if (t === \"inlineStr\") {\n const isEl = findLocalChild(cell, \"is\");\n return isEl ? flattenText(isEl) : undefined;\n }\n if (t === \"s\") {\n const v = findLocalChild(cell, \"v\");\n const raw = v?.elements?.[0]?.text;\n const idx = Number(raw);\n return Number.isNaN(idx) ? undefined : sharedTextByIndex.get(idx);\n }\n return undefined;\n}\n\n/** Rewrite a cell element to a typed value (`<v>` with the correct `t`). */\nfunction rewriteCellToValue(cell: Element, value: Exclude<ScalarValue, string>): void {\n const attrs = cell.attributes ?? (cell.attributes = {});\n let vText: string;\n if (typeof value === \"boolean\") {\n attrs[\"t\"] = \"b\";\n vText = value ? \"1\" : \"0\";\n } else if (value instanceof Date) {\n delete attrs[\"t\"]; // serial date is numeric\n vText = String(toExcelSerial(value));\n } else {\n delete attrs[\"t\"]; // plain numeric\n vText = String(value);\n }\n cell.elements = [{ type: \"element\", name: \"v\", elements: [{ type: \"text\", text: vText }] }];\n}\n\n/** Pass B — substitute placeholders in shared-string `<si>` text. */\nfunction patchSharedStrings(sst: Element, patchMap: Map<string, ScalarValue>): void {\n const root = sst.name ? sst : sst.elements?.[0];\n if (!root) return;\n\n for (const si of root.elements ?? []) {\n if (si.name !== \"si\") continue;\n\n // Simple: <si><t>text</t></si>\n const t = findLocalChild(si, \"t\");\n if (t) {\n patchTextElement(t, patchMap);\n } else {\n // Rich text: <si><r><t>text</t></r>...</si>\n for (const r of si.elements ?? []) {\n if (r.name !== \"r\") continue;\n const rt = findLocalChild(r, \"t\");\n if (rt) patchTextElement(rt, patchMap);\n }\n }\n }\n}\n\n/** Pass B — substitute placeholders in worksheet inline strings. */\nfunction patchWorksheetInlineStrings(ws: Element, patchMap: Map<string, ScalarValue>): void {\n const root = ws.name ? ws : ws.elements?.[0];\n if (!root) return;\n\n const sheetData = findLocalChild(root, \"sheetData\");\n if (!sheetData) return;\n\n for (const row of sheetData.elements ?? []) {\n if (localName(row) !== \"row\") continue;\n for (const cell of row.elements ?? []) {\n if (localName(cell) !== \"c\") continue;\n\n // Inline strings: <c t=\"inlineStr\"><is><t>text</t></is></c>\n const isEl = findLocalChild(cell, \"is\");\n if (isEl) {\n const t = findLocalChild(isEl, \"t\");\n if (t) patchTextElement(t, patchMap);\n }\n }\n }\n}\n\nconst HEADER_FOOTER_NAMES = new Set([\n \"oddHeader\",\n \"oddFooter\",\n \"evenHeader\",\n \"evenFooter\",\n \"firstHeader\",\n \"firstFooter\",\n]);\n\n/**\n * Pass C — substitute placeholders in worksheet print header/footer text.\n * Header/footer children (oddHeader/oddFooter/…) carry their text directly\n * (not wrapped in `<t>`), so this is a substring substitution on the element's\n * own text node.\n */\nfunction patchHeaderFooter(ws: Element, patchMap: Map<string, ScalarValue>): void {\n const root = ws.name ? ws : ws.elements?.[0];\n if (!root) return;\n const headerFooter = findLocalChild(root, \"headerFooter\");\n if (!headerFooter) return;\n\n for (const part of headerFooter.elements ?? []) {\n if (part.type !== \"element\" || !HEADER_FOOTER_NAMES.has(localName(part))) continue;\n const textNode = part.elements?.[0];\n if (!textNode || typeof textNode.text !== \"string\") continue;\n\n let replaced = textNode.text;\n for (const [placeholder, value] of patchMap) {\n if (!replaced.includes(placeholder)) continue;\n const display = typeof value === \"string\" ? value : toDisplayString(value);\n replaced = replaced.split(placeholder).join(display);\n }\n if (replaced !== textNode.text) {\n part.elements![0] = { ...textNode, text: replaced };\n }\n }\n}\n\n/** Substitute any placeholder substring in a `<t>` element's text. */\nfunction patchTextElement(tEl: Element, patchMap: Map<string, ScalarValue>): void {\n const textNode = tEl.elements?.[0];\n const text = textNode?.text;\n if (typeof text !== \"string\") return;\n\n let replaced = text;\n for (const [placeholder, value] of patchMap) {\n if (!replaced.includes(placeholder)) continue;\n const display = typeof value === \"string\" ? value : toDisplayString(value);\n replaced = replaced.split(placeholder).join(display);\n }\n if (replaced !== text && tEl.elements) {\n tEl.elements[0] = { ...textNode, text: replaced };\n }\n}\n\n/** Flatten all descendant text of an element into a single string. */\nfunction flattenText(el: Element): string {\n let out = \"\";\n for (const child of el.elements ?? []) {\n if (child.type === \"text\") {\n out += child.text ?? \"\";\n } else if (child.type === \"element\") {\n out += flattenText(child);\n }\n }\n return out;\n}\n\nfunction localName(el: Element): string {\n const name = el.name ?? \"\";\n const colonIdx = name.indexOf(\":\");\n return colonIdx >= 0 ? name.slice(colonIdx + 1) : name;\n}\n\nfunction findLocalChild(parent: Element, name: string): Element | undefined {\n return (parent.elements ?? []).find((el) => localName(el) === name);\n}\n\n// ── Worksheet collection edits (append / replace) ──\n\n/** Unwrap the document element: a parsed part is `{ declaration, elements: [<root>] }`. */\nfunction rootOf(doc: Element | undefined): Element | undefined {\n return doc && (doc.name ? doc : doc.elements?.[0]);\n}\n\n/** Build a bare element node with the given attributes. */\nfunction makeElement(name: string, attributes: Record<string, string> = {}): Element {\n return { type: \"element\", name, attributes, elements: [] };\n}\n\n/** Empty `<Relationships>` part (wrapped for js2xml serialization). */\nfunction createRelationshipFile(): Element {\n return {\n declaration: { attributes: { encoding: \"UTF-8\", standalone: \"yes\", version: \"1.0\" } },\n elements: [\n {\n attributes: { xmlns: \"http://schemas.openxmlformats.org/package/2006/relationships\" },\n elements: [],\n name: \"Relationships\",\n type: \"element\",\n },\n ],\n };\n}\n\n/** Next 1-based worksheet file number given existing worksheet parts. */\nfunction nextWorksheetNumber(xmlMap: Map<string, Element>): number {\n let maxN = 0;\n for (const key of xmlMap.keys()) {\n const m = key.match(/^xl\\/worksheets\\/sheet(\\d+)\\.xml$/);\n if (m) maxN = Math.max(maxN, Number(m[1]));\n }\n return maxN + 1;\n}\n\n/** Next `sheetId` for an appended `<sheet>` entry. */\nfunction nextSheetId(sheetsEl: Element | undefined): number {\n return nextNumericId(sheetsEl, \"sheet\", \"sheetId\", 0);\n}\n\n/** Resolve a relationship `rId` to its Target via a rels part root. */\nfunction resolveRelTarget(relsRoot: Element | undefined, rId: string): string | undefined {\n for (const child of relsRoot?.elements ?? []) {\n if (localName(child) === \"Relationship\" && String(child.attributes?.[\"Id\"]) === rId) {\n const target = child.attributes?.[\"Target\"];\n return target !== undefined ? String(target) : undefined;\n }\n }\n return undefined;\n}\n\n/** Rebuild the shared-strings table from the template so new sheets extend it. */\nfunction rebuildSharedStrings(xmlMap: Map<string, Element>): SharedStrings {\n const ss = new SharedStrings();\n const sstRoot = rootOf(xmlMap.get(\"xl/sharedStrings.xml\"));\n if (sstRoot) {\n ss.loadEntries(sharedStringsDesc.parse(sstRoot, STUB_READ_CTX).entries);\n }\n return ss;\n}\n\n/** Re-serialize the shared-strings part (called after worksheets are built). */\nfunction rewriteSharedStrings(xmlMap: Map<string, Element>, ss: SharedStrings): void {\n if (ss.count === 0) return;\n xmlMap.set(\n \"xl/sharedStrings.xml\",\n toJson(`<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>${ss.serialize()}`),\n );\n}\n\n/**\n * Append a worksheet: serialize it (registering strings into the shared-strings\n * table), then wire workbook `<sheets>` + workbook rels + content types.\n */\nfunction appendWorksheetToMap(\n xmlMap: Map<string, Element>,\n wsOpts: WorksheetOptions,\n sharedStrings: SharedStrings,\n): void {\n const newN = nextWorksheetNumber(xmlMap);\n const sheetPath = `xl/worksheets/sheet${newN}.xml`;\n const sheetName = wsOpts.name ?? `Sheet${newN}`;\n\n // Worksheet part (no XML declaration — matches generated worksheet parts)\n xmlMap.set(sheetPath, toJson(buildWorksheetXml(wsOpts, { sharedStrings })));\n\n // workbook.xml <sheets> + workbook.xml.rels (the new rId ties them)\n const wbRoot = rootOf(xmlMap.get(\"xl/workbook.xml\"));\n const wbSheets = wbRoot && findLocalChild(wbRoot, \"sheets\");\n const wbRels = xmlMap.get(\"xl/_rels/workbook.xml.rels\") ?? createRelationshipFile();\n xmlMap.set(\"xl/_rels/workbook.xml.rels\", wbRels);\n const newRId = getNextRelationshipIndex(wbRels);\n\n if (wbSheets) {\n const els = wbSheets.elements ?? (wbSheets.elements = []);\n els.push(\n makeElement(\"sheet\", {\n name: sheetName,\n sheetId: String(nextSheetId(wbSheets)),\n \"r:id\": `rId${newRId}`,\n }),\n );\n }\n appendRelationship(wbRels, newRId, WORKSHEET_REL_TYPE, `worksheets/sheet${newN}.xml`);\n\n // [Content_Types].xml Override\n const contentTypes = xmlMap.get(\"[Content_Types].xml\");\n if (contentTypes) {\n appendOverride(contentTypes, `/${sheetPath}`, WORKSHEET_CONTENT_TYPE);\n }\n}\n\n/** Normalize a worksheet name to its full part path via workbook.xml + rels. */\nfunction resolveSheetPath(xmlMap: Map<string, Element>, name: string): string {\n const wbRoot = rootOf(xmlMap.get(\"xl/workbook.xml\"));\n const wbSheets = wbRoot && findLocalChild(wbRoot, \"sheets\");\n const sheetEls = (wbSheets?.elements ?? []).filter((e) => localName(e) === \"sheet\");\n const target = sheetEls.find((e) => String(e.attributes?.[\"name\"]) === name);\n if (!target?.attributes?.[\"r:id\"]) {\n throw new Error(`patchWorkbook: no worksheet named \"${name}\"`);\n }\n const relTarget = resolveRelTarget(\n rootOf(xmlMap.get(\"xl/_rels/workbook.xml.rels\")),\n String(target.attributes[\"r:id\"]),\n );\n if (!relTarget) {\n throw new Error(`patchWorkbook: worksheet \"${name}\" relationship target not found`);\n }\n if (relTarget.startsWith(\"/\")) return relTarget.slice(1);\n return relTarget.startsWith(\"xl/\") ? relTarget : `xl/${relTarget}`;\n}\n\n/**\n * Replace a worksheet by name: resolve the name to its part via workbook rels,\n * then rewrite only that part's content. Sheet identity, rId, and content types\n * are unchanged.\n */\nfunction replaceWorksheetInMap(\n xmlMap: Map<string, Element>,\n name: string,\n wsOpts: WorksheetOptions,\n sharedStrings: SharedStrings,\n): void {\n const sheetPath = resolveSheetPath(xmlMap, name);\n xmlMap.set(sheetPath, toJson(buildWorksheetXml(wsOpts, { sharedStrings })));\n}\n\n/** Build the rels part path for a given part path (…/_rels/<file>.rels). */\nfunction relsKeyFor(partPath: string): string {\n const slash = partPath.lastIndexOf(\"/\");\n return `${partPath.substring(0, slash)}/_rels/${partPath.substring(slash + 1)}.rels`;\n}\n\n/** Find an existing relationship of a type in a rels root: { id, target }. */\nfunction findRelByType(\n relsRoot: Element | undefined,\n type: string,\n): { id: string; target: string } | undefined {\n for (const child of relsRoot?.elements ?? []) {\n if (localName(child) === \"Relationship\" && String(child.attributes?.[\"Type\"]) === type) {\n const target = child.attributes?.[\"Target\"];\n if (target !== undefined) {\n return { id: String(child.attributes?.[\"Id\"]), target: String(target) };\n }\n }\n }\n return undefined;\n}\n\n/** Largest existing comments file number (xl/comments{n}.xml), for append offset. */\nfunction nextCommentsNumber(xmlMap: Map<string, Element>): number {\n let maxN = 0;\n for (const key of xmlMap.keys()) {\n const m = key.match(/^xl\\/comments(\\d+)\\.xml$/);\n if (m) maxN = Math.max(maxN, Number(m[1]));\n }\n return maxN + 1;\n}\n\n/**\n * Insert `<legacyDrawing>` into a worksheet, after `<drawing>` and before the\n * trailing collection elements (CT_Worksheet sequence order). Skipped when one\n * already exists.\n */\nfunction insertLegacyDrawing(wsRoot: Element, rId: string): void {\n const els = wsRoot.elements ?? (wsRoot.elements = []);\n if (els.some((e) => localName(e) === \"legacyDrawing\")) return;\n const legacy = makeElement(\"legacyDrawing\", { \"r:id\": rId });\n const afterLegacy = new Set([\n \"tableParts\",\n \"extLst\",\n \"oleObjects\",\n \"controls\",\n \"picture\",\n \"webPublishItems\",\n ]);\n let insertAt = els.length;\n for (let i = 0; i < els.length; i++) {\n if (afterLegacy.has(localName(els[i]))) {\n insertAt = i;\n break;\n }\n }\n els.splice(insertAt, 0, legacy);\n}\n\n/** commentsDesc.stringify ignores its context; this satisfies the WriteContext type. */\nconst STUB_WRITE_CTX = {} as unknown as WriteContext;\n\n/**\n * Append cell comments to a worksheet, merging with any existing comments part.\n * Wires commentsN.xml + vmlDrawingN.vml (reusing the existing pair when present),\n * the worksheet relationships, the `<legacyDrawing>` anchor, and content types.\n * VML text is written to {@link vmlFiles} (not xmlMap) because of its extension.\n */\nfunction appendCommentsToMap(\n xmlMap: Map<string, Element>,\n vmlFiles: Map<string, string>,\n sheetName: string,\n commentOpts: CommentOptions[],\n): void {\n const sheetPath = resolveSheetPath(xmlMap, sheetName);\n const wsRelsKey = relsKeyFor(sheetPath);\n const wsRels = xmlMap.get(wsRelsKey) ?? createRelationshipFile();\n xmlMap.set(wsRelsKey, wsRels);\n\n // Reuse the worksheet's existing comments/vmlDrawing relationships when present.\n const existingComments = findRelByType(rootOf(wsRels), COMMENTS_REL_TYPE);\n const existingVml = findRelByType(rootOf(wsRels), VML_REL_TYPE);\n\n const commentsN = existingComments\n ? Number((existingComments.target.match(/comments(\\d+)\\.xml$/) ?? [])[1]) ||\n nextCommentsNumber(xmlMap)\n : nextCommentsNumber(xmlMap);\n const commentsPath = `xl/comments${commentsN}.xml`;\n // Reuse the existing vmlDrawing path when present — its index can differ from\n // the comments index in third-party files.\n const vmlPath = existingVml\n ? `xl/drawings/${existingVml.target.slice(existingVml.target.lastIndexOf(\"/\") + 1)}`\n : `xl/drawings/vmlDrawing${commentsN}.vml`;\n\n // Merge with the existing comments part if it was already in the package.\n const existingPart = rootOf(xmlMap.get(commentsPath));\n let merged = commentOpts;\n if (existingPart) {\n merged = [...commentsDesc.parse(existingPart, STUB_READ_CTX).comments, ...commentOpts];\n }\n\n const commentsXml = commentsDesc.stringify({ comments: merged }, STUB_WRITE_CTX);\n if (commentsXml) {\n xmlMap.set(\n commentsPath,\n toJson(`<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>${commentsXml}`),\n );\n }\n const vmlXml = vmlNotesDesc.stringify({ comments: merged }, STUB_WRITE_CTX);\n if (vmlXml) {\n vmlFiles.set(vmlPath, `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>${vmlXml}`);\n }\n\n // Worksheet relationships — added only when the part is newly introduced.\n if (!existingComments) {\n const n = getNextRelationshipIndex(wsRels);\n appendRelationship(wsRels, n, COMMENTS_REL_TYPE, `../comments${commentsN}.xml`);\n }\n let vmlRidRef: string;\n if (existingVml) {\n vmlRidRef = existingVml.id;\n } else {\n const n = getNextRelationshipIndex(wsRels);\n appendRelationship(wsRels, n, VML_REL_TYPE, `../drawings/vmlDrawing${commentsN}.vml`);\n vmlRidRef = `rId${n}`;\n }\n\n // `<legacyDrawing>` anchor on the worksheet (deduped).\n const wsRoot = rootOf(xmlMap.get(sheetPath));\n if (wsRoot) insertLegacyDrawing(wsRoot, vmlRidRef);\n\n // Content types — comments Override (new part only) + vml Default (deduped).\n const contentTypes = xmlMap.get(\"[Content_Types].xml\");\n if (contentTypes) {\n if (!existingPart) {\n appendOverride(contentTypes, `/${commentsPath}`, COMMENTS_CONTENT_TYPE);\n }\n appendContentType(contentTypes, VML_CONTENT_TYPE, \"vml\");\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"patch.mjs","names":["buildWorksheetXml"],"sources":["../src/patch.ts"],"sourcesContent":["/**\n * XLSX patching — replace placeholders in existing .xlsx files.\n *\n * Unlike DOCX/PPTX (paragraph-based), XLSX patching targets cell values:\n * - String-valued patches substitute the placeholder text in place (shared\n * strings table or inline strings).\n * - Non-string-valued patches (number / boolean / Date) whose placeholder is\n * the entire cell content rewrite the cell to a typed value with the correct\n * cell type (`t`), so the result is a real number/boolean/date cell — not a\n * stringified copy.\n *\n * @module\n */\nimport {\n OoxmlMimeType,\n appendContentType,\n appendOverride,\n appendRelationship,\n applyCorePropertiesOverride,\n getNextRelationshipIndex,\n nextNumericId,\n strFromU8,\n toJson,\n unzipSync,\n zipAndConvert,\n} from \"@office-open/core\";\nimport type {\n BasePatchOptions,\n CorePropertiesOptions,\n OutputByType,\n OutputType,\n} from \"@office-open/core\";\nimport { toUint8Array } from \"@office-open/core\";\nimport type { ReadContext, WriteContext } from \"@office-open/core/descriptor\";\nimport { js2xml } from \"@office-open/xml\";\nimport type { Element } from \"@office-open/xml\";\nimport { commentsDesc, vmlNotesDesc } from \"@parts/comments\";\nimport { SharedStrings, sharedStringsDesc } from \"@parts/shared-strings\";\nimport { buildWorksheetXml } from \"@parts/worksheet\";\nimport type { CommentOptions, WorksheetOptions } from \"@parts/worksheet\";\n\n/** Reusable TextEncoder (stateless, safe to share). */\nconst encoder = new TextEncoder();\n\n/** Scalar cell value accepted by {@link patchWorkbook}. */\nexport type ScalarValue = string | number | boolean | Date;\n\n/** A patch value is just a scalar. */\nexport type Patch = ScalarValue;\n\nexport interface PatchWorkbookOptions<\n T extends OutputType = OutputType,\n> extends BasePatchOptions<T> {\n /** Placeholder substitutions: `{{key}}` (per delimiters) → value. */\n placeholders?: Readonly<Record<string, ScalarValue>>;\n /** Literal find/replace: the find string → value (no delimiters added). */\n findReplace?: Readonly<Record<string, ScalarValue>>;\n /** Core-properties metadata override (merged over the existing docProps/core.xml). */\n coreProperties?: Partial<CorePropertiesOptions>;\n /**\n * Worksheet collection edits. The shared-strings table is rebuilt from the\n * template first, so appended/replaced worksheets continue indexing strings\n * at the correct offset. Cell styles are not supported on appended rows —\n * reference only styles already present in the template.\n */\n worksheets?: {\n /** Replace worksheets keyed by sheet name (as declared in workbook.xml). */\n replace?: Readonly<Record<string, WorksheetOptions>>;\n /** Append worksheets after the last existing sheet. */\n append?: Readonly<WorksheetOptions[]>;\n };\n /**\n * Cell comments (notes) to append per worksheet. Existing comments on the\n * target worksheet are merged — parsed, extended with the new entries, and\n * re-serialized. Keyed by worksheet name (as declared in workbook.xml).\n */\n comments?: Readonly<Record<string, CommentOptions[]>>;\n}\n\n// Excel serial-date epoch: 1899-12-30 accounts for the spurious 1900 leap year.\nconst EXCEL_EPOCH_MS = Date.UTC(1899, 11, 30);\nconst MS_PER_DAY = 86_400_000;\n\nconst WORKSHEET_CONTENT_TYPE =\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml\";\nconst WORKSHEET_REL_TYPE =\n \"http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet\";\nconst COMMENTS_REL_TYPE =\n \"http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments\";\nconst VML_REL_TYPE =\n \"http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing\";\nconst COMMENTS_CONTENT_TYPE =\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml\";\nconst VML_CONTENT_TYPE = \"application/vnd.openxmlformats-officedocument.vmlDrawing\";\n\n/**\n * sharedStringsDesc.parse ignores its context, but its signature requires a\n * {@link ReadContext}. This stub satisfies the type without pulling in parse\n * machinery the patch path does not need.\n */\nconst STUB_READ_CTX: ReadContext = {\n resolveRelationship: () => undefined,\n getPart: () => undefined,\n getRaw: () => undefined,\n};\n\nconst toExcelSerial = (date: Date): number => (date.getTime() - EXCEL_EPOCH_MS) / MS_PER_DAY;\n\n/** Human-readable form for string-substitution (mixed-text) fallback. */\nconst toDisplayString = (value: Exclude<ScalarValue, string>): string => {\n if (typeof value === \"boolean\") return value ? \"TRUE\" : \"FALSE\";\n if (value instanceof Date) return value.toISOString().split(\"T\")[0];\n return String(value);\n};\n\n/**\n * Patch an existing .xlsx workbook by replacing placeholder text in cells.\n *\n * @publicApi\n */\nexport const patchWorkbook = async <T extends OutputType = OutputType>({\n outputType,\n data,\n placeholders,\n findReplace,\n coreProperties,\n worksheets,\n comments,\n placeholderDelimiters = { start: \"{{\", end: \"}}\" } as const,\n}: PatchWorkbookOptions<T>): Promise<OutputByType[T]> => {\n const { start, end } = placeholderDelimiters;\n if (!start.trim() || !end.trim()) {\n throw new Error(\"Both start and end delimiters must be non-empty strings.\");\n }\n\n const zipContent = unzipSync(toUint8Array(data));\n\n const xmlMap = new Map<string, Element>();\n const binaryMap = new Map<string, Uint8Array>();\n // VML parts are text XML under a .vml extension — kept out of xmlMap (which\n // only holds .xml/.rels) and serialized as raw text at the end.\n const vmlFiles = new Map<string, string>();\n\n // Separate XML files from binary files\n for (const [key, value] of Object.entries(zipContent)) {\n if (key.endsWith(\".xml\") || key.endsWith(\".rels\")) {\n xmlMap.set(key, toJson(strFromU8(value)));\n } else {\n binaryMap.set(key, value);\n }\n }\n\n // Unified patch map: placeholders are delimiter-wrapped, findReplace keys are\n // literal strings. Both feed the same Pass A (typed cells) / Pass B (text) engine.\n const patchMap = new Map<string, ScalarValue>();\n if (placeholders) {\n for (const [key, value] of Object.entries(placeholders)) {\n patchMap.set(`${start}${key}${end}`, value);\n }\n }\n if (findReplace) {\n for (const [key, value] of Object.entries(findReplace)) {\n patchMap.set(key, value);\n }\n }\n\n const sharedStrings = xmlMap.get(\"xl/sharedStrings.xml\");\n const sharedTextByIndex = buildSharedTextIndex(sharedStrings);\n\n const worksheetKeys = Object.keys(zipContent).filter(\n (k) => k.startsWith(\"xl/worksheets/sheet\") && k.endsWith(\".xml\"),\n );\n\n // Pass A: rewrite pure placeholder cells to typed values (number / boolean / Date)\n for (const wsKey of worksheetKeys) {\n const ws = xmlMap.get(wsKey);\n if (ws) rewriteTypedCells(ws, patchMap, sharedTextByIndex);\n }\n\n // Pass B: text substitution in shared strings + inline strings\n // (string-valued patches, plus non-string patches embedded in mixed text)\n if (sharedStrings) patchSharedStrings(sharedStrings, patchMap);\n for (const wsKey of worksheetKeys) {\n const ws = xmlMap.get(wsKey);\n if (!ws) continue;\n patchWorksheetInlineStrings(ws, patchMap);\n // Pass C: print headers/footers (oddHeader/oddFooter/… literal text)\n patchHeaderFooter(ws, patchMap);\n }\n\n // Worksheet collection edits — rebuild shared strings first so appended/\n // replaced worksheets continue indexing at the right offset, then serialize.\n if (worksheets) {\n const sharedStrings = rebuildSharedStrings(xmlMap);\n if (worksheets.replace) {\n for (const [name, wsOpts] of Object.entries(worksheets.replace)) {\n replaceWorksheetInMap(xmlMap, name, wsOpts, sharedStrings);\n }\n }\n if (worksheets.append) {\n for (const wsOpts of worksheets.append) {\n appendWorksheetToMap(xmlMap, wsOpts, sharedStrings);\n }\n }\n rewriteSharedStrings(xmlMap, sharedStrings);\n }\n\n // Cell comments — append per worksheet, merging with any existing comments.\n if (comments) {\n for (const [sheetName, commentOpts] of Object.entries(comments)) {\n appendCommentsToMap(xmlMap, vmlFiles, sheetName, commentOpts);\n }\n }\n\n // Rebuild ZIP\n const files: Record<string, Uint8Array> = {};\n const XML_DECL = '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>';\n for (const [key, value] of xmlMap) {\n files[key] =\n key === \"docProps/core.xml\" && coreProperties\n ? encoder.encode(XML_DECL + applyCorePropertiesOverride(value, coreProperties))\n : encoder.encode(js2xml(value));\n }\n for (const [key, value] of binaryMap) {\n files[key] = value;\n }\n for (const [key, value] of vmlFiles) {\n files[key] = encoder.encode(value);\n }\n\n return await zipAndConvert(files, outputType, OoxmlMimeType.XLSX);\n};\n\n/** Map each `<si>` shared-string index to its flattened text. */\nfunction buildSharedTextIndex(sst: Element | undefined): Map<number, string> {\n const map = new Map<number, string>();\n if (!sst) return map;\n const root = sst.name ? sst : sst.elements?.[0];\n let idx = 0;\n for (const si of root?.elements ?? []) {\n if (si.name !== \"si\") continue;\n map.set(idx, flattenText(si));\n idx++;\n }\n return map;\n}\n\n/**\n * Pass A — for each cell whose entire text is a non-string placeholder, rewrite\n * the cell to a typed value cell (`<v>` with the correct `t`).\n */\nfunction rewriteTypedCells(\n ws: Element,\n patchMap: Map<string, ScalarValue>,\n sharedTextByIndex: Map<number, string>,\n): void {\n const root = ws.name ? ws : ws.elements?.[0];\n const sheetData = root && findLocalChild(root, \"sheetData\");\n if (!sheetData) return;\n\n for (const row of sheetData.elements ?? []) {\n if (localName(row) !== \"row\") continue;\n for (const cell of row.elements ?? []) {\n if (localName(cell) !== \"c\") continue;\n const text = effectiveCellText(cell, sharedTextByIndex);\n if (text === undefined) continue;\n\n for (const [placeholder, value] of patchMap) {\n if (typeof value === \"string\") continue; // Pass B handles string values\n if (text === placeholder) {\n rewriteCellToValue(cell, value);\n break; // a pure cell holds a single placeholder\n }\n }\n }\n }\n}\n\n/** Resolve the displayed text of a string/inline-string cell, else undefined. */\nfunction effectiveCellText(\n cell: Element,\n sharedTextByIndex: Map<number, string>,\n): string | undefined {\n const t = cell.attributes?.[\"t\"];\n if (t === \"inlineStr\") {\n const isEl = findLocalChild(cell, \"is\");\n return isEl ? flattenText(isEl) : undefined;\n }\n if (t === \"s\") {\n const v = findLocalChild(cell, \"v\");\n const raw = v?.elements?.[0]?.text;\n const idx = Number(raw);\n return Number.isNaN(idx) ? undefined : sharedTextByIndex.get(idx);\n }\n return undefined;\n}\n\n/** Rewrite a cell element to a typed value (`<v>` with the correct `t`). */\nfunction rewriteCellToValue(cell: Element, value: Exclude<ScalarValue, string>): void {\n const attrs = cell.attributes ?? (cell.attributes = {});\n let vText: string;\n if (typeof value === \"boolean\") {\n attrs[\"t\"] = \"b\";\n vText = value ? \"1\" : \"0\";\n } else if (value instanceof Date) {\n delete attrs[\"t\"]; // serial date is numeric\n vText = String(toExcelSerial(value));\n } else {\n delete attrs[\"t\"]; // plain numeric\n vText = String(value);\n }\n cell.elements = [{ type: \"element\", name: \"v\", elements: [{ type: \"text\", text: vText }] }];\n}\n\n/** Pass B — substitute placeholders in shared-string `<si>` text. */\nfunction patchSharedStrings(sst: Element, patchMap: Map<string, ScalarValue>): void {\n const root = sst.name ? sst : sst.elements?.[0];\n if (!root) return;\n\n for (const si of root.elements ?? []) {\n if (si.name !== \"si\") continue;\n\n // Simple: <si><t>text</t></si>\n const t = findLocalChild(si, \"t\");\n if (t) {\n patchTextElement(t, patchMap);\n } else {\n // Rich text: <si><r><t>text</t></r>...</si>\n for (const r of si.elements ?? []) {\n if (r.name !== \"r\") continue;\n const rt = findLocalChild(r, \"t\");\n if (rt) patchTextElement(rt, patchMap);\n }\n }\n }\n}\n\n/** Pass B — substitute placeholders in worksheet inline strings. */\nfunction patchWorksheetInlineStrings(ws: Element, patchMap: Map<string, ScalarValue>): void {\n const root = ws.name ? ws : ws.elements?.[0];\n if (!root) return;\n\n const sheetData = findLocalChild(root, \"sheetData\");\n if (!sheetData) return;\n\n for (const row of sheetData.elements ?? []) {\n if (localName(row) !== \"row\") continue;\n for (const cell of row.elements ?? []) {\n if (localName(cell) !== \"c\") continue;\n\n // Inline strings: <c t=\"inlineStr\"><is><t>text</t></is></c>\n const isEl = findLocalChild(cell, \"is\");\n if (isEl) {\n const t = findLocalChild(isEl, \"t\");\n if (t) patchTextElement(t, patchMap);\n }\n }\n }\n}\n\nconst HEADER_FOOTER_NAMES = new Set([\n \"oddHeader\",\n \"oddFooter\",\n \"evenHeader\",\n \"evenFooter\",\n \"firstHeader\",\n \"firstFooter\",\n]);\n\n/**\n * Pass C — substitute placeholders in worksheet print header/footer text.\n * Header/footer children (oddHeader/oddFooter/…) carry their text directly\n * (not wrapped in `<t>`), so this is a substring substitution on the element's\n * own text node.\n */\nfunction patchHeaderFooter(ws: Element, patchMap: Map<string, ScalarValue>): void {\n const root = ws.name ? ws : ws.elements?.[0];\n if (!root) return;\n const headerFooter = findLocalChild(root, \"headerFooter\");\n if (!headerFooter) return;\n\n for (const part of headerFooter.elements ?? []) {\n if (part.type !== \"element\" || !HEADER_FOOTER_NAMES.has(localName(part))) continue;\n const textNode = part.elements?.[0];\n if (!textNode || typeof textNode.text !== \"string\") continue;\n\n let replaced = textNode.text;\n for (const [placeholder, value] of patchMap) {\n if (!replaced.includes(placeholder)) continue;\n const display = typeof value === \"string\" ? value : toDisplayString(value);\n replaced = replaced.split(placeholder).join(display);\n }\n if (replaced !== textNode.text) {\n part.elements![0] = { ...textNode, text: replaced };\n }\n }\n}\n\n/** Substitute any placeholder substring in a `<t>` element's text. */\nfunction patchTextElement(tEl: Element, patchMap: Map<string, ScalarValue>): void {\n const textNode = tEl.elements?.[0];\n const text = textNode?.text;\n if (typeof text !== \"string\") return;\n\n let replaced = text;\n for (const [placeholder, value] of patchMap) {\n if (!replaced.includes(placeholder)) continue;\n const display = typeof value === \"string\" ? value : toDisplayString(value);\n replaced = replaced.split(placeholder).join(display);\n }\n if (replaced !== text && tEl.elements) {\n tEl.elements[0] = { ...textNode, text: replaced };\n }\n}\n\n/** Flatten all descendant text of an element into a single string. */\nfunction flattenText(el: Element): string {\n let out = \"\";\n for (const child of el.elements ?? []) {\n if (child.type === \"text\") {\n out += child.text ?? \"\";\n } else if (child.type === \"element\") {\n out += flattenText(child);\n }\n }\n return out;\n}\n\nfunction localName(el: Element): string {\n const name = el.name ?? \"\";\n const colonIdx = name.indexOf(\":\");\n return colonIdx >= 0 ? name.slice(colonIdx + 1) : name;\n}\n\nfunction findLocalChild(parent: Element, name: string): Element | undefined {\n return (parent.elements ?? []).find((el) => localName(el) === name);\n}\n\n// ── Worksheet collection edits (append / replace) ──\n\n/** Unwrap the document element: a parsed part is `{ declaration, elements: [<root>] }`. */\nfunction rootOf(doc: Element | undefined): Element | undefined {\n return doc && (doc.name ? doc : doc.elements?.[0]);\n}\n\n/** Build a bare element node with the given attributes. */\nfunction makeElement(name: string, attributes: Record<string, string> = {}): Element {\n return { type: \"element\", name, attributes, elements: [] };\n}\n\n/** Empty `<Relationships>` part (wrapped for js2xml serialization). */\nfunction createRelationshipFile(): Element {\n return {\n declaration: { attributes: { encoding: \"UTF-8\", standalone: \"yes\", version: \"1.0\" } },\n elements: [\n {\n attributes: { xmlns: \"http://schemas.openxmlformats.org/package/2006/relationships\" },\n elements: [],\n name: \"Relationships\",\n type: \"element\",\n },\n ],\n };\n}\n\n/** Next 1-based worksheet file number given existing worksheet parts. */\nfunction nextWorksheetNumber(xmlMap: Map<string, Element>): number {\n let maxN = 0;\n for (const key of xmlMap.keys()) {\n const m = key.match(/^xl\\/worksheets\\/sheet(\\d+)\\.xml$/);\n if (m) maxN = Math.max(maxN, Number(m[1]));\n }\n return maxN + 1;\n}\n\n/** Next `sheetId` for an appended `<sheet>` entry. */\nfunction nextSheetId(sheetsEl: Element | undefined): number {\n return nextNumericId(sheetsEl, \"sheet\", \"sheetId\", 0);\n}\n\n/** Resolve a relationship `rId` to its Target via a rels part root. */\nfunction resolveRelTarget(relsRoot: Element | undefined, rId: string): string | undefined {\n for (const child of relsRoot?.elements ?? []) {\n if (localName(child) === \"Relationship\" && String(child.attributes?.[\"Id\"]) === rId) {\n const target = child.attributes?.[\"Target\"];\n return target !== undefined ? String(target) : undefined;\n }\n }\n return undefined;\n}\n\n/** Rebuild the shared-strings table from the template so new sheets extend it. */\nfunction rebuildSharedStrings(xmlMap: Map<string, Element>): SharedStrings {\n const ss = new SharedStrings();\n const sstRoot = rootOf(xmlMap.get(\"xl/sharedStrings.xml\"));\n if (sstRoot) {\n ss.loadEntries(sharedStringsDesc.parse(sstRoot, STUB_READ_CTX).entries);\n }\n return ss;\n}\n\n/** Re-serialize the shared-strings part (called after worksheets are built). */\nfunction rewriteSharedStrings(xmlMap: Map<string, Element>, ss: SharedStrings): void {\n if (ss.count === 0) return;\n xmlMap.set(\n \"xl/sharedStrings.xml\",\n toJson(`<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>${ss.serialize()}`),\n );\n}\n\n/**\n * Append a worksheet: serialize it (registering strings into the shared-strings\n * table), then wire workbook `<sheets>` + workbook rels + content types.\n */\nfunction appendWorksheetToMap(\n xmlMap: Map<string, Element>,\n wsOpts: WorksheetOptions,\n sharedStrings: SharedStrings,\n): void {\n const newN = nextWorksheetNumber(xmlMap);\n const sheetPath = `xl/worksheets/sheet${newN}.xml`;\n const sheetName = wsOpts.name ?? `Sheet${newN}`;\n\n // Worksheet part (no XML declaration — matches generated worksheet parts)\n xmlMap.set(sheetPath, toJson(buildWorksheetXml(wsOpts, { sharedStrings })));\n\n // workbook.xml <sheets> + workbook.xml.rels (the new rId ties them)\n const wbRoot = rootOf(xmlMap.get(\"xl/workbook.xml\"));\n const wbSheets = wbRoot && findLocalChild(wbRoot, \"sheets\");\n const wbRels = xmlMap.get(\"xl/_rels/workbook.xml.rels\") ?? createRelationshipFile();\n xmlMap.set(\"xl/_rels/workbook.xml.rels\", wbRels);\n const newRId = getNextRelationshipIndex(wbRels);\n\n if (wbSheets) {\n const els = wbSheets.elements ?? (wbSheets.elements = []);\n els.push(\n makeElement(\"sheet\", {\n name: sheetName,\n sheetId: String(nextSheetId(wbSheets)),\n \"r:id\": `rId${newRId}`,\n }),\n );\n }\n appendRelationship(wbRels, newRId, WORKSHEET_REL_TYPE, `worksheets/sheet${newN}.xml`);\n\n // [Content_Types].xml Override\n const contentTypes = xmlMap.get(\"[Content_Types].xml\");\n if (contentTypes) {\n appendOverride(contentTypes, `/${sheetPath}`, WORKSHEET_CONTENT_TYPE);\n }\n}\n\n/** Normalize a worksheet name to its full part path via workbook.xml + rels. */\nfunction resolveSheetPath(xmlMap: Map<string, Element>, name: string): string {\n const wbRoot = rootOf(xmlMap.get(\"xl/workbook.xml\"));\n const wbSheets = wbRoot && findLocalChild(wbRoot, \"sheets\");\n const sheetEls = (wbSheets?.elements ?? []).filter((e) => localName(e) === \"sheet\");\n const target = sheetEls.find((e) => String(e.attributes?.[\"name\"]) === name);\n if (!target?.attributes?.[\"r:id\"]) {\n throw new Error(`patchWorkbook: no worksheet named \"${name}\"`);\n }\n const relTarget = resolveRelTarget(\n rootOf(xmlMap.get(\"xl/_rels/workbook.xml.rels\")),\n String(target.attributes[\"r:id\"]),\n );\n if (!relTarget) {\n throw new Error(`patchWorkbook: worksheet \"${name}\" relationship target not found`);\n }\n if (relTarget.startsWith(\"/\")) return relTarget.slice(1);\n return relTarget.startsWith(\"xl/\") ? relTarget : `xl/${relTarget}`;\n}\n\n/**\n * Replace a worksheet by name: resolve the name to its part via workbook rels,\n * then rewrite only that part's content. Sheet identity, rId, and content types\n * are unchanged.\n */\nfunction replaceWorksheetInMap(\n xmlMap: Map<string, Element>,\n name: string,\n wsOpts: WorksheetOptions,\n sharedStrings: SharedStrings,\n): void {\n const sheetPath = resolveSheetPath(xmlMap, name);\n xmlMap.set(sheetPath, toJson(buildWorksheetXml(wsOpts, { sharedStrings })));\n}\n\n/** Build the rels part path for a given part path (…/_rels/<file>.rels). */\nfunction relsKeyFor(partPath: string): string {\n const slash = partPath.lastIndexOf(\"/\");\n return `${partPath.substring(0, slash)}/_rels/${partPath.substring(slash + 1)}.rels`;\n}\n\n/** Find an existing relationship of a type in a rels root: { id, target }. */\nfunction findRelByType(\n relsRoot: Element | undefined,\n type: string,\n): { id: string; target: string } | undefined {\n for (const child of relsRoot?.elements ?? []) {\n if (localName(child) === \"Relationship\" && String(child.attributes?.[\"Type\"]) === type) {\n const target = child.attributes?.[\"Target\"];\n if (target !== undefined) {\n return { id: String(child.attributes?.[\"Id\"]), target: String(target) };\n }\n }\n }\n return undefined;\n}\n\n/** Largest existing comments file number (xl/comments{n}.xml), for append offset. */\nfunction nextCommentsNumber(xmlMap: Map<string, Element>): number {\n let maxN = 0;\n for (const key of xmlMap.keys()) {\n const m = key.match(/^xl\\/comments(\\d+)\\.xml$/);\n if (m) maxN = Math.max(maxN, Number(m[1]));\n }\n return maxN + 1;\n}\n\n/**\n * Insert `<legacyDrawing>` into a worksheet, after `<drawing>` and before the\n * trailing collection elements (CT_Worksheet sequence order). Skipped when one\n * already exists.\n */\nfunction insertLegacyDrawing(wsRoot: Element, rId: string): void {\n const els = wsRoot.elements ?? (wsRoot.elements = []);\n if (els.some((e) => localName(e) === \"legacyDrawing\")) return;\n const legacy = makeElement(\"legacyDrawing\", { \"r:id\": rId });\n const afterLegacy = new Set([\n \"tableParts\",\n \"extLst\",\n \"oleObjects\",\n \"controls\",\n \"picture\",\n \"webPublishItems\",\n ]);\n let insertAt = els.length;\n for (let i = 0; i < els.length; i++) {\n if (afterLegacy.has(localName(els[i]))) {\n insertAt = i;\n break;\n }\n }\n els.splice(insertAt, 0, legacy);\n}\n\n/** commentsDesc.stringify ignores its context; this satisfies the WriteContext type. */\nconst STUB_WRITE_CTX = {} as unknown as WriteContext;\n\n/**\n * Append cell comments to a worksheet, merging with any existing comments part.\n * Wires commentsN.xml + vmlDrawingN.vml (reusing the existing pair when present),\n * the worksheet relationships, the `<legacyDrawing>` anchor, and content types.\n * VML text is written to {@link vmlFiles} (not xmlMap) because of its extension.\n */\nfunction appendCommentsToMap(\n xmlMap: Map<string, Element>,\n vmlFiles: Map<string, string>,\n sheetName: string,\n commentOpts: CommentOptions[],\n): void {\n const sheetPath = resolveSheetPath(xmlMap, sheetName);\n const wsRelsKey = relsKeyFor(sheetPath);\n const wsRels = xmlMap.get(wsRelsKey) ?? createRelationshipFile();\n xmlMap.set(wsRelsKey, wsRels);\n\n // Reuse the worksheet's existing comments/vmlDrawing relationships when present.\n const existingComments = findRelByType(rootOf(wsRels), COMMENTS_REL_TYPE);\n const existingVml = findRelByType(rootOf(wsRels), VML_REL_TYPE);\n\n const commentsN = existingComments\n ? Number((existingComments.target.match(/comments(\\d+)\\.xml$/) ?? [])[1]) ||\n nextCommentsNumber(xmlMap)\n : nextCommentsNumber(xmlMap);\n const commentsPath = `xl/comments${commentsN}.xml`;\n // Reuse the existing vmlDrawing path when present — its index can differ from\n // the comments index in third-party files.\n const vmlPath = existingVml\n ? `xl/drawings/${existingVml.target.slice(existingVml.target.lastIndexOf(\"/\") + 1)}`\n : `xl/drawings/vmlDrawing${commentsN}.vml`;\n\n // Merge with the existing comments part if it was already in the package.\n const existingPart = rootOf(xmlMap.get(commentsPath));\n let merged = commentOpts;\n if (existingPart) {\n merged = [...commentsDesc.parse(existingPart, STUB_READ_CTX).comments, ...commentOpts];\n }\n\n const commentsXml = commentsDesc.stringify({ comments: merged }, STUB_WRITE_CTX);\n if (commentsXml) {\n xmlMap.set(\n commentsPath,\n toJson(`<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>${commentsXml}`),\n );\n }\n const vmlXml = vmlNotesDesc.stringify({ comments: merged }, STUB_WRITE_CTX);\n if (vmlXml) {\n vmlFiles.set(vmlPath, `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>${vmlXml}`);\n }\n\n // Worksheet relationships — added only when the part is newly introduced.\n if (!existingComments) {\n const n = getNextRelationshipIndex(wsRels);\n appendRelationship(wsRels, n, COMMENTS_REL_TYPE, `../comments${commentsN}.xml`);\n }\n let vmlRidRef: string;\n if (existingVml) {\n vmlRidRef = existingVml.id;\n } else {\n const n = getNextRelationshipIndex(wsRels);\n appendRelationship(wsRels, n, VML_REL_TYPE, `../drawings/vmlDrawing${commentsN}.vml`);\n vmlRidRef = `rId${n}`;\n }\n\n // `<legacyDrawing>` anchor on the worksheet (deduped).\n const wsRoot = rootOf(xmlMap.get(sheetPath));\n if (wsRoot) insertLegacyDrawing(wsRoot, vmlRidRef);\n\n // Content types — comments Override (new part only) + vml Default (deduped).\n const contentTypes = xmlMap.get(\"[Content_Types].xml\");\n if (contentTypes) {\n if (!existingPart) {\n appendOverride(contentTypes, `/${commentsPath}`, COMMENTS_CONTENT_TYPE);\n }\n appendContentType(contentTypes, VML_CONTENT_TYPE, \"vml\");\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@office-open/xlsx",
3
- "version": "0.10.5",
3
+ "version": "0.10.7",
4
4
  "description": "Generate, parse, and patch .xlsx spreadsheets with a declarative TypeScript API",
5
5
  "keywords": [
6
6
  "excel",
@@ -48,8 +48,8 @@
48
48
  }
49
49
  },
50
50
  "dependencies": {
51
- "@office-open/core": "0.10.5",
52
- "@office-open/xml": "0.10.5"
51
+ "@office-open/xml": "0.10.7",
52
+ "@office-open/core": "0.10.7"
53
53
  },
54
54
  "scripts": {
55
55
  "dev": "basis build --stub",