{"version":3,"file":"pivot.cjs","names":["PATH_SEP","MEASURE_SEP","TOTAL_PREFIX","PIVOT_GRAND_TOTAL_KEY","pivotPathKey","path","join","pivotLeafKey","measureKey","pivotTotalLeafKey","resolveAggregateValue","compareValues","PIVOT_GRAND_TOTAL_KEY","pivotLeafKey","pivotPathKey","pivotTotalLeafKey","PIVOT_BLANK","dimensionLabel","value","undefined","String","dimensionOf","row","key","byKey","get","distinctPaths","rows","dimensions","length","paths","level","dimension","entries","next","seen","Map","prefix","slice","map","d","bucket","Set","set","add","path","values","sort","push","columnTreeOf","measures","depth","build","matches","every","i","label","includes","children","span","reduce","sum","child","columnLeavesOf","grandTotals","hasColumnDimensions","leaves","measure","total","cellsOf","covered","columnDimensions","aggregate","format","leaf","matching","filter","result","hiddenByCollapse","collapsed","has","pivot","config","options","columns","column","subtotals","columnPaths","columnLeaves","columnTree","cells","aggregatorOf","body","bodyRows","kind","count","rowDepth","emitted","rowsUnder","Math","max","at","agg","builtInAggregator","name","numbers","summableNumbers","min","Number","isFinite","trim","parsed","n","resolveLabels","measureLabel","PIVOT_ROW_COLUMN_KEY","leafColumnKey","index","String","groupOf","leaf","totalLabel","total","path","length","undefined","textCaptionOf","row","labels","kind","pivotGrandTotal","label","rowHeaderCell","indent","content","depth","paddingInlineStart","pivotTableModel","result","options","fields","renderRowHeader","rowHeader","caption","columns","key","header","pivotRows","accessor","formatValue","columnLeaves","map","measure","group","pivotTotal","align","cells","meta","pivotLeaf","rows","find","filter","rowKey","summaryRow","Object","fromEntries","cell","EMPTY_PIVOT_CONFIG","PATH_SEP","AGGREGATIONS","ROWS","COLUMNS","SUBTOTALS","GRAND_TOTALS","COLLAPSED","OFF","COLLAPSED_PATH_SEP","COLLAPSED_SEP","NOTHING_COLLAPSED","isAggregateName","value","includes","decodeField","decodeURIComponent","encodeCollapsed","key","split","map","encodeURIComponent","join","decodeCollapsed","serializePivotState","state","config","collapsed","parts","rows","length","push","columns","measure","measures","agg","subtotals","grandTotals","folded","filter","deserializePivotState","raw","part","at","indexOf","head","slice","body","undefined","serializePivot","deserializePivot","useCallback","useEffect","useMemo","useRef","useState","useSyncExternalStore","useResolvedAdapter","PARAM_PIVOT","EMPTY_PIVOT_CONFIG","deserializePivotState","serializePivotState","PIVOT_URL_WRITE_DEBOUNCE_MS","NOTHING_COLLAPSED","usePivotUrlState","options","urlAdapter","urlSync","urlKey","defaultConfig","ns","param","resolved","search","onChange","subscribe","getSearch","pending","setPending","flushTimer","state","raw","URLSearchParams","get","config","collapsed","Set","persist","next","params","value","delete","set","setSearch","toString","latest","current","change","clearTimeout","setTimeout","onConfigChange","onCollapsedChange","latestRef","last","write","PIVOT_GRAND_TOTAL_KEY","pivotLeafKey","pivotPathKey","pivotTotalLeafKey","treeOf","paths","measures","depth","build","prefix","level","seen","path","length","every","value","i","label","undefined","includes","push","map","children","span","reduce","sum","child","serverPivotResult","page","config","format","leaves","columns","measure","key","total","columnCells","grandTotals","cellsOf","row","leaf","index","totals","cells","node","body","rows","Math","max","kind","subtotal","at","count","columnTree","columnLeaves","rowDepth"],"sources":["../src/pivot/pivotKeys.ts","../src/pivot/pivotModel.ts","../src/pivot/pivotTableModel.tsx","../src/pivot/pivotUrlCodec.ts","../src/pivot/pivotUrlState.ts","../src/pivot/serverPivot.ts"],"sourcesContent":["/**\n * The separators a pivot's composite keys are built from, and the builders that\n * use them.\n *\n * A dimension label is arbitrary data — a team can be called \"A / B\" or\n * \"Q1-Q2\" — so any printable separator could turn up inside one and split a key\n * in the wrong place. Control characters cannot appear in a rendered label,\n * which makes them the only safe choice; they are written as escapes so they\n * are visible in this file rather than invisible in it.\n *\n * They live in a module of their own because three files build or read the same\n * keys: the local engine, the server translator whose keys must match it\n * exactly, and the URL codec, which takes a collapse key apart to write it into\n * a link. Kept private to one of those files, the bytes get copied into the\n * others as literal characters — and a source file carrying a raw NUL is a file\n * git treats as binary: no diff, no blame, nothing to review.\n *\n * Nothing here is exported from an entry point. What a key looks like inside is\n * not a promise to anyone; `PIVOT_GRAND_TOTAL_KEY` is the one value a host\n * compares against, and it is re-exported from the engine.\n */\n\n/** Between the values of one dimension path. */\nexport const PATH_SEP = \"\\u0000\";\n/** Between a column path and the measure rendered in it. */\nexport const MEASURE_SEP = \"\\u0001\";\n/** In front of a key that stands for a total rather than a real path. */\nexport const TOTAL_PREFIX = \"\\u0002\";\n\n/** The key of the grand-total line, distinct from every real row path. */\nexport const PIVOT_GRAND_TOTAL_KEY = `${TOTAL_PREFIX}grand`;\n\n/** A stable key for a dimension path. */\nexport function pivotPathKey(path: readonly string[]): string {\n  return path.join(PATH_SEP);\n}\n\n/** A rendered column's key: where it sits, and what it shows. */\nexport function pivotLeafKey(\n  path: readonly string[],\n  measureKey: string\n): string {\n  return `${pivotPathKey(path)}${MEASURE_SEP}${measureKey}`;\n}\n\n/** The grand-total column's key for one measure. */\nexport function pivotTotalLeafKey(measureKey: string): string {\n  return `${TOTAL_PREFIX}total${MEASURE_SEP}${measureKey}`;\n}\n","/**\n * The pivot engine: rows down the side, dimensions across the top, a measure\n * in every cell.\n *\n * A pivot is the one table shape a data grid cannot fake. Grouping answers\n * \"what are the totals per team\"; a pivot answers \"what are the totals per\n * team **per quarter**\", and the second dimension has to become columns that\n * did not exist in the data. Everything downstream — the header tree, the\n * subtotals, the collapse state — follows from that one move.\n *\n * This module is the whole calculation and none of the rendering. It takes\n * rows and a configuration and returns a flat list of lines with a depth and\n * a kind, plus the column tree they line up against. An adapter renders that\n * with its own table markup; nothing here knows what a `<td>` is.\n *\n * Three decisions worth stating, because they are the ones a reader will\n * check:\n *\n * Subtotals are **header** rows, not footers. That is what makes collapsing\n * work: a collapsed group still shows its own line with its own totals,\n * rather than vanishing or leaving a footer with nothing above it. It also\n * matches how grouping already reads in this table, where the aggregates sit\n * in the group header.\n *\n * Values resolve through `resolveAggregateValue`, so a column's `sortValue`\n * decides what gets aggregated — exactly as it does for sorting, grouping and\n * the summary row. A pivot that read raw fields would disagree with the\n * footer of the same table.\n *\n * A missing dimension value is its own bucket, labelled by\n * {@link PIVOT_BLANK}, rather than being dropped. Rows that fall in no column\n * silently disappearing is how a pivot table lies about a total.\n */\nimport type { ReactNode } from \"react\";\n\nimport {\n  type AggregateName,\n  type Aggregator,\n  resolveAggregateValue,\n} from \"../aggregate/aggregate\";\nimport { compareValues } from \"../sort/compare\";\nimport type { ColumnDef, SortableValue } from \"../types\";\nimport {\n  PIVOT_GRAND_TOTAL_KEY,\n  pivotLeafKey,\n  pivotPathKey,\n  pivotTotalLeafKey,\n} from \"./pivotKeys\";\n\n// Keys are built in `./pivotKeys`, which the server translator and the URL\n// codec share, so the three agree by construction rather than by copying. The\n// grand-total key is the one of them a host compares against, so the engine is\n// still where it is exported from.\nexport { PIVOT_GRAND_TOTAL_KEY };\n\n/** The label a dimension value gets when the row has none. */\nexport const PIVOT_BLANK = \"—\";\n\n/** One computed value per cell. */\nexport interface PivotMeasure {\n  /** The column key whose values are aggregated. */\n  key: string;\n  /** A built-in aggregate name, or your own function. */\n  agg: AggregateName | Aggregator;\n  /** Header caption. Defaults to the column key. */\n  label?: string;\n}\n\n/** What to pivot, and how. */\nexport interface PivotConfig {\n  /** Dimensions down the side, outermost first. Empty pivots to one line. */\n  rows: readonly string[];\n  /** Dimensions across the top, outermost first. Empty gives measure columns. */\n  columns: readonly string[];\n  /** What every cell computes. At least one, or there is nothing to show. */\n  measures: readonly PivotMeasure[];\n  /** A totals line for every level above the innermost. Defaults to `true`. */\n  subtotals?: boolean;\n  /** A grand-total line across everything. Defaults to `true`. */\n  grandTotals?: boolean;\n}\n\n/** A node in the column header tree. */\nexport interface PivotColumnNode {\n  /** The dimension value this node stands for. */\n  label: string;\n  /** Its full path from the outermost dimension. */\n  path: readonly string[];\n  /** How many leaf columns sit under it — the header cell's `colSpan`. */\n  span: number;\n  /** Nested dimension values, or empty at the innermost level. */\n  children: readonly PivotColumnNode[];\n}\n\n/** One rendered column: a column path plus the measure shown in it. */\nexport interface PivotColumnLeaf {\n  /** Stable key for React and for column-level state. */\n  key: string;\n  /** The column-dimension values, outermost first. Empty without any. */\n  path: readonly string[];\n  /** The measure this column shows. */\n  measure: PivotMeasure;\n  /** Whether this is the grand-total column rather than a real path. */\n  total: boolean;\n}\n\n/** What a line in the body is. */\nexport type PivotRowKind = \"leaf\" | \"subtotal\" | \"grandTotal\";\n\n/** One rendered line. */\nexport interface PivotRow {\n  /** Stable id — also the collapse key for a `subtotal` line. */\n  key: string;\n  /** The row-dimension values, outermost first. */\n  path: readonly string[];\n  /** Nesting level, 0 for the outermost. */\n  depth: number;\n  /** Whether this line is a data line, a subtotal, or the grand total. */\n  kind: PivotRowKind;\n  /** The dimension value this line is labelled with. */\n  label: string;\n  /** One value per entry of {@link PivotResult.columnLeaves}, in order. */\n  cells: readonly ReactNode[];\n  /** How many source rows it covers — for \"12 rows\" affordances. */\n  count: number;\n}\n\n/** The whole pivot, ready to render. */\nexport interface PivotResult {\n  /** The column header tree; empty when there are no column dimensions. */\n  columnTree: readonly PivotColumnNode[];\n  /** The rendered columns, left to right — the order every row's cells use. */\n  columnLeaves: readonly PivotColumnLeaf[];\n  /** Every line of the body, in render order. */\n  rows: readonly PivotRow[];\n  /** Depth of the row-header area — how many dimensions are down the side. */\n  rowDepth: number;\n}\n\n/** Options for {@link pivot}. */\nexport interface PivotOptions<TRow> {\n  /**\n   * Columns, so dimension and measure values resolve through `sortValue`\n   * exactly as sorting and grouping do.\n   */\n  columns?: readonly ColumnDef<TRow>[];\n  /** Format a computed cell. Receives the raw result and the measure. */\n  format?: (value: ReactNode, measure: PivotMeasure) => ReactNode;\n  /**\n   * Subtotal keys the user has collapsed. A collapsed line keeps its own\n   * totals and drops everything beneath it.\n   */\n  collapsed?: ReadonlySet<string>;\n}\n\n/** The label for a dimension value, with a bucket for \"no value\". */\nfunction dimensionLabel(value: SortableValue): string {\n  if (value === undefined || value === null || value === \"\") return PIVOT_BLANK;\n  return String(value);\n}\n\n/** Resolve a row's value for one dimension, as a display label. */\nfunction dimensionOf<TRow>(\n  row: TRow,\n  key: string,\n  byKey: ReadonlyMap<string, ColumnDef<TRow>>\n): string {\n  return dimensionLabel(resolveAggregateValue(row, key, byKey.get(key)));\n}\n\n/**\n * Distinct paths for a set of dimensions, in sorted order, with each level\n * sorted within its parent.\n */\nfunction distinctPaths<TRow>(\n  rows: readonly TRow[],\n  dimensions: readonly string[],\n  byKey: ReadonlyMap<string, ColumnDef<TRow>>\n): string[][] {\n  if (dimensions.length === 0) return [[]];\n  let paths: string[][] = [[]];\n  for (const [level, dimension] of dimensions.entries()) {\n    const next: string[][] = [];\n    const seen = new Map<string, Set<string>>();\n    for (const row of rows) {\n      const prefix = pivotPathKey(\n        dimensions.slice(0, level).map((d) => dimensionOf(row, d, byKey))\n      );\n      let bucket = seen.get(prefix);\n      if (!bucket) {\n        bucket = new Set();\n        seen.set(prefix, bucket);\n      }\n      bucket.add(dimensionOf(row, dimension, byKey));\n    }\n    for (const path of paths) {\n      const values = [...(seen.get(pivotPathKey(path)) ?? [])].sort(\n        compareValues\n      );\n      for (const value of values) next.push([...path, value]);\n    }\n    paths = next;\n  }\n  return paths;\n}\n\n/** Build the column header tree from the leaf paths. */\nfunction columnTreeOf(\n  paths: readonly (readonly string[])[],\n  measures: number,\n  depth: number\n): PivotColumnNode[] {\n  if (depth === 0) return [];\n  const build = (\n    prefix: readonly string[],\n    level: number\n  ): PivotColumnNode[] => {\n    const seen: string[] = [];\n    for (const path of paths) {\n      if (path.length <= level) continue;\n      const matches = prefix.every((value, i) => path[i] === value);\n      const label = path[level];\n      if (matches && label !== undefined && !seen.includes(label)) {\n        seen.push(label);\n      }\n    }\n    return seen.map((label) => {\n      const path = [...prefix, label];\n      const children = level + 1 < depth ? build(path, level + 1) : [];\n      const span =\n        children.length > 0\n          ? children.reduce((sum, child) => sum + child.span, 0)\n          : measures;\n      return { label, path, span, children };\n    });\n  };\n  return build([], 0);\n}\n\n/** Every rendered column, left to right. */\nfunction columnLeavesOf(\n  paths: readonly (readonly string[])[],\n  measures: readonly PivotMeasure[],\n  grandTotals: boolean,\n  hasColumnDimensions: boolean\n): PivotColumnLeaf[] {\n  const leaves: PivotColumnLeaf[] = [];\n  for (const path of paths) {\n    for (const measure of measures) {\n      leaves.push({\n        key: pivotLeafKey(path, measure.key),\n        path,\n        measure,\n        total: false,\n      });\n    }\n  }\n  // A grand-total column only means something when the columns are split by\n  // something; without dimensions it would repeat the only column there is.\n  if (grandTotals && hasColumnDimensions) {\n    for (const measure of measures) {\n      leaves.push({\n        key: pivotTotalLeafKey(measure.key),\n        path: [],\n        measure,\n        total: true,\n      });\n    }\n  }\n  return leaves;\n}\n\n/** Compute one line's cells from the rows it covers. */\nfunction cellsOf<TRow>(\n  covered: readonly TRow[],\n  leaves: readonly PivotColumnLeaf[],\n  columnDimensions: readonly string[],\n  byKey: ReadonlyMap<string, ColumnDef<TRow>>,\n  aggregate: (leaf: PivotColumnLeaf) => Aggregator,\n  format: PivotOptions<TRow>[\"format\"]\n): ReactNode[] {\n  return leaves.map((leaf) => {\n    const matching = leaf.total\n      ? covered\n      : covered.filter((row) =>\n          leaf.path.every(\n            (value, i) =>\n              dimensionOf(row, columnDimensions[i] ?? \"\", byKey) === value\n          )\n        );\n    const values: SortableValue[] = [];\n    for (const row of matching) {\n      const value = resolveAggregateValue(\n        row,\n        leaf.measure.key,\n        byKey.get(leaf.measure.key)\n      );\n      // A missing value is not a zero — the aggregator sees only what is\n      // really there, the same rule the summary row follows.\n      if (value !== undefined && value !== null) values.push(value);\n    }\n    const result = aggregate(leaf)(values);\n    return format ? format(result, leaf.measure) : result;\n  });\n}\n\n/** Whether a line sits under a collapsed ancestor. */\nfunction hiddenByCollapse(\n  path: readonly string[],\n  collapsed: ReadonlySet<string>\n): boolean {\n  for (let depth = 1; depth < path.length; depth++) {\n    if (collapsed.has(pivotPathKey(path.slice(0, depth)))) return true;\n  }\n  return false;\n}\n\n/**\n * Pivot rows into a table.\n *\n * @typeParam TRow - The row type.\n * @param rows - The rows to pivot. Filtering and searching happen upstream.\n * @param config - Which dimensions go where, and what each cell computes.\n * @param options - Columns for value resolution, formatting, collapse state.\n * @returns The column tree, the rendered columns and every body line.\n */\nexport function pivot<TRow>(\n  rows: readonly TRow[],\n  config: PivotConfig,\n  options: PivotOptions<TRow> = {}\n): PivotResult {\n  const { columns, format, collapsed = new Set<string>() } = options;\n  const byKey = new Map(columns?.map((column) => [column.key, column]));\n  const subtotals = config.subtotals ?? true;\n  const grandTotals = config.grandTotals ?? true;\n\n  const columnPaths = distinctPaths(rows, config.columns, byKey);\n  const columnLeaves = columnLeavesOf(\n    columnPaths,\n    config.measures,\n    grandTotals,\n    config.columns.length > 0\n  );\n  const columnTree = columnTreeOf(\n    columnPaths,\n    config.measures.length,\n    config.columns.length\n  );\n\n  const cells = (covered: readonly TRow[]) =>\n    cellsOf(\n      covered,\n      columnLeaves,\n      config.columns,\n      byKey,\n      (leaf) => aggregatorOf(leaf.measure),\n      format\n    );\n\n  const body = bodyRows({\n    rows,\n    dimensions: config.rows,\n    paths: distinctPaths(rows, config.rows, byKey),\n    byKey,\n    subtotals,\n    collapsed,\n    cells,\n  });\n\n  if (grandTotals) {\n    body.push({\n      key: PIVOT_GRAND_TOTAL_KEY,\n      path: [],\n      depth: 0,\n      kind: \"grandTotal\",\n      label: \"\",\n      cells: cells(rows),\n      count: rows.length,\n    });\n  }\n\n  return {\n    columnTree,\n    columnLeaves,\n    rows: body,\n    rowDepth: config.rows.length,\n  };\n}\n\n/** What {@link bodyRows} needs. */\ninterface BodyInput<TRow> {\n  rows: readonly TRow[];\n  dimensions: readonly string[];\n  paths: readonly (readonly string[])[];\n  byKey: ReadonlyMap<string, ColumnDef<TRow>>;\n  subtotals: boolean;\n  collapsed: ReadonlySet<string>;\n  cells: (covered: readonly TRow[]) => ReactNode[];\n}\n\n/**\n * Every body line in render order: each group's subtotal before the lines it\n * covers, and nothing at all beneath a collapsed one.\n *\n * Only subtotal lines carry a collapse key, so a key that names a leaf simply\n * has no effect — hiding a leaf would take its data out of view with no\n * subtotal standing in for it.\n */\nfunction bodyRows<TRow>({\n  rows,\n  dimensions,\n  paths,\n  byKey,\n  subtotals,\n  collapsed,\n  cells,\n}: BodyInput<TRow>): PivotRow[] {\n  const body: PivotRow[] = [];\n  const emitted = new Set<string>();\n\n  const push = (\n    path: readonly string[],\n    depth: number,\n    kind: PivotRowKind,\n    label: string\n  ) => {\n    const covered = rowsUnder(rows, path, dimensions, byKey);\n    body.push({\n      key: pivotPathKey(path),\n      path,\n      depth,\n      kind,\n      label,\n      cells: cells(covered),\n      count: covered.length,\n    });\n  };\n\n  for (const path of paths) {\n    if (subtotals) {\n      for (let depth = 1; depth < path.length; depth++) {\n        const prefix = path.slice(0, depth);\n        const key = pivotPathKey(prefix);\n        if (emitted.has(key) || hiddenByCollapse(prefix, collapsed)) continue;\n        emitted.add(key);\n        push(prefix, depth - 1, \"subtotal\", prefix[depth - 1] ?? \"\");\n      }\n    }\n    if (hiddenByCollapse(path, collapsed)) continue;\n    push(path, Math.max(path.length - 1, 0), \"leaf\", path.at(-1) ?? \"\");\n  }\n  return body;\n}\n\n/** The rows matching a row-dimension prefix. */\nfunction rowsUnder<TRow>(\n  rows: readonly TRow[],\n  prefix: readonly string[],\n  dimensions: readonly string[],\n  byKey: ReadonlyMap<string, ColumnDef<TRow>>\n): TRow[] {\n  return rows.filter((row) =>\n    prefix.every(\n      (value, i) => dimensionOf(row, dimensions[i] ?? \"\", byKey) === value\n    )\n  );\n}\n\n/**\n * The aggregator a measure names.\n *\n * Resolved per measure rather than looked up per cell: a lookup would need a\n * fallback for a miss that cannot happen, and unreachable code is worse than\n * a function call.\n */\nfunction aggregatorOf(measure: PivotMeasure): Aggregator {\n  return typeof measure.agg === \"string\"\n    ? builtInAggregator(measure.agg)\n    : measure.agg;\n}\n\n/**\n * The built-in aggregators, by name.\n *\n * Re-derived here rather than imported from the aggregate module's private\n * table: the pivot entry is optional and must not drag anything extra into\n * the base bundle for tables that never pivot.\n */\nfunction builtInAggregator(name: AggregateName): Aggregator {\n  return (values) => {\n    if (name === \"count\") return values.length;\n    const numbers = summableNumbers(values);\n    // Nothing summable is no value, not a zero: a missing budget is not $0.\n    if (numbers.length === 0) return undefined;\n    switch (name) {\n      case \"sum\":\n        return sum(numbers);\n      case \"avg\":\n        return sum(numbers) / numbers.length;\n      case \"min\":\n        return Math.min(...numbers);\n      case \"max\":\n        return Math.max(...numbers);\n    }\n  };\n}\n\n/** The values that are actually numbers, in the aggregate module's sense. */\nfunction summableNumbers(values: readonly SortableValue[]): number[] {\n  const numbers: number[] = [];\n  for (const value of values) {\n    if (typeof value === \"number\") {\n      if (Number.isFinite(value)) numbers.push(value);\n      continue;\n    }\n    if (typeof value !== \"string\" || value.trim() === \"\") continue;\n    const parsed = Number(value);\n    if (Number.isFinite(parsed)) numbers.push(parsed);\n  }\n  return numbers;\n}\n\nconst sum = (numbers: readonly number[]): number =>\n  numbers.reduce((total, n) => total + n, 0);\n","/**\n * A `PivotResult`, as the props a `DataTable` already takes.\n *\n * The engine returns a pivot as data: a column tree, the leaf columns it\n * flattens to, and a list of lines. Rendering that was left entirely to the\n * host — which sounds like freedom and works out as a hand-rolled `<table>`,\n * because a pivot has three shapes an ordinary table does not: header cells\n * that span, a row-header area down the side, and lines that are totals rather\n * than data. Every host that wanted a pivot in their own kit had to draw those\n * by hand, so the pivot was the one feature whose look nobody's adapter owned.\n *\n * This is the other half. It maps the result onto mechanisms the table already\n * ships, so any kit renders a pivot with its own components and nothing new:\n *\n * - **The column tree becomes `column.group`.** Header groups already take a\n *   path (`[\"EU\", \"Q1\"]`), already stack a row per level, and already compute\n *   spans from adjacency — which is exactly the tree the engine built. The\n *   grand-total column sits under its own one-level group, so it reads as\n *   apart from the tree rather than inside it.\n * - **The lines become rows.** Every line is a row of the table, keyed by the\n *   engine's own key, with one column per leaf.\n * - **The grand total becomes the `summaryRow`.** The table's footer is\n *   already a column-aligned totals row; a pivot's grand total is a\n *   column-aligned totals row. Two mechanisms for one thing would let them\n *   disagree.\n *\n * What is deliberately NOT here: the fold control on a subtotal line. Core\n * ships no user-facing controls — the row header takes\n * {@link PivotTableModelOptions.renderRowHeader}, and a host that wants a\n * fold button renders it there with its own kit's button, wired to the same\n * `collapsed` set the engine reads. The indent, the part name and the\n * grand-total captions are structure, which is core's.\n */\nimport type { ReactNode } from \"react\";\n\nimport { resolveLabels } from \"../labels\";\nimport type { ColumnDef, TableLabels } from \"../types\";\nimport { measureLabel, type PivotField } from \"./pivotConfigModel\";\nimport type { PivotColumnLeaf, PivotResult, PivotRow } from \"./pivotModel\";\n\n/**\n * The key of the row-header column — the one down the side, holding each\n * line's label. Stable, so a host can style or address it.\n */\nexport const PIVOT_ROW_COLUMN_KEY = \"pivot-row\";\n\n/** The key of the column rendering `columnLeaves[index]`. */\nfunction leafColumnKey(index: number): string {\n  return `pivot-${String(index)}`;\n}\n\n/** Options for {@link pivotTableModel}. */\nexport interface PivotTableModelOptions {\n  /**\n   * The fields the pivot was configured from, for the measure captions — the\n   * same list the configuration panel takes. Without it a measure column is\n   * captioned from its key.\n   */\n  fields?: readonly PivotField[];\n  /**\n   * Localized labels. Only the pivot captions are read: the grand-total\n   * column's group header, the grand-total footer's caption, and the\n   * row-header column's own header when {@link rowHeader} is absent.\n   */\n  labels?: TableLabels;\n  /**\n   * The row-header column's header — the cell in the corner. Defaults to the\n   * localized \"Rows\"; pass the row dimensions' own captions to name them.\n   */\n  rowHeader?: ReactNode;\n  /**\n   * One body line's row-header content. Defaults to the line's own label. This\n   * is where a fold control belongs: the line's `kind` says whether it is\n   * foldable and its `key` is the collapse key.\n   *\n   * The grand-total footer keeps its localized caption either way — there is\n   * nothing to fold on a total, and a renderer that assumed a label would\n   * leave the footer blank.\n   */\n  renderRowHeader?: (row: PivotRow) => ReactNode;\n  /**\n   * Pixels of indent per nesting level in the row-header column, so a nested\n   * pivot reads as nested. Defaults to 16; `0` turns it off.\n   */\n  indent?: number;\n}\n\n/** A pivot as table props. Spread the parts a `DataTable` takes. */\nexport interface PivotTableModel {\n  /** The row-header column, then one column per entry of `columnLeaves`. */\n  columns: ColumnDef<PivotRow>[];\n  /** Every line except the grand total, which is the footer instead. */\n  rows: readonly PivotRow[];\n  /** Row identity — the engine's own line key. */\n  rowKey: (row: PivotRow) => string;\n  /**\n   * The grand-total line as the table's footer row, or `undefined` when the\n   * pivot has no grand total (`grandTotals: false`).\n   */\n  summaryRow?: (\n    rows: readonly PivotRow[]\n  ) => Partial<Record<string, ReactNode>>;\n}\n\n/**\n * The header group a leaf column sits under: its column path, or the\n * grand-total caption for the total column.\n *\n * A total column has no path — it stands for all of them — so it would\n * otherwise land in the gap over ungrouped columns and read as belonging to\n * whatever precedes it.\n */\nfunction groupOf(\n  leaf: PivotColumnLeaf,\n  totalLabel: string\n): readonly string[] | undefined {\n  if (leaf.total) return [totalLabel];\n  return leaf.path.length > 0 ? leaf.path : undefined;\n}\n\n/** A line's own caption, as text: its label, or the grand-total wording. */\nfunction textCaptionOf(row: PivotRow, labels: Required<TableLabels>): string {\n  return row.kind === \"grandTotal\" ? labels.pivotGrandTotal : row.label;\n}\n\n/** One line's row-header cell: the indent, the part name, and the content. */\nfunction rowHeaderCell(\n  row: PivotRow,\n  indent: number,\n  content: ReactNode\n): ReactNode {\n  return (\n    <span\n      data-adapttable-part=\"pivot-row-header\"\n      data-pivot-kind={row.kind}\n      style={\n        row.depth > 0 && indent > 0\n          ? { paddingInlineStart: `${String(row.depth * indent)}px` }\n          : undefined\n      }\n    >\n      {content}\n    </span>\n  );\n}\n\n/**\n * Render a pivot with the table you already have.\n *\n * @param result - What `pivot` (or `serverPivotResult`) returned.\n * @param options - Captions, labels and the row-header renderer.\n * @returns Columns, rows, `rowKey` and the `summaryRow` for a `DataTable`.\n *\n * ```tsx\n * const result = pivot(rows, config, { collapsed });\n * const model = pivotTableModel(result, { fields, labels });\n *\n * <DataTable {...model} />;\n * ```\n */\nexport function pivotTableModel(\n  result: PivotResult,\n  options: PivotTableModelOptions = {}\n): PivotTableModel {\n  const { fields = [], renderRowHeader, indent = 16, rowHeader } = options;\n  const labels = resolveLabels(options.labels);\n  // The host's row-header renderer, or the line's own caption when it has none.\n  const caption =\n    renderRowHeader ?? ((row: PivotRow) => textCaptionOf(row, labels));\n\n  const columns: ColumnDef<PivotRow>[] = [\n    {\n      key: PIVOT_ROW_COLUMN_KEY,\n      header: rowHeader ?? labels.pivotRows,\n      accessor: (row) => rowHeaderCell(row, indent, caption(row)),\n      // The label as text, for every context that cannot render an element:\n      // an export, an announcement, the clipboard.\n      formatValue: (row) => textCaptionOf(row, labels),\n    },\n    ...result.columnLeaves.map((leaf, index) => ({\n      key: leafColumnKey(index),\n      header: measureLabel(leaf.measure, fields),\n      group: groupOf(leaf, labels.pivotTotal),\n      align: \"end\" as const,\n      accessor: (row: PivotRow) => row.cells[index],\n      // The leaf a column renders, for a host that needs to know which\n      // measure and which column path it is looking at.\n      meta: { pivotLeaf: leaf },\n    })),\n  ];\n\n  const total = result.rows.find((row) => row.kind === \"grandTotal\");\n  const rows = total\n    ? result.rows.filter((row) => row.kind !== \"grandTotal\")\n    : result.rows;\n\n  return {\n    columns,\n    rows,\n    rowKey: (row) => row.key,\n    summaryRow: total\n      ? () => ({\n          // The footer's caption is the label, never the host's row-header\n          // renderer: that renderer exists for the body's lines, where the\n          // fold control lives, and a fold control on the grand total would be\n          // a button with nothing to fold.\n          [PIVOT_ROW_COLUMN_KEY]: textCaptionOf(total, labels),\n          ...Object.fromEntries(\n            total.cells.map((cell, index) => [leafColumnKey(index), cell])\n          ),\n        })\n      : undefined,\n  };\n}\n","/**\n * The pivot state as a URL parameter — the encoding on its own, without the\n * hook that keeps it in sync.\n *\n * A pivot is the most expensive table state there is to rebuild by hand —\n * two axes, an order on each, and a measure list — which makes it the state\n * most worth putting in a link. It sits alongside sort, filters and column\n * layout for exactly the reason those do.\n *\n * The serialization is compact and readable rather than JSON-in-a-parameter:\n * `pivot=rows:region,team;cols:quarter;sum:amount`. A URL someone might read\n * or hand-edit should look like something, and the round trip is tested\n * rather than assumed.\n *\n * What travels is everything a reader can change: the two axes, the measures,\n * whether subtotals and grand totals are shown (`sub:0`, `grand:0`), and which\n * groups are folded (`hide:EU/Alpha`). A link that carried the axes and dropped\n * the rest would reopen showing numbers its sender had switched off, or lines\n * they had folded away, which is a different table from the one they sent.\n *\n * Only the departures are written. Subtotals and grand totals default to on, so\n * a parameter says so by staying silent about them — the same rule the density\n * and column-layout parameters follow. That is also what makes the encoding\n * backward compatible: a link or a saved view from before these fields existed\n * says nothing about them and reads back exactly as it always did.\n *\n * Custom aggregators cannot be serialized — a function has no URL form. A\n * configuration carrying one keeps working in memory and simply does not write\n * that measure to the URL, because a link that silently turned a custom\n * aggregation into `sum` would be worse than a link that omits it.\n *\n * The codec lives apart from {@link usePivotUrlState} because the two ends of\n * that link do not run in the same place: the table writes the parameter in a\n * browser, and a route handler reads it in Node. Keeping the reading half free\n * of React is what lets `@adapttable/core/query` — and `@adapttable/server`\n * through it — decode the same string a backend never renders.\n */\nimport type { AggregateName } from \"../aggregate/aggregate\";\nimport { EMPTY_PIVOT_CONFIG } from \"./pivotConfigModel\";\nimport { PATH_SEP } from \"./pivotKeys\";\nimport type { PivotConfig, PivotMeasure } from \"./pivotModel\";\n\nconst AGGREGATIONS: readonly AggregateName[] = [\n  \"sum\",\n  \"avg\",\n  \"count\",\n  \"min\",\n  \"max\",\n];\n\n/** The segment heads that are not an aggregation. */\nconst ROWS = \"rows\";\nconst COLUMNS = \"cols\";\nconst SUBTOTALS = \"sub\";\nconst GRAND_TOTALS = \"grand\";\nconst COLLAPSED = \"hide\";\n\n/** What a flag that is off looks like. On is written by saying nothing. */\nconst OFF = \"0\";\n\n/** Between the values of one folded path, once they are percent-encoded. */\nconst COLLAPSED_PATH_SEP = \"/\";\n/** Between one folded path and the next. */\nconst COLLAPSED_SEP = \",\";\n\n/** Nothing folded, with a stable identity so a read cannot churn a memo. */\nconst NOTHING_COLLAPSED: readonly string[] = [];\n\n/** Everything the pivot parameter carries. */\nexport interface PivotUrlState {\n  /** What to pivot, and how. */\n  config: PivotConfig;\n  /**\n   * The keys of the folded subtotal lines — a `PivotRow.key`, which is what\n   * `pivot`'s `collapsed` option matches against.\n   */\n  collapsed: readonly string[];\n}\n\n/** Whether a string names a built-in aggregation. */\nfunction isAggregateName(value: string): value is AggregateName {\n  return (AGGREGATIONS as readonly string[]).includes(value);\n}\n\n/**\n * Decode one field, tolerating the malformed input a hand-edited URL brings.\n *\n * Local rather than shared with `url/serialize`: this module is one of the few a\n * backend reads a shared link with in a process where React is not installed,\n * and it stays that light by importing almost nothing.\n */\nfunction decodeField(value: string): string {\n  try {\n    return decodeURIComponent(value);\n  } catch {\n    return value;\n  }\n}\n\n/**\n * A folded path in URL form: `EU/Alpha`.\n *\n * A collapse key is dimension values joined by a control character, and those\n * values are user data — a team can be called \"A/B\" or \"Q1,Q2\". Each value is\n * percent-encoded, which escapes both the separators this grammar reserves and\n * the control character itself, so nothing in a label can split a path in the\n * wrong place.\n */\nfunction encodeCollapsed(key: string): string {\n  return key.split(PATH_SEP).map(encodeURIComponent).join(COLLAPSED_PATH_SEP);\n}\n\n/** The collapse key a URL path names. Inverse of {@link encodeCollapsed}. */\nfunction decodeCollapsed(value: string): string {\n  return value.split(COLLAPSED_PATH_SEP).map(decodeField).join(PATH_SEP);\n}\n\n/**\n * Write the whole pivot state as a URL parameter value.\n *\n * @param state - The configuration, and which groups are folded.\n * @returns The parameter value, or `\"\"` when there is nothing to say.\n */\nexport function serializePivotState(state: PivotUrlState): string {\n  const { config, collapsed } = state;\n  const parts: string[] = [];\n  if (config.rows.length > 0) parts.push(`${ROWS}:${config.rows.join(\",\")}`);\n  if (config.columns.length > 0) {\n    parts.push(`${COLUMNS}:${config.columns.join(\",\")}`);\n  }\n  for (const measure of config.measures) {\n    // A function has no URL form. Omitting it beats writing `sum` and\n    // quietly changing what the link computes.\n    if (typeof measure.agg !== \"string\") continue;\n    parts.push(`${measure.agg}:${measure.key}`);\n  }\n  // Nothing on either axis and nothing to compute is not a pivot, so it writes\n  // no parameter at all — and it has no groups to fold, which is why the folded\n  // set goes with it rather than lingering as the only thing in the link.\n  if (parts.length === 0) return \"\";\n  if (config.subtotals === false) parts.push(`${SUBTOTALS}:${OFF}`);\n  if (config.grandTotals === false) parts.push(`${GRAND_TOTALS}:${OFF}`);\n  const folded = collapsed\n    .filter((key) => key !== \"\")\n    .map((key) => encodeCollapsed(key));\n  if (folded.length > 0) {\n    parts.push(`${COLLAPSED}:${folded.join(COLLAPSED_SEP)}`);\n  }\n  return parts.join(\";\");\n}\n\n/**\n * Read the whole pivot state back from a URL parameter value.\n *\n * Unknown segments are ignored rather than throwing: a URL is user input,\n * and a hand-edited one should degrade to a simpler pivot instead of an\n * error page.\n *\n * @param raw - The parameter value.\n * @returns The configuration it describes, and which groups are folded.\n */\nexport function deserializePivotState(raw: string | null): PivotUrlState {\n  if (!raw) return { config: EMPTY_PIVOT_CONFIG, collapsed: NOTHING_COLLAPSED };\n  let rows: readonly string[] = [];\n  let columns: readonly string[] = [];\n  let collapsed: readonly string[] = NOTHING_COLLAPSED;\n  let subtotals: boolean | undefined;\n  let grandTotals: boolean | undefined;\n  const measures: PivotMeasure[] = [];\n  for (const part of raw.split(\";\")) {\n    const at = part.indexOf(\":\");\n    if (at < 0) continue;\n    const head = part.slice(0, at);\n    const body = part.slice(at + 1);\n    if (body === \"\") continue;\n    if (head === ROWS) rows = body.split(\",\");\n    else if (head === COLUMNS) columns = body.split(\",\");\n    else if (head === SUBTOTALS) subtotals = body !== OFF;\n    else if (head === GRAND_TOTALS) grandTotals = body !== OFF;\n    else if (head === COLLAPSED) {\n      collapsed = body\n        .split(COLLAPSED_SEP)\n        // An empty entry — `hide:,EU` from a hand-edited URL — names no group.\n        .filter((key) => key !== \"\")\n        .map((key) => decodeCollapsed(key));\n    } else if (isAggregateName(head)) measures.push({ key: body, agg: head });\n  }\n  return {\n    config: {\n      rows,\n      columns,\n      measures,\n      // Absent rather than `true`: a parameter that said nothing about them is a\n      // parameter that leaves the engine's own defaults in charge.\n      ...(subtotals === undefined ? {} : { subtotals }),\n      ...(grandTotals === undefined ? {} : { grandTotals }),\n    },\n    collapsed,\n  };\n}\n\n/**\n * Write a configuration as a URL parameter value.\n *\n * @param config - The configuration to serialize.\n * @returns The parameter value, or `\"\"` when there is nothing to say.\n */\nexport function serializePivot(config: PivotConfig): string {\n  return serializePivotState({ config, collapsed: NOTHING_COLLAPSED });\n}\n\n/**\n * Read a configuration back from a URL parameter value.\n *\n * @param raw - The parameter value.\n * @returns The configuration it describes.\n */\nexport function deserializePivot(raw: string | null): PivotConfig {\n  return deserializePivotState(raw).config;\n}\n","/**\n * The pivot state in the URL, so a built pivot survives a reload and can be\n * sent to someone.\n *\n * A pivot is the most expensive table state there is to rebuild by hand —\n * two axes, an order on each, and a measure list — which makes it the state\n * most worth putting in a link. It sits alongside sort, filters and column\n * layout for exactly the reason those do.\n *\n * Everything a reader changed travels, not only the axes: the subtotal and\n * grand-total switches, and which groups are folded. What someone sends is what\n * they were looking at, or the link is of a different table.\n *\n * The encoding itself is in {@link ./pivotUrlCodec}, which this hook reads\n * and writes through: a browser is only one end of a shared link, and the\n * other end is a server that never renders.\n */\nimport {\n  useCallback,\n  useEffect,\n  useMemo,\n  useRef,\n  useState,\n  useSyncExternalStore,\n} from \"react\";\n\nimport { type UrlStateAdapter, useResolvedAdapter } from \"../url/adapter\";\nimport { PARAM_PIVOT } from \"../url/serialize\";\nimport { EMPTY_PIVOT_CONFIG } from \"./pivotConfigModel\";\nimport type { PivotConfig } from \"./pivotModel\";\nimport {\n  deserializePivotState,\n  type PivotUrlState,\n  serializePivotState,\n} from \"./pivotUrlCodec\";\n\n/**\n * Trailing debounce for URL persistence, as the column-layout and formula hooks\n * use. Reads stay instant through the optimistic overlay below; the write waits,\n * which is what lets the overlay bridge a router whose navigation lands a tick\n * later — clearing it in the same batch as the write leaves one render with the\n * overlay gone and the URL not yet updated, so a field the reader just moved\n * jumps back to where it was.\n */\nexport const PIVOT_URL_WRITE_DEBOUNCE_MS = 150;\n\n/** Nothing folded, with a stable identity so a read cannot churn a memo. */\nconst NOTHING_COLLAPSED: readonly string[] = [];\n\n/** What {@link usePivotUrlState} needs. */\nexport interface UsePivotUrlStateOptions {\n  urlAdapter?: UrlStateAdapter;\n  urlSync?: boolean;\n  urlKey?: string;\n  /** The pivot before anyone has built one. Defaults to empty. */\n  defaultConfig?: PivotConfig;\n}\n\n/** The controlled state to hand the panel and the engine. */\nexport interface UsePivotUrlStateResult {\n  /** What to pivot, and how. Give it to the panel and to `pivot`. */\n  config: PivotConfig;\n  /** Persist a new configuration. Wire to the panel's `onChange`. */\n  onConfigChange: (next: PivotConfig) => void;\n  /**\n   * The folded subtotal lines, by key — `pivot`'s `collapsed` option, so the\n   * link and the rendering agree without the host holding a second copy.\n   */\n  collapsed: ReadonlySet<string>;\n  /** Persist a new folded set. Wire to whatever folds a subtotal line. */\n  onCollapsedChange: (next: ReadonlySet<string>) => void;\n}\n\n/**\n * Keep the pivot state in the URL.\n *\n * @param options - See {@link UsePivotUrlStateOptions}.\n * @returns The configuration, the folded set, and the setters for both.\n */\nexport function usePivotUrlState(\n  options: UsePivotUrlStateOptions = {}\n): UsePivotUrlStateResult {\n  const { urlAdapter, urlSync, urlKey, defaultConfig } = options;\n  const ns = urlKey ? `${urlKey}.` : \"\";\n  const param = `${ns}${PARAM_PIVOT}`;\n  const resolved = useResolvedAdapter(urlAdapter, urlSync ?? true);\n  // Same SSR rule as the other URL hooks: only an explicit adapter is\n  // trusted to be hydration-consistent.\n  const search = useSyncExternalStore(\n    (onChange) => resolved.subscribe(onChange),\n    () => resolved.getSearch(),\n    () => (urlAdapter ? urlAdapter.getSearch() : \"\")\n  );\n  // Optimistic overlay: the change that has not reached the URL yet.\n  const [pending, setPending] = useState<PivotUrlState | null>(null);\n  const flushTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n  const state = useMemo<PivotUrlState>(() => {\n    if (pending) return pending;\n    const raw = new URLSearchParams(search).get(param);\n    if (raw === null) {\n      return {\n        config: defaultConfig ?? EMPTY_PIVOT_CONFIG,\n        collapsed: NOTHING_COLLAPSED,\n      };\n    }\n    return deserializePivotState(raw);\n  }, [pending, search, param, defaultConfig]);\n\n  const collapsed = useMemo(() => new Set(state.collapsed), [state.collapsed]);\n\n  const persist = useCallback(\n    (next: PivotUrlState) => {\n      const params = new URLSearchParams(resolved.getSearch());\n      const value = serializePivotState(next);\n      // An empty pivot writes no parameter: a URL should carry what someone\n      // built, not restate the nothing the table starts with.\n      if (value === \"\") params.delete(param);\n      else params.set(param, value);\n      resolved.setSearch(params.toString());\n    },\n    [resolved, param]\n  );\n\n  // What the setters below read. Two of them share one parameter, and a render\n  // is not guaranteed between them: a handler that changes the configuration and\n  // the folded set in one batch would otherwise write the second change over the\n  // first, because both would have read the state this render was built from.\n  const latest = useRef<PivotUrlState>(state);\n  latest.current = state;\n\n  const change = useCallback(\n    (next: PivotUrlState) => {\n      latest.current = next;\n      setPending(next);\n      if (flushTimer.current) clearTimeout(flushTimer.current);\n      flushTimer.current = setTimeout(() => {\n        flushTimer.current = null;\n        persist(next);\n        setPending(null);\n      }, PIVOT_URL_WRITE_DEBOUNCE_MS);\n    },\n    [persist]\n  );\n\n  const onConfigChange = useCallback(\n    (next: PivotConfig) => {\n      // The folded keys ride along: a field moved on an axis does not unfold\n      // what the reader had folded, and a key whose group is gone simply\n      // matches nothing.\n      change({ config: next, collapsed: latest.current.collapsed });\n    },\n    [change]\n  );\n\n  const onCollapsedChange = useCallback(\n    (next: ReadonlySet<string>) => {\n      change({ config: latest.current.config, collapsed: [...next] });\n    },\n    [change]\n  );\n\n  // Flush a pending change on unmount, so the last move a reader made before\n  // navigating is not lost.\n  const latestRef = useRef<{\n    pending: PivotUrlState | null;\n    persist: typeof persist;\n  }>({ pending, persist });\n  latestRef.current = { pending, persist };\n  useEffect(\n    () => () => {\n      if (flushTimer.current) {\n        clearTimeout(flushTimer.current);\n        // Invariant: a live timer implies a pending change — the timeout\n        // clears the timer BEFORE it clears `pending`.\n        const { pending: last, persist: write } = latestRef.current;\n        write(last!);\n      }\n    },\n    []\n  );\n\n  return { config: state.config, onConfigChange, collapsed, onCollapsedChange };\n}\n","/**\n * Pivoting on the server.\n *\n * A pivot over ten million rows is not a browser's job. When the server can\n * do it, the table's part is to ask in a shape a server can answer and to\n * render the reply — and the reply has to become the *same* `PivotResult` the\n * local engine produces, or every adapter would need a second rendering path\n * and the two would drift.\n *\n * So this module is a translator, not a second engine. The server sends the\n * numbers it computed; the column tree, the spans and the leaf ordering are\n * rebuilt here from the paths it named, exactly as the local engine builds\n * them. What the server decides is the arithmetic and the ordering. What core\n * decides is the shape.\n *\n * Keys come from {@link ./pivotKeys}, which both engines share: a leaf key that\n * disagreed with the local one by a byte would break column-level state on the\n * way from a local pivot to a server-backed one, and nothing would say why.\n *\n * The wire format is deliberately small. A server that can pivot but cannot\n * count rows, or that has no subtotals, should not have to send empty fields\n * to say so — so `count`, `subtotal` and `totals` are optional, and a missing\n * cell is an empty cell rather than a zero.\n */\nimport type { ReactNode } from \"react\";\n\nimport {\n  PIVOT_GRAND_TOTAL_KEY,\n  pivotLeafKey,\n  pivotPathKey,\n  pivotTotalLeafKey,\n} from \"./pivotKeys\";\nimport type {\n  PivotColumnLeaf,\n  PivotConfig,\n  PivotResult,\n  PivotRow,\n} from \"./pivotModel\";\n\n/** One line of a server-computed pivot. */\nexport interface QueryPivotRow {\n  /**\n   * The row-dimension values, outermost first, as the server labelled them.\n   * An empty path is the grand total.\n   */\n  path: readonly string[];\n  /**\n   * The computed values, in column-path order and within that in measure\n   * order — the same order the table renders its columns. A missing entry is\n   * an empty cell.\n   */\n  cells: readonly unknown[];\n  /**\n   * This line's values for the grand-total **column**, one per measure in\n   * measure order.\n   *\n   * That column exists whenever the configuration asks for grand totals and\n   * something splits the columns — the local engine's rule, so a table moving\n   * from one engine to the other keeps the same columns. What core cannot do is\n   * compute it: summing sums is not how an average or a minimum totals. So a\n   * server that does not send this leaves the column empty, exactly as an\n   * omitted cell is empty, and a configuration with `grandTotals: false` does\n   * not ask for it at all.\n   */\n  totals?: readonly unknown[];\n  /** How many source rows this line covers, when the server counts. */\n  count?: number;\n  /** Whether this line totals the lines beneath it rather than being one. */\n  subtotal?: boolean;\n}\n\n/** A page of server-computed pivot results. */\nexport interface QueryPivotPage {\n  /**\n   * The column-dimension paths, outermost value first, in the order the\n   * server wants them shown. One entry per path, NOT per rendered column —\n   * the measures multiply them here, the way they do locally.\n   */\n  columns: readonly (readonly string[])[];\n  /** The body lines, in display order. */\n  rows: readonly QueryPivotRow[];\n  /** The grand-total line, when the server computed one. */\n  total?: QueryPivotRow;\n}\n\n/** What {@link serverPivotResult} needs. */\nexport interface ServerPivotOptions {\n  /** The configuration that was sent, for the measures and their order. */\n  config: PivotConfig;\n  /** Format a computed cell, as the local engine's `format` does. */\n  format?: (\n    value: ReactNode,\n    measure: PivotConfig[\"measures\"][number]\n  ) => ReactNode;\n}\n\n/** Rebuild the column header tree from the paths the server named. */\nfunction treeOf(\n  paths: readonly (readonly string[])[],\n  measures: number,\n  depth: number\n): PivotResult[\"columnTree\"] {\n  if (depth === 0) return [];\n  const build = (\n    prefix: readonly string[],\n    level: number\n  ): PivotResult[\"columnTree\"] => {\n    const seen: string[] = [];\n    for (const path of paths) {\n      if (path.length <= level) continue;\n      if (!prefix.every((value, i) => path[i] === value)) continue;\n      const label = path[level];\n      if (label !== undefined && !seen.includes(label)) seen.push(label);\n    }\n    return seen.map((label) => {\n      const path = [...prefix, label];\n      const children = level + 1 < depth ? build(path, level + 1) : [];\n      const span =\n        children.length > 0\n          ? children.reduce((sum, child) => sum + child.span, 0)\n          : measures;\n      return { label, path, span, children };\n    });\n  };\n  return build([], 0);\n}\n\n/**\n * Turn a server's answer into the result the adapters already render.\n *\n * @param page - What the server sent.\n * @param options - The configuration that was asked for, and formatting.\n * @returns The same `PivotResult` shape the local engine returns.\n */\nexport function serverPivotResult(\n  page: QueryPivotPage,\n  { config, format }: ServerPivotOptions\n): PivotResult {\n  const leaves: PivotColumnLeaf[] = [];\n  for (const path of page.columns) {\n    for (const measure of config.measures) {\n      leaves.push({\n        key: pivotLeafKey(path, measure.key),\n        path,\n        measure,\n        total: false,\n      });\n    }\n  }\n  // Where `cells` stops and `totals` starts. The grand-total column follows\n  // every path column, in measure order, so a total leaf's position past this\n  // point IS its measure index.\n  const columnCells = leaves.length;\n  // The local engine's rule, followed here so that moving a table from local to\n  // server keeps the columns it had: a grand-total column means something only\n  // when the columns are split by something, and it is what `grandTotals` asks\n  // for, which defaults to on.\n  if ((config.grandTotals ?? true) && config.columns.length > 0) {\n    for (const measure of config.measures) {\n      leaves.push({\n        key: pivotTotalLeafKey(measure.key),\n        path: [],\n        measure,\n        total: true,\n      });\n    }\n  }\n\n  const cellsOf = (row: QueryPivotRow): ReactNode[] =>\n    leaves.map((leaf, index) => {\n      const value = leaf.total\n        ? row.totals?.[index - columnCells]\n        : row.cells[index];\n      // A cell the server did not send is empty, not zero — the same rule the\n      // local engine follows for a value that will not add up.\n      const node = (value ?? undefined) as ReactNode;\n      return format ? format(node, leaf.measure) : node;\n    });\n\n  const body: PivotRow[] = page.rows.map((row) => ({\n    key: pivotPathKey(row.path),\n    path: row.path,\n    depth: Math.max(row.path.length - 1, 0),\n    kind: row.subtotal === true ? \"subtotal\" : \"leaf\",\n    label: row.path.at(-1) ?? \"\",\n    cells: cellsOf(row),\n    count: row.count ?? 0,\n  }));\n\n  if (page.total) {\n    body.push({\n      key: PIVOT_GRAND_TOTAL_KEY,\n      path: [],\n      depth: 0,\n      kind: \"grandTotal\",\n      label: \"\",\n      cells: cellsOf(page.total),\n      count: page.total.count ?? 0,\n    });\n  }\n\n  return {\n    columnTree: treeOf(\n      page.columns,\n      config.measures.length,\n      config.columns.length\n    ),\n    columnLeaves: leaves,\n    rows: body,\n    rowDepth: config.rows.length,\n  };\n}\n"],"mappings":"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"}