{"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 (const [i, el] of els.entries()) {\n    if (afterLegacy.has(localName(el))) {\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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"}