{"version":3,"file":"workbook-T1Y3lstQ.mjs","names":[],"sources":["../src/workbook/shared-strings.ts","../src/workbook/workbook.ts"],"sourcesContent":["// Shared-strings table read/write.\n//\n// Excel pulls every plain-string cell out of the sheet bodies and into\n// `xl/sharedStrings.xml` so duplicates compress well. The format is a flat list\n// of `<si>` entries, each holding either a single `<t>` (plain text) or a\n// sequence of `<r><rPr/>?<t/></r>` runs (rich text).\n//\n// Rich-text entries are kept as their full `RichText` runs so per-run fonts\n// (bold / italic / colour / size / …) survive the round-trip. Plain strings\n// still dedup against literal text; rich text is kept distinct per-cell\n// (Excel's writer doesn't dedupe rich-text either — formatting equality is\n// rarely worth comparing).\n\nimport type { RichText } from '../cell/rich-text';\nimport { type Color, colorToHex } from '../styles/colors';\nimport { escapeCellString, escapeXmlAttr, escapeXmlText, unescapeCellString } from '../utils/escape';\nimport { OpenXmlSchemaError } from '../utils/exceptions';\nimport { qname, SHEET_MAIN_NS } from '../xml/namespaces';\nimport { parseXml } from '../xml/parser';\nimport { findChild, findChildren, type XmlNode } from '../xml/tree';\n\nconst SST_TAG = `{${SHEET_MAIN_NS}}sst`;\nconst SI_TAG = `{${SHEET_MAIN_NS}}si`;\nconst T_TAG = `{${SHEET_MAIN_NS}}t`;\nconst R_TAG = `{${SHEET_MAIN_NS}}r`;\n\n/** A single SST entry: either a plain string or a rich-text run array. */\nexport type SharedStringEntry = string | { kind: 'rich-text'; runs: RichText };\n\n/**\n * Mutable shared-strings accumulator + lookup table. The same shape is used\n * during read (just populate `entries`) and write (call `addSharedString` from\n * the worksheet writer; emit to bytes at the end).\n */\nexport interface SharedStringsTable {\n  /** Insertion-ordered list of unique entries. */\n  entries: SharedStringEntry[];\n  /** Reverse lookup keyed by literal text — rich-text entries skip this map. */\n  index: Map<string, number>;\n}\n\nexport function makeSharedStrings(): SharedStringsTable {\n  return { entries: [], index: new Map() };\n}\n\n/**\n * Insert a string and return its index. Idempotent: calling with the same value\n * twice gives the same index. Empty strings are deduped just like everything\n * else.\n */\nexport function addSharedString(table: SharedStringsTable, value: string): number {\n  const cached = table.index.get(value);\n  if (cached !== undefined) return cached;\n  const id = table.entries.length;\n  table.entries.push(value);\n  table.index.set(value, id);\n  return id;\n}\n\n/** Look up a shared-string index by its literal text. Returns `undefined` for unknown values. */\nexport function getSharedStringIndex(table: SharedStringsTable, value: string): number | undefined {\n  return table.index.get(value);\n}\n\n/**\n * Read a shared-string by its 0-based index. Returns `undefined` for\n * out-of-range. Rich-text entries surface their concatenated plain text so\n * callers that want only the textual body don't need to know about the\n * discriminated union.\n */\nexport function getSharedStringAt(table: SharedStringsTable, index: number): string | undefined {\n  const entry = table.entries[index];\n  if (entry === undefined) return undefined;\n  if (typeof entry === 'string') return entry;\n  return entry.runs.map((r) => r.text).join('');\n}\n\n/** Number of unique entries in the SST. */\nexport function sharedStringCount(table: SharedStringsTable): number {\n  return table.entries.length;\n}\n\n// ---- read ------------------------------------------------------------------\n\n/** Concatenate every `<t>` text node found inside an arbitrary XmlNode tree. */\nconst collectText = (node: XmlNode): string => {\n  // Most common case: a direct `<si><t>x</t></si>` — bypass the recursion.\n  if (node.children.length === 1) {\n    const only = node.children[0];\n    if (only && only.name === T_TAG) return unescapeCellString(only.text ?? '');\n  }\n  let out = '';\n  for (const child of node.children) {\n    if (child.name === T_TAG) {\n      out += child.text ?? '';\n    } else if (child.name === R_TAG) {\n      const t = findChild(child, T_TAG);\n      if (t?.text) out += t.text;\n    }\n  }\n  return unescapeCellString(out);\n};\n\n/**\n * Parse a `xl/sharedStrings.xml` payload. Returns the table directly (rather\n * than just the array) so the worksheet writer can keep appending to it without\n * rebuilding the index.\n *\n * Rich-text runs are preserved as their full per-run formatting so\n * round-tripping a file with rich text doesn't drop the styling.\n */\nexport function parseSharedStringsXml(bytes: Uint8Array | string): SharedStringsTable {\n  const root = parseXml(bytes);\n  if (root.name !== SST_TAG) {\n    throw new OpenXmlSchemaError(`parseSharedStringsXml: root is \"${root.name}\", expected sst`);\n  }\n  const table = makeSharedStrings();\n  for (const si of findChildren(root, SI_TAG)) {\n    const entry = parseSi(si);\n    // Don't dedup — Excel preserves duplicate `<si>` entries by index, and the\n    // worksheet `t=\"s\"` references depend on slot, not on text equality.\n    const id = table.entries.length;\n    table.entries.push(entry);\n    if (typeof entry === 'string' && !table.index.has(entry)) table.index.set(entry, id);\n  }\n  return table;\n}\n\nconst parseSi = (si: XmlNode): SharedStringEntry => {\n  // Rich-text si has one or more <r> children. Plain si has a single <t>.\n  const runEls = findChildren(si, R_TAG);\n  if (runEls.length > 0) {\n    const runs: Array<{ text: string; font?: import('../cell/rich-text').InlineFont }> = [];\n    for (const rEl of runEls) {\n      const tEl = findChild(rEl, T_TAG);\n      const text = unescapeCellString(tEl?.text ?? '');\n      const rPrEl = findChild(rEl, qname(SHEET_MAIN_NS, 'rPr'));\n      const font = rPrEl ? parseRunPr(rPrEl) : undefined;\n      runs.push(font !== undefined ? { text, font } : { text });\n    }\n    return { kind: 'rich-text', runs: Object.freeze(runs) };\n  }\n  return collectText(si);\n};\n\nconst parseRunPr = (rPr: XmlNode): import('../cell/rich-text').InlineFont | undefined => {\n  type InlineFontMutable = {\n    -readonly [K in keyof import('../cell/rich-text').InlineFont]: import('../cell/rich-text').InlineFont[K];\n  };\n  const f: InlineFontMutable = {};\n  for (const child of rPr.children) {\n    const local = child.name.replace(/^\\{[^}]+\\}/, '');\n    const valAttr = child.attrs['val'];\n    switch (local) {\n      case 'rFont':\n      case 'name':\n        if (valAttr !== undefined) f.name = valAttr;\n        break;\n      case 'sz':\n        if (valAttr !== undefined) f.sz = Number.parseFloat(valAttr);\n        break;\n      case 'b':\n        f.b = valAttr === undefined ? true : valAttr !== '0' && valAttr !== 'false';\n        break;\n      case 'i':\n        f.i = valAttr === undefined ? true : valAttr !== '0' && valAttr !== 'false';\n        break;\n      case 'u': {\n        const v = (valAttr ?? 'single') as import('../cell/rich-text').InlineUnderline;\n        f.u = v;\n        break;\n      }\n      case 'strike':\n        f.strike = valAttr === undefined ? true : valAttr !== '0' && valAttr !== 'false';\n        break;\n      case 'vertAlign':\n        if (valAttr !== undefined) f.vertAlign = valAttr as import('../cell/rich-text').InlineVertAlign;\n        break;\n      case 'family':\n        if (valAttr !== undefined) f.family = Number.parseInt(valAttr, 10);\n        break;\n      case 'charset':\n        if (valAttr !== undefined) f.charset = Number.parseInt(valAttr, 10);\n        break;\n      case 'scheme':\n        if (valAttr !== undefined) f.scheme = valAttr as 'major' | 'minor';\n        break;\n      case 'color': {\n        const c: { rgb?: string; theme?: number; indexed?: number; tint?: number; auto?: boolean } = {};\n        if (child.attrs['rgb'] !== undefined) c.rgb = child.attrs['rgb'];\n        if (child.attrs['theme'] !== undefined) c.theme = Number.parseInt(child.attrs['theme'], 10);\n        if (child.attrs['indexed'] !== undefined) c.indexed = Number.parseInt(child.attrs['indexed'], 10);\n        if (child.attrs['tint'] !== undefined) c.tint = Number.parseFloat(child.attrs['tint']);\n        if (child.attrs['auto'] !== undefined) c.auto = child.attrs['auto'] === '1' || child.attrs['auto'] === 'true';\n        f.color = c as Color;\n        break;\n      }\n    }\n  }\n  return Object.keys(f).length === 0 ? undefined : Object.freeze(f as import('../cell/rich-text').InlineFont);\n};\n\n// ---- write -----------------------------------------------------------------\n\nconst XML_HEADER = '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>';\n\n/**\n * Serialise a SharedStringsTable to its OOXML bytes. The `count` attribute\n * tracks total references (we don't know that here so we report the same as\n * `uniqueCount` — readers tolerate the discrepancy and Excel ignores `count` in\n * practice). `uniqueCount` always matches `entries.length`.\n */\nexport function sharedStringsToBytes(table: SharedStringsTable): Uint8Array {\n  return new TextEncoder().encode(serializeSharedStrings(table));\n}\n\nexport function serializeSharedStrings(table: SharedStringsTable): string {\n  const total = table.entries.length;\n  const parts: string[] = [XML_HEADER, `<sst xmlns=\"${SHEET_MAIN_NS}\" count=\"${total}\" uniqueCount=\"${total}\">`];\n  for (const value of table.entries) {\n    parts.push(serializeSi(value));\n  }\n  parts.push('</sst>');\n  return parts.join('');\n}\n\nconst serializeSi = (value: SharedStringEntry): string => {\n  if (typeof value === 'string') {\n    // Whitespace at either end needs xml:space=\"preserve\" so Excel doesn't\n    // collapse it. Mirrors openpyxl's emitter.\n    const preserve = value.length > 0 && (value[0] === ' ' || value[value.length - 1] === ' ' || /[\\t\\n]/.test(value));\n    const tAttr = preserve ? ' xml:space=\"preserve\"' : '';\n    return `<si><t${tAttr}>${escapeXmlText(escapeCellString(value))}</t></si>`;\n  }\n  return `<si>${serializeRichTextRuns(value.runs)}</si>`;\n};\n\n/**\n * Serialise a sequence of `<r>...<r>` runs — shared by the SST `<si>` writer\n * and the worksheet's inline-string (`t=\"inlineStr\"`) cell writer.\n */\nexport function serializeRichTextRuns(runs: import('../cell/rich-text').RichText): string {\n  const parts: string[] = [];\n  for (const run of runs) {\n    parts.push('<r>');\n    if (run.font) parts.push(serializeInlineFont(run.font));\n    const text = run.text;\n    const preserve = text.length > 0 && (text[0] === ' ' || text[text.length - 1] === ' ' || /[\\t\\n]/.test(text));\n    const tAttr = preserve ? ' xml:space=\"preserve\"' : '';\n    parts.push(`<t${tAttr}>${escapeXmlText(escapeCellString(text))}</t>`);\n    parts.push('</r>');\n  }\n  return parts.join('');\n}\n\nconst serializeInlineFont = (f: import('../cell/rich-text').InlineFont): string => {\n  // Element order per ECMA-376 §17.4.4.10 (CT_RPrElt). Excel's parser is\n  // sensitive to ordering — out-of-order children make the run silently fall\n  // back to the cell's font.\n  const parts: string[] = ['<rPr>'];\n  if (f.name !== undefined) parts.push(`<rFont val=\"${escapeXmlAttr(f.name)}\"/>`);\n  if (f.charset !== undefined) parts.push(`<charset val=\"${f.charset}\"/>`);\n  if (f.family !== undefined) parts.push(`<family val=\"${f.family}\"/>`);\n  if (f.b) parts.push('<b/>');\n  if (f.i) parts.push('<i/>');\n  if (f.strike) parts.push('<strike/>');\n  if (f.outline) parts.push('<outline/>');\n  if (f.shadow) parts.push('<shadow/>');\n  if (f.condense) parts.push('<condense/>');\n  if (f.extend) parts.push('<extend/>');\n  if (f.color) parts.push(serializeRunColor(f.color));\n  if (f.sz !== undefined) parts.push(`<sz val=\"${f.sz}\"/>`);\n  if (f.u) parts.push(`<u val=\"${f.u}\"/>`);\n  if (f.vertAlign) parts.push(`<vertAlign val=\"${f.vertAlign}\"/>`);\n  if (f.scheme) parts.push(`<scheme val=\"${f.scheme}\"/>`);\n  parts.push('</rPr>');\n  return parts.join('');\n};\n\nconst serializeRunColor = (c: Color): string => {\n  const attrs: string[] = [];\n  if (c.rgb !== undefined) attrs.push(`rgb=\"${escapeXmlAttr(c.rgb)}\"`);\n  else if (c.theme !== undefined) attrs.push(`theme=\"${c.theme}\"`);\n  else if (c.indexed !== undefined) attrs.push(`indexed=\"${c.indexed}\"`);\n  else if (c.auto !== undefined) attrs.push(`auto=\"${c.auto ? '1' : '0'}\"`);\n  if (c.tint !== undefined) attrs.push(`tint=\"${c.tint}\"`);\n  // Fallback to colorToHex if nothing was set above (shouldn't happen, but\n  // safe).\n  if (attrs.length === 0) {\n    const hex = colorToHex(c);\n    if (hex !== undefined) attrs.push(`rgb=\"${hex}\"`);\n  }\n  return `<color${attrs.length > 0 ? ` ${attrs.join(' ')}` : ''}/>`;\n};\n","// Workbook root model. / §4.2 / the Workbook is a plain mutable object the user\n// composes via free functions. The Stylesheet pool is held inline so styling\n// operations don't need a side channel.\n\nimport type { Chartsheet } from '../chartsheet/chartsheet';\nimport { makeChartsheet } from '../chartsheet/chartsheet';\nimport { makeAbsoluteAnchor } from '../drawing/anchor';\nimport { type ChartReference, makeChartDrawingItem, makeDrawing } from '../drawing/drawing';\nimport type { CoreProperties } from '../packaging/core';\nimport type { CustomProperties } from '../packaging/custom';\nimport type { ExtendedProperties } from '../packaging/extended';\nimport {\n  getCellAlignment,\n  getCellBorder,\n  getCellFill,\n  getCellFont,\n  getCellNumberFormat,\n  getCellProtection,\n} from '../styles/cell-style';\nimport type { Stylesheet } from '../styles/stylesheet';\nimport { makeStylesheet } from '../styles/stylesheet';\nimport { OpenXmlSchemaError } from '../utils/exceptions';\nimport { type CellValue, isFormulaValue } from '../cell/cell';\nimport type { Alignment } from '../styles/alignment';\nimport type { Border } from '../styles/borders';\nimport type { Fill } from '../styles/fills';\nimport type { Font } from '../styles/fonts';\nimport type { Protection } from '../styles/protection';\nimport { coordinateToTuple, parseSheetRange } from '../utils/coordinate';\nimport { multiCellRangeContainsCell, parseRange, rangeContainsCell, rangeToString } from '../worksheet/cell-range';\nimport type { LegacyComment } from '../worksheet/comments';\nimport type { Hyperlink } from '../worksheet/hyperlinks';\nimport type { CellsByKindCounts, Worksheet } from '../worksheet/worksheet';\nimport {\n  classifyCellValue,\n  countCellsByKind,\n  getCell,\n  getCellComment,\n  getCellHyperlink,\n  getMergedRangeAt,\n  isWorksheetEmpty,\n  makeWorksheet,\n  setCellByCoord,\n} from '../worksheet/worksheet';\n\nexport type SheetState = 'visible' | 'hidden' | 'veryHidden';\n\n/**\n * Discriminated union over the two kinds of sheet a workbook can host. Both\n * variants share `title` (via `sheet.title`) plus the OOXML `sheetId` and\n * `state` attributes; consumers narrow on `kind` to reach the worksheet- vs\n * chartsheet-specific data.\n */\nexport type SheetRef =\n  | { kind: 'worksheet'; sheet: Worksheet; sheetId: number; state: SheetState; rId?: string }\n  | { kind: 'chartsheet'; sheet: Chartsheet; sheetId: number; state: SheetState; rId?: string };\n\nexport interface Workbook {\n  sheets: SheetRef[];\n  /** Index into `sheets` of the sheet shown when Excel opens the file. */\n  activeSheetIndex: number;\n  /** Style pool; cells reference its cellXfs by index. */\n  styles: Stylesheet;\n  /** Date1904 mode toggles between Excel's two epoch systems. */\n  date1904: boolean;\n  /** Document properties (docProps/core.xml), typically auto-filled on save. */\n  properties?: CoreProperties;\n  appProperties?: ExtendedProperties;\n  customProperties?: CustomProperties;\n  /** Author display names, shared between threaded comments. */\n  authors: string[];\n  /** Workbook + sheet-scope defined names (named ranges, print areas etc). */\n  definedNames: import('./defined-names').DefinedName[];\n  /**\n   * Raw `xl/theme/theme1.xml` payload kept verbatim across read → write. The\n   * theme XML is large and seldom edited by writers; we just shuttle it.\n   */\n  themeXml?: Uint8Array;\n  /**\n   * `xl/vbaProject.bin` payload (macro-enabled workbooks). Round-tripped\n   * byte-identical when present; the writer also promotes the workbook Override\n   * to `vnd.ms-excel.sheet.macroEnabled.main+xml`.\n   */\n  vbaProject?: Uint8Array;\n  /** `xl/vbaProjectSignature.bin` payload, when the macros are signed. */\n  vbaSignature?: Uint8Array;\n  /**\n   * Pass-through bytes for parts we don't model (pivot tables, ActiveX\n   * controls, OLE embeddings, customUI ribbons, customXml items …). Keys are\n   * archive-relative paths; values are the raw bytes the loader pulled out of\n   * the zip and the writer pushes back in unchanged.\n   */\n  passthrough?: Map<string, Uint8Array>;\n  /**\n   * Override content type per pass-through path. Excel uses these in\n   * `[Content_Types].xml` so manifest validation stays intact across\n   * round-trips. Paths without an explicit override fall back to the archive\n   * Default extension.\n   */\n  passthroughContentTypes?: Map<string, string>;\n  /**\n   * Top-level `<workbook>` children that aren't `<sheets>` or `<definedNames>`\n   * (e.g. `<fileVersion>`, `<workbookPr>`, `<bookViews>`, `<calcPr>`,\n   * `<pivotCaches>`, `<extLst>`). Captured verbatim so re-saving keeps\n   * Excel-rendering fidelity for things we don't model. Split into the two\n   * halves the writer needs: anything before `<sheets>` is emitted ahead of the\n   * `<sheets>` element, the rest after `<definedNames>`.\n   */\n  workbookXmlExtras?: {\n    beforeSheets: import('../xml/tree').XmlNode[];\n    afterSheets: import('../xml/tree').XmlNode[];\n  };\n  /**\n   * `<workbookProtection>` — locks structure / window / revision tracking with\n   * the modern hash quad or the legacy 16-bit hash. Round-tripped verbatim;\n   * password hashing helpers come later.\n   */\n  workbookProtection?: import('./protection').WorkbookProtection;\n  /**\n   * `<bookViews>` — the workbook's window/tab-strip presets. Most workbooks\n   * have a single entry whose `firstSheet` / `activeTab` drive the tab the user\n   * sees first. Stored as an array because Excel allows multiple views (rare).\n   */\n  bookViews?: import('./views').WorkbookView[];\n  /**\n   * `<customWorkbookViews>` — saved per-user view presets used by the\n   * deprecated \"Shared Workbook\" feature. Each entry carries its own window\n   * position, active sheet, and visibility toggles.\n   */\n  customWorkbookViews?: import('./views').CustomWorkbookView[];\n  /** `<calcPr>` — calculation engine settings (calcMode / iterate / fullPrecision etc.). */\n  calcProperties?: import('./calc-properties').CalcProperties;\n  /** `<fileVersion>` — Office app/version metadata Excel records on save. */\n  fileVersion?: import('./file-version').FileVersion;\n  /** `<fileSharing>` — read-only-recommended toggle + write-protection password. */\n  fileSharing?: import('./file-sharing').FileSharing;\n  /**\n   * `<oleSize ref=\"…\">` — bounding range Excel uses when the workbook is\n   * embedded as an OLE object inside another Office document.\n   */\n  oleSize?: string;\n  /** `<fileRecoveryPr>` — autoRecover-style flags Excel writes after a recovery save. */\n  fileRecoveryPr?: import('./file-recovery').FileRecoveryProperties;\n  /**\n   * `<pivotCaches>` — links from workbook root to xl/pivotCache parts. The\n   * underlying parts survive via the passthrough archive; this typed array\n   * preserves the cacheId ↔ rId mapping for consumers that want to introspect\n   * the pivot links.\n   */\n  pivotCaches?: ReadonlyArray<{ cacheId: number; rId: string }>;\n  /**\n   * `<externalReferences>` — links from workbook root to xl/externalLinks\n   * parts. The numeric token in cross-workbook formulas like `[1]Sheet!A1` is\n   * the 1-based index into this array. Underlying parts continue via\n   * passthrough archive.\n   */\n  externalReferences?: ReadonlyArray<{ rId: string }>;\n  /** `<smartTagPr>` — Excel 2003 smart-tag persistence flags. */\n  smartTagPr?: import('./smart-tags').SmartTagProperties;\n  /** `<smartTagTypes>` — Excel 2003 smart-tag type registrations. */\n  smartTagTypes?: ReadonlyArray<import('./smart-tags').SmartTagType>;\n  /** `<functionGroups>` — built-in + user-defined XLL function groups. */\n  functionGroups?: import('./function-groups').FunctionGroups;\n  /**\n   * `<workbookPr>` — VBA codeName, defaultThemeVersion, link-update prompt\n   * mode, etc. `date1904` is mirrored here for completeness but the canonical\n   * source remains `wb.date1904`.\n   */\n  workbookProperties?: import('./workbook-properties').WorkbookProperties;\n  /**\n   * Workbook-level rels that don't match a modeled type. Re-emitted with their\n   * original Id so captured `<pivotCaches r:id=\"…\"/>` etc. still resolve after\n   * a round-trip.\n   */\n  workbookRelsExtras?: ReadonlyArray<{ id: string; type: string; target: string }>;\n  /**\n   * Original rIds for the modeled non-sheet workbook rels so a captured extras\n   * XML referencing one of them still resolves after re-save.\n   */\n  workbookRelOriginalIds?: {\n    sharedStrings?: string;\n    styles?: string;\n    theme?: string;\n    vbaProject?: string;\n  };\n}\n\n/** Build an empty Workbook ready to host worksheets. */\nexport function createWorkbook(opts?: { date1904?: boolean }): Workbook {\n  return {\n    sheets: [],\n    activeSheetIndex: 0,\n    styles: makeStylesheet(),\n    date1904: opts?.date1904 ?? false,\n    authors: [],\n    definedNames: [],\n  };\n}\n\n/**\n * Validate a sheet title against Excel's character + length rules. Returns the\n * reason string when the title is rejected; `undefined` when valid. The same\n * rules apply to worksheets and chartsheets.\n *\n * Rules:\n *  - Type must be `string`; non-empty; length ≤ 31.\n *  - May not contain any of `:`, `\\`, `/`, `?`, `*`, `[`, `]`.\n *  - May not start or end with an apostrophe `'`.\n *  - May not be the literal `\"History\"` (case-insensitive — Excel\n * reserves that name for the change-tracking sheet).\n *\n * Uniqueness is **not** checked here; pass through `addWorksheet` /\n * `renameSheet` for the workbook-aware duplicate check.\n */\nexport function validateSheetTitle(title: unknown): string | undefined {\n  if (typeof title !== 'string') return 'must be a string';\n  if (title.length === 0) return 'must be 1..31 chars';\n  if (title.length > 31) return 'must be 1..31 chars';\n  if (/[:\\\\/?*[\\]]/.test(title)) return 'must not contain : \\\\ / ? * [ ]';\n  if (title.startsWith(\"'\") || title.endsWith(\"'\")) return 'must not start or end with an apostrophe';\n  if (title.toLowerCase() === 'history') return '\"History\" is reserved by Excel';\n  return undefined;\n}\n\n/** Boolean form of {@link validateSheetTitle}. */\nexport const isValidSheetTitle = (title: unknown): title is string => validateSheetTitle(title) === undefined;\n\n/**\n * Pick a unique sheet title based on `base`. If `base` itself is available,\n * it's returned verbatim. Otherwise the helper appends ` (2)`, ` (3)`, … until\n * it finds a free slot. The returned title always satisfies {@link\n * validateSheetTitle} — if the base+suffix would exceed 31 chars, the base is\n * truncated to fit.\n *\n * Excel treats sheet names as case-insensitive for uniqueness, so `Data` and\n * `data` collide; the helper applies the same rule.\n *\n * Useful for \"duplicate sheet\" / \"import\" flows where you want Excel-like\n * automatic uniqueification (\"Sheet1 (2)\").\n */\nexport function pickUniqueSheetTitle(wb: Workbook, base: string): string {\n  const reason = validateSheetTitle(base);\n  if (reason) {\n    throw new OpenXmlSchemaError(`pickUniqueSheetTitle: base \"${base}\" is not a valid sheet title (${reason})`);\n  }\n  const used = new Set<string>();\n  for (const s of wb.sheets) used.add(s.sheet.title.toLowerCase());\n  if (!used.has(base.toLowerCase())) return base;\n  for (let n = 2; n < 1000; n++) {\n    const suffix = ` (${n})`;\n    const room = 31 - suffix.length;\n    const truncatedBase = base.length > room ? base.slice(0, room) : base;\n    const candidate = `${truncatedBase}${suffix}`;\n    if (!used.has(candidate.toLowerCase())) return candidate;\n  }\n  throw new OpenXmlSchemaError(`pickUniqueSheetTitle: exhausted candidates for \"${base}\"`);\n}\n\n// Excel treats sheet names as case-insensitive for uniqueness — \"Data\" and\n// \"data\" cannot co-exist in the same workbook. `ignoreIndex` lets renameSheet\n// pass its own slot so a case-only rename (\"Data\" → \"data\") still succeeds.\nconst validateUniqueTitle = (wb: Workbook, title: string, ignoreIndex?: number): void => {\n  const reason = validateSheetTitle(title);\n  if (reason) {\n    throw new OpenXmlSchemaError(`Worksheet title \"${title}\": ${reason}`);\n  }\n  const lower = title.toLowerCase();\n  for (let i = 0; i < wb.sheets.length; i++) {\n    if (i === ignoreIndex) continue;\n    const s = wb.sheets[i];\n    if (s && s.sheet.title.toLowerCase() === lower) {\n      throw new OpenXmlSchemaError(`Worksheet title \"${title}\" is already in use`);\n    }\n  }\n};\n\nconst allocateSheetId = (wb: Workbook): number => {\n  // sheetId is 1-based and unique. Allocate the smallest unused integer.\n  const used = new Set<number>();\n  for (const s of wb.sheets) used.add(s.sheetId);\n  let n = 1;\n  while (used.has(n)) n++;\n  return n;\n};\n\n/** Add a Worksheet to the Workbook. Returns the sheet for further population. */\nexport function addWorksheet(wb: Workbook, title: string, opts?: { index?: number; state?: SheetState }): Worksheet {\n  validateUniqueTitle(wb, title);\n  const sheet = makeWorksheet(title);\n  const ref: SheetRef = {\n    kind: 'worksheet',\n    sheet,\n    sheetId: allocateSheetId(wb),\n    state: opts?.state ?? 'visible',\n  };\n  if (opts?.index === undefined) {\n    wb.sheets.push(ref);\n  } else {\n    if (opts.index < 0 || opts.index > wb.sheets.length) {\n      throw new OpenXmlSchemaError(`addWorksheet: index ${opts.index} out of range`);\n    }\n    wb.sheets.splice(opts.index, 0, ref);\n  }\n  return sheet;\n}\n\n/**\n * 0-based tab-strip index of the sheet (worksheet *or* chartsheet) with the\n * given title, or `-1` when not present. Useful when the caller wants to act on\n * the index for `setActiveSheet` / `swapSheets` / similar operations without\n * manually scanning `wb.sheets`.\n */\nexport function getSheetIndex(wb: Workbook, title: string): number {\n  for (let i = 0; i < wb.sheets.length; i++) {\n    const ref = wb.sheets[i];\n    if (ref && ref.sheet.title === title) return i;\n  }\n  return -1;\n}\n\n/**\n * True iff the workbook has a sheet (worksheet *or* chartsheet) with the given\n * title. Thin shortcut over {@link getSheetIndex}.\n */\nexport function hasSheet(wb: Workbook, title: string): boolean {\n  return getSheetIndex(wb, title) >= 0;\n}\n\n/**\n * Count sheets in the workbook, with optional kind/state filters. Mirrors the\n * filter shape of {@link getSheetTitles} but skips the array allocation when\n * the caller only needs the count.\n */\nexport function countSheets(\n  wb: Workbook,\n  opts: { kind?: 'worksheet' | 'chartsheet'; state?: SheetState } = {},\n): number {\n  let n = 0;\n  for (const ref of wb.sheets) {\n    if (opts.kind !== undefined && ref.kind !== opts.kind) continue;\n    if (opts.state !== undefined && ref.state !== opts.state) continue;\n    n++;\n  }\n  return n;\n}\n\n/**\n * Sheet titles in tab-strip order. By default returns titles for every sheet\n * (worksheets + chartsheets). Optional filters narrow to one kind\n * (`'worksheet'` / `'chartsheet'`) or one state (`'visible' | 'hidden' |\n * 'veryHidden'`).\n */\nexport function getSheetTitles(\n  wb: Workbook,\n  opts: { kind?: 'worksheet' | 'chartsheet'; state?: SheetState } = {},\n): string[] {\n  const out: string[] = [];\n  for (const ref of wb.sheets) {\n    if (opts.kind !== undefined && ref.kind !== opts.kind) continue;\n    if (opts.state !== undefined && ref.state !== opts.state) continue;\n    out.push(ref.sheet.title);\n  }\n  return out;\n}\n\n/**\n * True iff the workbook has a **worksheet** (not a chartsheet) with the given\n * title. Distinct from {@link hasSheet} (matches either kind) and {@link\n * hasChartsheet} (chartsheets only).\n */\nexport function hasWorksheet(wb: Workbook, title: string): boolean {\n  return getSheet(wb, title) !== undefined;\n}\n\n/**\n * True iff the workbook has a **chartsheet** (not a worksheet) with the given\n * title. Distinct from {@link hasSheet}, which matches either kind. Use this\n * when the caller needs to discriminate before calling chartsheet-only\n * operations.\n */\nexport function hasChartsheet(wb: Workbook, title: string): boolean {\n  for (const ref of wb.sheets) {\n    if (ref.kind === 'chartsheet' && ref.sheet.title === title) return true;\n  }\n  return false;\n}\n\n/** Look up a Worksheet by title. Returns undefined for missing names or chartsheets. */\nexport function getSheet(wb: Workbook, title: string): Worksheet | undefined {\n  for (const s of wb.sheets) {\n    if (s.kind === 'worksheet' && s.sheet.title === title) return s.sheet;\n  }\n  return undefined;\n}\n\n/** Look up a Worksheet by index in the sheets array. Returns undefined for chartsheet slots. */\nexport function getSheetByIndex(wb: Workbook, idx: number): Worksheet | undefined {\n  const ref = wb.sheets[idx];\n  return ref?.kind === 'worksheet' ? ref.sheet : undefined;\n}\n\n/** Look up a Chartsheet by title. Returns undefined for missing names or worksheets. */\nexport function getChartsheet(wb: Workbook, title: string): Chartsheet | undefined {\n  for (const s of wb.sheets) {\n    if (s.kind === 'chartsheet' && s.sheet.title === title) return s.sheet;\n  }\n  return undefined;\n}\n\n/** Add a Chartsheet to the Workbook. Returns the chartsheet for further population. */\nexport function addChartsheet(\n  wb: Workbook,\n  title: string,\n  opts?: { index?: number; state?: SheetState; chart?: ChartReference },\n): Chartsheet {\n  validateUniqueTitle(wb, title);\n  const cs = makeChartsheet(title);\n  // When the caller supplies a ChartReference, wrap it in a single-anchor\n  // drawing so the writer emits xl/drawings/drawingN.xml + chart part.\n  if (opts?.chart) {\n    // The drawing wraps the chart in a single absoluteAnchor sized to a\n    // standard A4-landscape page (Excel re-flows on open if needed).\n    cs.drawing = makeDrawing([\n      makeChartDrawingItem(makeAbsoluteAnchor({ x: 0, y: 0, cx: 9144000, cy: 6858000 }), opts.chart),\n    ]);\n  }\n  const ref: SheetRef = {\n    kind: 'chartsheet',\n    sheet: cs,\n    sheetId: allocateSheetId(wb),\n    state: opts?.state ?? 'visible',\n  };\n  if (opts?.index === undefined) {\n    wb.sheets.push(ref);\n  } else {\n    if (opts.index < 0 || opts.index > wb.sheets.length) {\n      throw new OpenXmlSchemaError(`addChartsheet: index ${opts.index} out of range`);\n    }\n    wb.sheets.splice(opts.index, 0, ref);\n  }\n  return cs;\n}\n\n/** All worksheet titles, in display order. */\nexport function sheetNames(wb: Workbook): string[] {\n  return wb.sheets.map((s) => s.sheet.title);\n}\n\n/** Remove a sheet by title. No-op if the title is not registered. */\nexport function removeSheet(wb: Workbook, title: string): void {\n  const i = wb.sheets.findIndex((s) => s.sheet.title === title);\n  if (i < 0) return;\n  wb.sheets.splice(i, 1);\n  // Clamp activeSheetIndex within bounds.\n  if (wb.activeSheetIndex >= wb.sheets.length) {\n    wb.activeSheetIndex = Math.max(0, wb.sheets.length - 1);\n  }\n}\n\n/** Set the active sheet by title; throws on unknown title. */\nexport function setActiveSheet(wb: Workbook, title: string): void {\n  const i = wb.sheets.findIndex((s) => s.sheet.title === title);\n  if (i < 0) throw new OpenXmlSchemaError(`setActiveSheet: no sheet named \"${title}\"`);\n  wb.activeSheetIndex = i;\n}\n\n/**\n * Rename a sheet from `oldTitle` to `newTitle`. Throws if no sheet matches\n * `oldTitle`, or if `newTitle` collides with an existing sheet (Excel requires\n * sheet names to be unique within a workbook).\n */\nexport function renameSheet(wb: Workbook, oldTitle: string, newTitle: string): void {\n  const i = wb.sheets.findIndex((s) => s.sheet.title === oldTitle);\n  if (i < 0) throw new OpenXmlSchemaError(`renameSheet: no sheet named \"${oldTitle}\"`);\n  if (oldTitle === newTitle) return;\n  // Excel allows case-only renames (\"Data\" → \"data\"); ignore the current slot\n  // when checking uniqueness so the rename validates against everything else.\n  validateUniqueTitle(wb, newTitle, i);\n  const ref = wb.sheets[i];\n  if (ref) ref.sheet.title = newTitle;\n}\n\n/**\n * Set the visibility state on a sheet by title. Throws on unknown title.\n * Refuses to hide the last visible sheet: an .xlsx with every sheet hidden\n * fails to open in Excel (\"Excel cannot use the object linking and embedding\n * features because no sheet is visible\"). Catching it here keeps the\n * workbook recoverable instead of producing a save Excel will reject.\n */\nexport function setSheetState(wb: Workbook, title: string, state: SheetState): void {\n  const ref = wb.sheets.find((s) => s.sheet.title === title);\n  if (!ref) throw new OpenXmlSchemaError(`setSheetState: no sheet named \"${title}\"`);\n  if (ref.state === state) return;\n  if (state !== 'visible' && ref.state === 'visible') {\n    let otherVisible = false;\n    for (const candidate of wb.sheets) {\n      if (candidate !== ref && candidate.state === 'visible') {\n        otherVisible = true;\n        break;\n      }\n    }\n    if (!otherVisible) {\n      throw new OpenXmlSchemaError(\n        `setSheetState: cannot hide \"${title}\" — it's the last visible sheet,` +\n          ' and Excel refuses to open a workbook with every sheet hidden. Make another sheet' +\n          ' visible first (or call showSheet()).',\n      );\n    }\n  }\n  ref.state = state;\n}\n\n/** Look up the current visibility state. Throws on unknown title. */\nexport function getSheetState(wb: Workbook, title: string): SheetState {\n  const ref = wb.sheets.find((s) => s.sheet.title === title);\n  if (!ref) throw new OpenXmlSchemaError(`getSheetState: no sheet named \"${title}\"`);\n  return ref.state;\n}\n\n/**\n * Hide a sheet (`state: 'hidden'`). Equivalent to right-click → Hide in Excel —\n * the user can re-show it via the Unhide dialog.\n */\nexport function hideSheet(wb: Workbook, title: string): void {\n  setSheetState(wb, title, 'hidden');\n}\n\n/**\n * Mark a sheet as very-hidden (`state: 'veryHidden'`). Excel won't surface it\n * in the Unhide dialog — only reachable via VBA / API.\n */\nexport function veryHideSheet(wb: Workbook, title: string): void {\n  setSheetState(wb, title, 'veryHidden');\n}\n\n/** Make a hidden / veryHidden sheet visible. */\nexport function showSheet(wb: Workbook, title: string): void {\n  setSheetState(wb, title, 'visible');\n}\n\n/**\n * Bulk-update visibility state for many sheets in one call. `entries` is a\n * `Record<title, state>` map; missing titles throw via the underlying\n * `setSheetState`.\n */\nexport function setSheetStates(wb: Workbook, entries: Record<string, SheetState>): void {\n  for (const [title, state] of Object.entries(entries)) {\n    setSheetState(wb, title, state);\n  }\n}\n\n/**\n * Show every hidden / veryHidden worksheet. Returns the count unhidden. Useful\n * for spreadsheet-wide auditing.\n */\nexport function showAllSheets(wb: Workbook): number {\n  let n = 0;\n  for (const ref of wb.sheets) {\n    if (ref.state !== 'visible') {\n      ref.state = 'visible';\n      n++;\n    }\n  }\n  return n;\n}\n\n/**\n * Move a sheet to a new tab-strip position. `toIndex` is clamped to `[0,\n * sheets.length - 1]`. Adjusts `activeSheetIndex` so the same sheet stays\n * active across the move.\n */\nexport function moveSheet(wb: Workbook, title: string, toIndex: number): void {\n  const from = wb.sheets.findIndex((s) => s.sheet.title === title);\n  if (from < 0) throw new OpenXmlSchemaError(`moveSheet: no sheet named \"${title}\"`);\n  if (!Number.isInteger(toIndex)) {\n    throw new OpenXmlSchemaError(`moveSheet: toIndex must be an integer; got ${toIndex}`);\n  }\n  const dest = Math.max(0, Math.min(wb.sheets.length - 1, toIndex));\n  if (from === dest) return;\n  const wasActive = wb.activeSheetIndex === from;\n  const [moved] = wb.sheets.splice(from, 1);\n  if (moved) wb.sheets.splice(dest, 0, moved);\n  if (wasActive) {\n    wb.activeSheetIndex = dest;\n  } else {\n    // Re-index activeSheetIndex if the move shifted it.\n    let cur = wb.activeSheetIndex;\n    if (from < cur) cur -= 1;\n    if (dest <= cur) cur += 1;\n    wb.activeSheetIndex = Math.max(0, Math.min(wb.sheets.length - 1, cur));\n  }\n}\n\n/**\n * Swap the tab-strip positions of two sheets by title. Both titles must exist;\n * throws otherwise. `activeSheetIndex` follows the moved sheet so the same\n * sheet stays active across the swap.\n */\nexport function swapSheets(wb: Workbook, titleA: string, titleB: string): void {\n  const i = wb.sheets.findIndex((s) => s.sheet.title === titleA);\n  const j = wb.sheets.findIndex((s) => s.sheet.title === titleB);\n  if (i < 0) throw new OpenXmlSchemaError(`swapSheets: no sheet named \"${titleA}\"`);\n  if (j < 0) throw new OpenXmlSchemaError(`swapSheets: no sheet named \"${titleB}\"`);\n  if (i === j) return;\n  const a = wb.sheets[i];\n  const b = wb.sheets[j];\n  if (!a || !b) return;\n  wb.sheets[i] = b;\n  wb.sheets[j] = a;\n  if (wb.activeSheetIndex === i) wb.activeSheetIndex = j;\n  else if (wb.activeSheetIndex === j) wb.activeSheetIndex = i;\n}\n\n/**\n * Duplicate a worksheet end-to-end and append it as `newTitle`. Mirrors Excel's\n * \"Move or Copy → Create a copy\" command. Cells, dimensions, styles (via shared\n * cellXf ids), comments, hyperlinks, conditional formatting, page setup, etc.\n * all carry over verbatim — only fields that must stay workbook-unique get\n * rewritten:\n *\n *  - sheet `title` → `newTitle`\n *  - sheet `sheetId` → freshly allocated\n *  - each table's `id` → max(workbook table ids) + 1\n *  - each table's `displayName` → suffixed with `opts.tableSuffix`\n * (default `\"_2\"`) so it doesn't collide with the original\n *\n * The new sheet is inserted at the optional `index` (default: appended).\n */\nexport function duplicateSheet(\n  wb: Workbook,\n  sourceTitle: string,\n  newTitle: string,\n  opts: { index?: number; state?: SheetState; tableSuffix?: string } = {},\n): Worksheet {\n  validateUniqueTitle(wb, newTitle);\n  const sourceRef = wb.sheets.find((s) => s.kind === 'worksheet' && s.sheet.title === sourceTitle);\n  if (!sourceRef || sourceRef.kind !== 'worksheet') {\n    throw new OpenXmlSchemaError(`duplicateSheet: no worksheet named \"${sourceTitle}\"`);\n  }\n  const cloned = structuredClone(sourceRef.sheet);\n  cloned.title = newTitle;\n\n  // Table id + displayName must stay workbook-unique. Walk every other sheet to\n  // find the next free id and renumber/rename in place.\n  const suffix = opts.tableSuffix ?? '_2';\n  let nextTableId = 0;\n  const usedDisplayNames = new Set<string>();\n  for (const s of wb.sheets) {\n    if (s.kind !== 'worksheet') continue;\n    for (const t of s.sheet.tables) {\n      if (t.id > nextTableId) nextTableId = t.id;\n      usedDisplayNames.add(t.displayName);\n    }\n  }\n  for (const t of cloned.tables) {\n    nextTableId += 1;\n    t.id = nextTableId;\n    let candidate = `${t.displayName}${suffix}`;\n    let n = 2;\n    while (usedDisplayNames.has(candidate)) {\n      candidate = `${t.displayName}${suffix}${n}`;\n      n += 1;\n    }\n    t.displayName = candidate;\n    if (t.name === undefined) t.name = candidate;\n    usedDisplayNames.add(candidate);\n  }\n\n  const ref: SheetRef = {\n    kind: 'worksheet',\n    sheet: cloned,\n    sheetId: allocateSheetId(wb),\n    state: opts.state ?? 'visible',\n  };\n  if (opts.index === undefined) {\n    wb.sheets.push(ref);\n  } else {\n    if (opts.index < 0 || opts.index > wb.sheets.length) {\n      throw new OpenXmlSchemaError(`duplicateSheet: index ${opts.index} out of range`);\n    }\n    wb.sheets.splice(opts.index, 0, ref);\n  }\n  return cloned;\n}\n\n/**\n * Aggregate counts about a workbook's content. Useful for quick QA after large\n * mutations or for surfacing a \"what's in this file\" banner. All counts walk\n * the typed model — they do **not** save the workbook to bytes — so the cost is\n * O(workbook content).\n */\nexport interface WorkbookStats {\n  /** Total worksheets (excludes chartsheets). */\n  worksheetCount: number;\n  /** Total chartsheets. */\n  chartsheetCount: number;\n  /** Sum of populated cells across every worksheet. */\n  cellCount: number;\n  /** Sum of formula cells. */\n  formulaCount: number;\n  /** Sum of legacyComments across every worksheet. */\n  commentCount: number;\n  /** Sum of hyperlinks across every worksheet. */\n  hyperlinkCount: number;\n  /** Sum of mergedCells ranges. */\n  mergedRangeCount: number;\n  /** Sum of Excel tables. */\n  tableCount: number;\n  /** Workbook-level defined names. */\n  definedNameCount: number;\n  /** Custom-property entry count, 0 when no docProps/custom.xml. */\n  customPropertyCount: number;\n}\n\nexport function getWorkbookStats(wb: Workbook): WorkbookStats {\n  let worksheetCount = 0;\n  let chartsheetCount = 0;\n  let cellCount = 0;\n  let formulaCount = 0;\n  let commentCount = 0;\n  let hyperlinkCount = 0;\n  let mergedRangeCount = 0;\n  let tableCount = 0;\n  for (const ref of wb.sheets) {\n    if (ref.kind === 'worksheet') {\n      worksheetCount++;\n      const ws = ref.sheet;\n      for (const rowMap of ws.rows.values()) {\n        for (const cell of rowMap.values()) {\n          cellCount++;\n          if (isFormulaValue(cell.value)) formulaCount++;\n        }\n      }\n      commentCount += ws.legacyComments.length;\n      hyperlinkCount += ws.hyperlinks.length;\n      mergedRangeCount += ws.mergedCells.length;\n      tableCount += ws.tables.length;\n    } else {\n      chartsheetCount++;\n    }\n  }\n  return {\n    worksheetCount,\n    chartsheetCount,\n    cellCount,\n    formulaCount,\n    commentCount,\n    hyperlinkCount,\n    mergedRangeCount,\n    tableCount,\n    definedNameCount: wb.definedNames.length,\n    customPropertyCount: wb.customProperties?.properties.length ?? 0,\n  };\n}\n\n/**\n * Workbook-wide value-kind histogram. Sums {@link countCellsByKind} across\n * every Worksheet (chartsheets contribute no cells). Buckets have the same\n * shape as the per-worksheet result; an empty workbook returns all-zero counts.\n */\nexport function getWorkbookCellsByKind(wb: Workbook): CellsByKindCounts {\n  const out: CellsByKindCounts = {\n    null: 0,\n    string: 0,\n    number: 0,\n    boolean: 0,\n    date: 0,\n    duration: 0,\n    error: 0,\n    'rich-text': 0,\n    formula: 0,\n  };\n  for (const ws of iterWorksheets(wb)) {\n    const partial = countCellsByKind(ws);\n    out.null += partial.null;\n    out.string += partial.string;\n    out.number += partial.number;\n    out.boolean += partial.boolean;\n    out.date += partial.date;\n    out.duration += partial.duration;\n    out.error += partial.error;\n    out['rich-text'] += partial['rich-text'];\n    out.formula += partial.formula;\n  }\n  return out;\n}\n\n/**\n * Resolve a sheet-qualified A1 address (`'Sheet1!A1'`) to its Cell, or\n * `undefined` when the cell isn't materialised. Throws on malformed addresses,\n * missing sheets, or range inputs.\n */\nexport function getCellAtAddress(wb: Workbook, address: string): import('../cell/cell').Cell | undefined {\n  const { sheet: sheetTitle, range } = parseSheetRange(address);\n  if (range.includes(':')) {\n    throw new OpenXmlSchemaError(\n      `getCellAtAddress: address \"${address}\" refers to a range, not a single cell`,\n    );\n  }\n  const ws = getSheet(wb, sheetTitle);\n  if (!ws) {\n    throw new OpenXmlSchemaError(`getCellAtAddress: sheet \"${sheetTitle}\" not found`);\n  }\n  const { col, row } = coordinateToTuple(range);\n  return getCell(ws, row, col);\n}\n\n/**\n * Set a single cell by sheet-qualified A1 address. Throws on malformed\n * addresses, missing sheets, or range inputs.\n */\nexport function setCellAtAddress(\n  wb: Workbook,\n  address: string,\n  value: CellValue,\n): import('../cell/cell').Cell {\n  const { sheet: sheetTitle, range } = parseSheetRange(address);\n  if (range.includes(':')) {\n    throw new OpenXmlSchemaError(\n      `setCellAtAddress: address \"${address}\" refers to a range, not a single cell`,\n    );\n  }\n  const ws = getSheet(wb, sheetTitle);\n  if (!ws) {\n    throw new OpenXmlSchemaError(`setCellAtAddress: sheet \"${sheetTitle}\" not found`);\n  }\n  return setCellByCoord(ws, range, value);\n}\n\n/**\n * True iff every Worksheet in the workbook is empty (per {@link\n * isWorksheetEmpty}). Chartsheets carry no cells so they never affect the\n * result. A workbook with zero worksheets is also empty by this definition.\n *\n * Short-circuits on the first non-empty worksheet.\n */\nexport function isWorkbookEmpty(wb: Workbook): boolean {\n  for (const ws of iterWorksheets(wb)) {\n    if (!isWorksheetEmpty(ws)) return false;\n  }\n  return true;\n}\n\n/**\n * Per-sheet entry inside {@link WorkbookOverview}. Holds enough metadata to\n * make a \"what's in this workbook\" panel useful without forcing the caller to\n * walk every worksheet themselves.\n */\nexport interface WorkbookSheetOverview {\n  title: string;\n  kind: 'worksheet' | 'chartsheet';\n  state: SheetState;\n  /** Populated cells in the sheet (0 for chartsheets). */\n  cellCount: number;\n  /** Populated formula cells (0 for chartsheets). */\n  formulaCount: number;\n  /** Tables registered on the sheet. */\n  tableCount: number;\n  /** Drawing items (charts + pictures) on the sheet. */\n  drawingItemCount: number;\n}\n\n/**\n * High-level \"what's in this workbook\" snapshot. Combines the aggregate counts\n * from {@link getWorkbookStats} and value-kind histogram from {@link\n * getWorkbookCellsByKind} with per-sheet metadata. JSON-serialisable; suitable\n * for a UI banner / debug dump.\n */\nexport interface WorkbookOverview {\n  worksheetCount: number;\n  chartsheetCount: number;\n  cellCount: number;\n  formulaCount: number;\n  commentCount: number;\n  hyperlinkCount: number;\n  mergedRangeCount: number;\n  tableCount: number;\n  definedNameCount: number;\n  customPropertyCount: number;\n  cellsByKind: CellsByKindCounts;\n  sheets: WorkbookSheetOverview[];\n}\n\nexport function describeWorkbook(wb: Workbook): WorkbookOverview {\n  // Single-pass aggregation: a cell-by-cell walk dominates this function's\n  // cost on million-cell workbooks, so we compute the workbook stats, the\n  // value-kind histogram, AND each sheet's cell/formula counts in one sweep\n  // instead of triple-scanning.\n  let worksheetCount = 0;\n  let chartsheetCount = 0;\n  let cellCount = 0;\n  let formulaCount = 0;\n  let commentCount = 0;\n  let hyperlinkCount = 0;\n  let mergedRangeCount = 0;\n  let tableCount = 0;\n  const cellsByKind: CellsByKindCounts = {\n    null: 0,\n    string: 0,\n    number: 0,\n    boolean: 0,\n    date: 0,\n    duration: 0,\n    error: 0,\n    'rich-text': 0,\n    formula: 0,\n  };\n  const sheets: WorkbookSheetOverview[] = wb.sheets.map((ref) => {\n    if (ref.kind === 'chartsheet') {\n      chartsheetCount++;\n      return {\n        title: ref.sheet.title,\n        kind: 'chartsheet',\n        state: ref.state,\n        cellCount: 0,\n        formulaCount: 0,\n        tableCount: 0,\n        drawingItemCount: ref.sheet.drawing?.items.length ?? 0,\n      };\n    }\n    worksheetCount++;\n    const ws = ref.sheet;\n    let sheetCellCount = 0;\n    let sheetFormulaCount = 0;\n    for (const rowMap of ws.rows.values()) {\n      for (const cell of rowMap.values()) {\n        sheetCellCount++;\n        const bucket = classifyCellValue(cell.value);\n        cellsByKind[bucket]++;\n        if (isFormulaValue(cell.value)) sheetFormulaCount++;\n      }\n    }\n    cellCount += sheetCellCount;\n    formulaCount += sheetFormulaCount;\n    commentCount += ws.legacyComments.length;\n    hyperlinkCount += ws.hyperlinks.length;\n    mergedRangeCount += ws.mergedCells.length;\n    tableCount += ws.tables.length;\n    return {\n      title: ws.title,\n      kind: 'worksheet',\n      state: ref.state,\n      cellCount: sheetCellCount,\n      formulaCount: sheetFormulaCount,\n      tableCount: ws.tables.length,\n      drawingItemCount: ws.drawing?.items.length ?? 0,\n    };\n  });\n  return {\n    worksheetCount,\n    chartsheetCount,\n    cellCount,\n    formulaCount,\n    commentCount,\n    hyperlinkCount,\n    mergedRangeCount,\n    tableCount,\n    definedNameCount: wb.definedNames.length,\n    customPropertyCount: wb.customProperties?.properties.length ?? 0,\n    cellsByKind,\n    sheets,\n  };\n}\n\n/**\n * Debug-friendly snapshot of everything resolved for a single cell: its value,\n * the full style chain (font / fill / border / alignment / protection /\n * numberFormat), the applied hyperlink + comment, the merged range it sits\n * inside (if any), and the names of any tables / the count of CF / DV blocks\n * that target it.\n *\n * Designed for `console.log`-style introspection — JSON-serialisable and stable\n * in shape regardless of which axes are populated.\n *\n * Throws when `sheetTitle` doesn't resolve. When `ref` is a valid A1 coordinate\n * but no cell exists there, `exists` is `false` and the style chain reflects\n * the workbook defaults.\n */\nexport interface CellSummary {\n  ref: string;\n  sheet: string;\n  exists: boolean;\n  value: CellValue | undefined;\n  styleId: number;\n  font: Font;\n  fill: Fill;\n  border: Border;\n  alignment: Alignment;\n  protection: Protection;\n  numberFormat: string;\n  hyperlink: Hyperlink | undefined;\n  comment: LegacyComment | undefined;\n  mergedRange: string | undefined;\n  inTables: string[];\n  inDataValidations: number;\n  inConditionalFormatting: number;\n}\n\nexport function getCellSummary(wb: Workbook, sheetTitle: string, ref: string): CellSummary {\n  const ws = getSheet(wb, sheetTitle);\n  if (!ws) throw new OpenXmlSchemaError(`getCellSummary: sheet \"${sheetTitle}\" not found`);\n  const { col, row } = coordinateToTuple(ref);\n  const cell = getCell(ws, row, col);\n  // Synthesize a placeholder cell so getCell* helpers can resolve defaults even\n  // for unmaterialised coordinates.\n  const probe = cell ?? { row, col, value: null, styleId: 0 };\n  const merged = getMergedRangeAt(ws, row, col);\n  const inTables: string[] = [];\n  for (const t of ws.tables) {\n    if (rangeContainsCell(parseRange(t.ref), row, col)) inTables.push(t.displayName);\n  }\n  let inDv = 0;\n  for (const dv of ws.dataValidations) {\n    if (multiCellRangeContainsCell(dv.sqref, row, col)) inDv++;\n  }\n  let inCf = 0;\n  for (const cf of ws.conditionalFormatting) {\n    if (multiCellRangeContainsCell(cf.sqref, row, col)) inCf++;\n  }\n  return {\n    ref,\n    sheet: sheetTitle,\n    exists: cell !== undefined,\n    value: cell?.value,\n    styleId: probe.styleId,\n    font: getCellFont(wb, probe),\n    fill: getCellFill(wb, probe),\n    border: getCellBorder(wb, probe),\n    alignment: getCellAlignment(wb, probe),\n    protection: getCellProtection(wb, probe),\n    numberFormat: getCellNumberFormat(wb, probe),\n    hyperlink: cell ? getCellHyperlink(ws, cell) : undefined,\n    comment: cell ? getCellComment(ws, cell) : undefined,\n    mergedRange: merged ? rangeToString(merged) : undefined,\n    inTables,\n    inDataValidations: inDv,\n    inConditionalFormatting: inCf,\n  };\n}\n\n/**\n * Iterate over every Worksheet in the workbook (skips chartsheets). Yields each\n * worksheet in tab-strip order.\n */\nexport function* iterWorksheets(wb: Workbook): IterableIterator<Worksheet> {\n  for (const ref of wb.sheets) {\n    if (ref.kind === 'worksheet') yield ref.sheet;\n  }\n}\n\n/**\n * Iterate only over Worksheets whose tab-strip state is `'visible'`. Hidden /\n * veryHidden sheets are skipped. Useful for reports that should ignore\n * back-office sheets the author has hidden.\n */\nexport function* iterVisibleWorksheets(wb: Workbook): IterableIterator<Worksheet> {\n  for (const ref of wb.sheets) {\n    if (ref.kind === 'worksheet' && ref.state === 'visible') yield ref.sheet;\n  }\n}\n\n/**\n * Iterate Worksheets matching the supplied state. Pass `'hidden'` to skim\n * back-office sheets, `'veryHidden'` to find sheets only accessible via VBA,\n * etc.\n */\nexport function* iterWorksheetsByState(\n  wb: Workbook,\n  state: SheetState,\n): IterableIterator<Worksheet> {\n  for (const ref of wb.sheets) {\n    if (ref.kind === 'worksheet' && ref.state === state) yield ref.sheet;\n  }\n}\n\n/**\n * Iterate every cell across every worksheet in the workbook. Yields `{ sheet,\n * cell }` pairs in tab-strip order, then row-then-column within each sheet.\n * Useful for workbook-wide audits / find-and-replace passes.\n */\nexport function* iterAllCells(\n  wb: Workbook,\n): IterableIterator<{ sheet: Worksheet; cell: import('../cell/cell').Cell }> {\n  for (const sheet of iterWorksheets(wb)) {\n    const rowKeys = [...sheet.rows.keys()].sort((a, b) => a - b);\n    for (const r of rowKeys) {\n      const rowMap = sheet.rows.get(r);\n      if (!rowMap) continue;\n      const cols = [...rowMap.keys()].sort((a, b) => a - b);\n      for (const c of cols) {\n        const cell = rowMap.get(c);\n        if (cell !== undefined) yield { sheet, cell };\n      }\n    }\n  }\n}\n\n/**\n * Collect every merged range across every worksheet. Each entry carries the\n * merge bounds plus a back-reference to the owning sheet, in tab-strip order.\n * Equivalent to walking `iterWorksheets` and concatenating each sheet's\n * `mergedCells`.\n */\nexport function getAllMergedRanges(\n  wb: Workbook,\n): ReadonlyArray<{ sheet: Worksheet; range: import('../worksheet/cell-range').CellRange }> {\n  const out: Array<{ sheet: Worksheet; range: import('../worksheet/cell-range').CellRange }> = [];\n  for (const sheet of iterWorksheets(wb)) {\n    for (const range of sheet.mergedCells) out.push({ sheet, range });\n  }\n  return out;\n}\n\n/**\n * Collect every hyperlink across every worksheet. Each entry pairs the\n * hyperlink with a back-reference to the owning sheet, in tab-strip order.\n */\nexport function getAllHyperlinks(\n  wb: Workbook,\n): ReadonlyArray<{ sheet: Worksheet; hyperlink: import('../worksheet/hyperlinks').Hyperlink }> {\n  const out: Array<{ sheet: Worksheet; hyperlink: import('../worksheet/hyperlinks').Hyperlink }> = [];\n  for (const sheet of iterWorksheets(wb)) {\n    for (const h of sheet.hyperlinks) out.push({ sheet, hyperlink: h });\n  }\n  return out;\n}\n\n/**\n * Collect every legacy comment across every worksheet. Each entry pairs the\n * comment with a back-reference to the owning sheet, in tab-strip order.\n */\nexport function getAllComments(\n  wb: Workbook,\n): ReadonlyArray<{ sheet: Worksheet; comment: import('../worksheet/comments').LegacyComment }> {\n  const out: Array<{ sheet: Worksheet; comment: import('../worksheet/comments').LegacyComment }> = [];\n  for (const sheet of iterWorksheets(wb)) {\n    for (const c of sheet.legacyComments) out.push({ sheet, comment: c });\n  }\n  return out;\n}\n\n/**\n * Collect every Excel table across every worksheet. Each entry pairs the\n * TableDefinition with a back-reference to the owning sheet, in tab-strip\n * order.\n */\nexport function getAllTables(\n  wb: Workbook,\n): ReadonlyArray<{ sheet: Worksheet; table: import('../worksheet/table').TableDefinition }> {\n  const out: Array<{ sheet: Worksheet; table: import('../worksheet/table').TableDefinition }> = [];\n  for (const sheet of iterWorksheets(wb)) {\n    for (const t of sheet.tables) out.push({ sheet, table: t });\n  }\n  return out;\n}\n\n/**\n * Locate an Excel table by `displayName` across the whole workbook. Excel\n * enforces uniqueness at the workbook level, so the first match wins. Returns\n * the owning sheet + the table itself, or `undefined` when nothing matches.\n */\nexport function findTable(\n  wb: Workbook,\n  displayName: string,\n): { sheet: Worksheet; table: import('../worksheet/table').TableDefinition } | undefined {\n  for (const sheet of iterWorksheets(wb)) {\n    for (const t of sheet.tables) {\n      if (t.displayName === displayName) return { sheet, table: t };\n    }\n  }\n  return undefined;\n}\n\n/**\n * First cell across the workbook satisfying `predicate`. Walks every worksheet\n * in tab-strip order, then row-then-column within each sheet (same order as\n * {@link iterAllCells}). Returns `{ sheet, cell }` for the match, or\n * `undefined` when nothing matches.\n */\nexport function findCellInWorkbook(\n  wb: Workbook,\n  predicate: (cell: import('../cell/cell').Cell, sheet: Worksheet) => boolean,\n): { sheet: Worksheet; cell: import('../cell/cell').Cell } | undefined {\n  for (const { sheet, cell } of iterAllCells(wb)) {\n    if (predicate(cell, sheet)) return { sheet, cell };\n  }\n  return undefined;\n}\n\n/**\n * Every cell across the workbook satisfying `predicate`. Same iteration order\n * as {@link iterAllCells}. Returns an array of `{ sheet, cell }` matches.\n */\nexport function findCellsInWorkbook(\n  wb: Workbook,\n  predicate: (cell: import('../cell/cell').Cell, sheet: Worksheet) => boolean,\n): ReadonlyArray<{ sheet: Worksheet; cell: import('../cell/cell').Cell }> {\n  const out: Array<{ sheet: Worksheet; cell: import('../cell/cell').Cell }> = [];\n  for (const { sheet, cell } of iterAllCells(wb)) {\n    if (predicate(cell, sheet)) out.push({ sheet, cell });\n  }\n  return out;\n}\n\n/**\n * Workbook-wide find-and-replace. Same matching rule as `replaceCellValues` but\n * walks every worksheet via {@link iterAllCells}. `search` is either an\n * exact-string match (string-valued cells only) or a predicate `(value, cell,\n * sheet) → boolean`. `replacement` is the new `CellValue`. Returns the count of\n * cells changed across all sheets.\n */\nexport function replaceCellValuesInWorkbook(\n  wb: Workbook,\n  search:\n    | string\n    | ((value: import('../cell/cell').CellValue, cell: import('../cell/cell').Cell, sheet: Worksheet) => boolean),\n  replacement: import('../cell/cell').CellValue,\n): number {\n  let n = 0;\n  const matchFn =\n    typeof search === 'string'\n      ? (v: import('../cell/cell').CellValue) => typeof v === 'string' && v === search\n      : (v: import('../cell/cell').CellValue, c: import('../cell/cell').Cell, s: Worksheet) => search(v, c, s);\n  for (const { sheet, cell } of iterAllCells(wb)) {\n    if (matchFn(cell.value, cell, sheet)) {\n      cell.value = replacement;\n      n++;\n    }\n  }\n  return n;\n}\n\n/**\n * Collect every data-validation block across every worksheet. Each entry pairs\n * the validation with a back-reference to the owning sheet, in tab-strip order.\n */\nexport function getAllDataValidations(\n  wb: Workbook,\n): ReadonlyArray<{ sheet: Worksheet; validation: import('../worksheet/data-validations').DataValidation }> {\n  const out: Array<{\n    sheet: Worksheet;\n    validation: import('../worksheet/data-validations').DataValidation;\n  }> = [];\n  for (const sheet of iterWorksheets(wb)) {\n    for (const v of sheet.dataValidations) out.push({ sheet, validation: v });\n  }\n  return out;\n}\n\n/**\n * Collect every image (picture) DrawingItem across every worksheet, each paired\n * with its owning sheet in tab-strip order.\n */\nexport function getAllImages(\n  wb: Workbook,\n): ReadonlyArray<{ sheet: Worksheet; item: import('../drawing/drawing').DrawingItem }> {\n  const out: Array<{ sheet: Worksheet; item: import('../drawing/drawing').DrawingItem }> = [];\n  for (const sheet of iterWorksheets(wb)) {\n    if (!sheet.drawing) continue;\n    for (const item of sheet.drawing.items) {\n      if (item.content.kind === 'picture') out.push({ sheet, item });\n    }\n  }\n  return out;\n}\n\n/**\n * Collect every chart DrawingItem across every worksheet, each paired with its\n * owning sheet in tab-strip order.\n */\nexport function getAllCharts(\n  wb: Workbook,\n): ReadonlyArray<{ sheet: Worksheet; item: import('../drawing/drawing').DrawingItem }> {\n  const out: Array<{ sheet: Worksheet; item: import('../drawing/drawing').DrawingItem }> = [];\n  for (const sheet of iterWorksheets(wb)) {\n    if (!sheet.drawing) continue;\n    for (const item of sheet.drawing.items) {\n      if (item.content.kind === 'chart') out.push({ sheet, item });\n    }\n  }\n  return out;\n}\n\n/**\n * Collect every conditional-formatting block across every worksheet. Each entry\n * pairs the CF block with a back-reference to the owning sheet, in tab-strip\n * order.\n */\nexport function getAllConditionalFormatting(\n  wb: Workbook,\n): ReadonlyArray<{\n  sheet: Worksheet;\n  formatting: import('../worksheet/conditional-formatting').ConditionalFormatting;\n}> {\n  const out: Array<{\n    sheet: Worksheet;\n    formatting: import('../worksheet/conditional-formatting').ConditionalFormatting;\n  }> = [];\n  for (const sheet of iterWorksheets(wb)) {\n    for (const cf of sheet.conditionalFormatting) out.push({ sheet, formatting: cf });\n  }\n  return out;\n}\n\n/**\n * Iterate over every Chartsheet in the workbook. Yields in tab-strip order,\n * skipping regular worksheets.\n */\nexport function* iterChartsheets(wb: Workbook): IterableIterator<Chartsheet> {\n  for (const ref of wb.sheets) {\n    if (ref.kind === 'chartsheet') yield ref.sheet;\n  }\n}\n\n/** Convenience: array of every Worksheet in tab-strip order. */\nexport function listWorksheets(wb: Workbook): Worksheet[] {\n  return [...iterWorksheets(wb)];\n}\n\n/** Convenience: array of every Chartsheet in tab-strip order. */\nexport function listChartsheets(wb: Workbook): Chartsheet[] {\n  return [...iterChartsheets(wb)];\n}\n\n/** Currently active sheet (worksheet only), or undefined if the active slot is empty or a chartsheet. */\nexport function getActiveSheet(wb: Workbook): Worksheet | undefined {\n  const ref = wb.sheets[wb.activeSheetIndex];\n  return ref?.kind === 'worksheet' ? ref.sheet : undefined;\n}\n\n/**\n * Title of whichever sheet (worksheet *or* chartsheet) is currently marked\n * active via `wb.activeSheetIndex`. Returns `undefined` for an empty workbook\n * or an out-of-range index.\n *\n * Distinct from {@link getActiveSheet} (which only returns worksheets and\n * yields `undefined` when the active slot is a chartsheet) — this matches\n * `wb.activeSheetIndex` regardless of kind.\n */\nexport function getActiveSheetTitle(wb: Workbook): string | undefined {\n  return wb.sheets[wb.activeSheetIndex]?.sheet.title;\n}\n\n/**\n * True iff `title` matches the workbook's currently active sheet (any kind).\n * Empty workbook returns `false` (no active sheet).\n */\nexport function isActiveSheet(wb: Workbook, title: string): boolean {\n  return getActiveSheetTitle(wb) === title;\n}\n\n/** Read-only view onto the customXml/* pass-through parts. */\nexport function listCustomXmlParts(wb: Workbook): Array<{ path: string; content: Uint8Array }> {\n  if (!wb.passthrough) return [];\n  const out: Array<{ path: string; content: Uint8Array }> = [];\n  for (const [path, content] of wb.passthrough) {\n    if (path.startsWith('customXml/')) out.push({ path, content });\n  }\n  return out;\n}\n\n/**\n * JSON.stringify replacer that drops the Stylesheet's internal dedup Maps. Use\n * as `JSON.stringify(workbook, jsonReplacer)` when the workbook needs to\n * round-trip through plain JSON (tests, debug dumps). The dedup maps are\n * reconstructed lazily on first add.\n */\nexport function jsonReplacer(_key: string, value: unknown): unknown {\n  if (value instanceof Map) {\n    return { __map__: [...value.entries()] };\n  }\n  return value;\n}\n\n/** Companion reviver for {@link jsonReplacer}. */\nexport function jsonReviver(_key: string, value: unknown): unknown {\n  if (typeof value === 'object' && value !== null && Array.isArray((value as { __map__?: unknown[] }).__map__)) {\n    return new Map((value as { __map__: Array<[unknown, unknown]> }).__map__);\n  }\n  return value;\n}\n"],"mappings":"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"}