{"version":3,"sources":["../src/features/treeData.ts"],"names":["createRow"],"mappings":"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","file":"chunk-HMH2IMWJ.cjs","sourcesContent":["// @zvndev/yable-core — Tree Data Feature\n// Hierarchical parent-child data support.\n// `getDataPath` callback returns array path (e.g., ['USA', 'California', 'San Francisco'])\n// Auto-builds tree from flat data. Supports expand/collapse, indent by depth,\n// aggregation roll-up, and filter-with-parent-chain retention.\n\nimport type { RowData, Row, Table, RowModel } from '../types'\nimport { createRow } from '../core/row'\n\n/** Tree metadata attached to Row objects during flattenTree. */\ninterface TreeRowMeta {\n  _treeDepth?: number\n  _isLeaf?: boolean\n  _treePath?: string[]\n  _treeKey?: string\n  _hasChildren?: boolean\n}\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface TreeNode<TData extends RowData> {\n  /** The path segments for this node */\n  path: string[]\n  /** The original data (may be synthetic for intermediate nodes) */\n  data: TData\n  /** Child nodes */\n  children: TreeNode<TData>[]\n  /** Depth in the tree (0-based) */\n  depth: number\n  /** Whether this node is a leaf (has no children) */\n  isLeaf: boolean\n  /** Unique key derived from the full path */\n  key: string\n}\n\nexport interface TreeDataOptions<TData extends RowData> {\n  /** Callback that returns the path array for a data item */\n  getDataPath: (data: TData) => string[]\n  /** Whether to auto-expand all nodes initially */\n  autoExpandAll?: boolean\n  /** Maximum depth to auto-expand */\n  autoExpandDepth?: number\n}\n\nexport interface TreeRowModelOptions<TData extends RowData> {\n  /** Filter a tree before flattening; ancestors of matching nodes are retained. */\n  filterNode?: (node: TreeNode<TData>) => boolean\n  /** Sort sibling nodes recursively before flattening. */\n  compareNodes?: (a: TreeNode<TData>, b: TreeNode<TData>) => number\n  /** Expanded state used for flattening. */\n  expanded?: Record<string, boolean> | true\n  /** Force retained filter paths open so matching descendants are visible. */\n  expandFilteredPaths?: boolean\n}\n\n// ---------------------------------------------------------------------------\n// buildTreeFromPaths\n// ---------------------------------------------------------------------------\n\n/**\n * Build a tree structure from flat data using path arrays.\n * Each data item's path defines its position in the hierarchy.\n *\n * @example\n * ```\n * const data = [\n *   { name: 'USA', value: 100 },\n *   { name: 'California', value: 50 },\n *   { name: 'San Francisco', value: 20 },\n * ]\n * // With getDataPath returning:\n * // ['USA'] for first item\n * // ['USA', 'California'] for second\n * // ['USA', 'California', 'San Francisco'] for third\n * ```\n */\nexport function buildTreeFromPaths<TData extends RowData>(\n  data: TData[],\n  getDataPath: (item: TData) => string[],\n): TreeNode<TData>[] {\n  const rootNodes: TreeNode<TData>[] = []\n  const nodeMap = new Map<string, TreeNode<TData>>()\n\n  // Sort data by path length to ensure parents come before children\n  const sortedData = [...data].sort((a, b) => {\n    const pathA = getDataPath(a)\n    const pathB = getDataPath(b)\n    return pathA.length - pathB.length\n  })\n\n  for (const item of sortedData) {\n    const path = getDataPath(item)\n    const key = path.join('/')\n\n    const node: TreeNode<TData> = {\n      path,\n      data: item,\n      children: [],\n      depth: path.length - 1,\n      isLeaf: true,\n      key,\n    }\n\n    nodeMap.set(key, node)\n\n    if (path.length === 1) {\n      // Root-level node\n      rootNodes.push(node)\n    } else {\n      // Find parent by constructing parent path\n      const parentPath = path.slice(0, -1)\n      const parentKey = parentPath.join('/')\n      const parentNode = nodeMap.get(parentKey)\n\n      if (parentNode) {\n        parentNode.children.push(node)\n        parentNode.isLeaf = false\n      } else {\n        // No explicit parent exists — create synthetic intermediate nodes\n        let currentPath: string[] = []\n        let currentParent: TreeNode<TData>[] = rootNodes\n\n        for (let i = 0; i < path.length - 1; i++) {\n          currentPath = [...currentPath, path[i]!]\n          const currentKey = currentPath.join('/')\n\n          let existing = nodeMap.get(currentKey)\n          if (!existing) {\n            // Create synthetic node\n            existing = {\n              path: [...currentPath],\n              data: { [path[i]!]: path[i] } as unknown as TData,\n              children: [],\n              depth: i,\n              isLeaf: false,\n              key: currentKey,\n            }\n            nodeMap.set(currentKey, existing)\n            currentParent.push(existing)\n          }\n\n          existing.isLeaf = false\n          currentParent = existing.children\n        }\n\n        currentParent.push(node)\n      }\n    }\n  }\n\n  return rootNodes\n}\n\n// ---------------------------------------------------------------------------\n// flattenTree — Convert tree back to flat row array\n// ---------------------------------------------------------------------------\n\n/**\n * Flatten a tree of nodes into a row array, respecting expanded state.\n * Only includes children of expanded nodes.\n */\nexport function flattenTree<TData extends RowData>(\n  table: Table<TData>,\n  treeNodes: TreeNode<TData>[],\n  expanded: Record<string, boolean> | true,\n): Row<TData>[] {\n  const rows: Row<TData>[] = []\n  let index = 0\n\n  function walk(nodes: TreeNode<TData>[], parentId?: string) {\n    for (const node of nodes) {\n      const rowId = node.key\n      const subRows: Row<TData>[] = []\n\n      const row = createRow(table, rowId, node.data, index, node.depth, subRows, parentId)\n\n      // Attach tree metadata to the row\n      const meta = row as Row<TData> & TreeRowMeta\n      meta._treeDepth = node.depth\n      meta._isLeaf = node.isLeaf\n      meta._treePath = node.path\n      meta._treeKey = node.key\n      meta._hasChildren = node.children.length > 0\n\n      rows.push(row)\n      index++\n\n      const isExpanded = expanded === true || (typeof expanded === 'object' && expanded[rowId])\n\n      if (isExpanded && node.children.length > 0) {\n        const childRows: Row<TData>[] = []\n        const startIndex = index\n        walk(node.children, rowId)\n        // Collect child rows added since startIndex\n        for (let i = startIndex; i < index; i++) {\n          childRows.push(rows[i]!)\n        }\n        row.subRows = childRows\n      }\n    }\n  }\n\n  walk(treeNodes)\n  return rows\n}\n\n// ---------------------------------------------------------------------------\n// filterTreeData — Filter with parent chain retention\n// ---------------------------------------------------------------------------\n\n/**\n * Filter tree data, keeping parent chain visible when a child matches.\n * Returns a new tree with only matching nodes and their ancestors.\n */\nexport function filterTreeData<TData extends RowData>(\n  nodes: TreeNode<TData>[],\n  predicate: (node: TreeNode<TData>) => boolean,\n): TreeNode<TData>[] {\n  const result: TreeNode<TData>[] = []\n\n  for (const node of nodes) {\n    // Recursively filter children first\n    const filteredChildren = filterTreeData(node.children, predicate)\n\n    // Include this node if it matches OR any of its children matched\n    if (predicate(node) || filteredChildren.length > 0) {\n      result.push({\n        ...node,\n        children: filteredChildren,\n        isLeaf: filteredChildren.length === 0 && node.children.length === 0,\n      })\n    }\n  }\n\n  return result\n}\n\n// ---------------------------------------------------------------------------\n// sortTreeData — Sort while preserving tree hierarchy\n// ---------------------------------------------------------------------------\n\n/**\n * Sort tree data recursively. Children are sorted independently at each level.\n */\nexport function sortTreeData<TData extends RowData>(\n  nodes: TreeNode<TData>[],\n  compareFn: (a: TreeNode<TData>, b: TreeNode<TData>) => number,\n): TreeNode<TData>[] {\n  const sorted = [...nodes].sort(compareFn)\n\n  return sorted.map((node) => ({\n    ...node,\n    children: node.children.length > 0 ? sortTreeData(node.children, compareFn) : node.children,\n  }))\n}\n\n// ---------------------------------------------------------------------------\n// getTreeRowModel — Builds a RowModel from tree data\n// ---------------------------------------------------------------------------\n\n/**\n * Create a RowModel from tree data, applying the full tree processing pipeline.\n */\nexport function getTreeRowModel<TData extends RowData>(\n  table: Table<TData>,\n  data: TData[],\n  getDataPath: (item: TData) => string[],\n  options: TreeRowModelOptions<TData> = {},\n): RowModel<TData> {\n  // 1. Build tree from flat data\n  let tree = buildTreeFromPaths(data, getDataPath)\n\n  // 2. Filter over the tree, not the flattened visible rows. This preserves\n  // parent chains when a descendant matches.\n  if (options.filterNode) {\n    tree = filterTreeData(tree, options.filterNode)\n  }\n\n  // 3. Sort siblings recursively so hierarchy is retained.\n  if (options.compareNodes) {\n    tree = sortTreeData(tree, options.compareNodes)\n  }\n\n  // 4. Get expanded state. Filtered trees default to opened retained paths so\n  // matched descendants are visible with their ancestors.\n  const expanded =\n    options.expanded ??\n    (options.filterNode && options.expandFilteredPaths !== false\n      ? true\n      : (table.getState().expanded as Record<string, boolean>))\n\n  // 5. Flatten for rendering, respecting expanded state\n  const rows = flattenTree(table, tree, expanded)\n\n  // 6. Build lookup maps\n  const flatRows = rows\n  const rowsById: Record<string, Row<TData>> = {}\n  for (const row of flatRows) {\n    rowsById[row.id] = row\n  }\n\n  return { rows, flatRows, rowsById }\n}\n\n// ---------------------------------------------------------------------------\n// Row helper extensions\n// ---------------------------------------------------------------------------\n\n/**\n * Get the tree depth for a row (shortcut for row._treeDepth).\n */\nexport function getTreeDepth<TData extends RowData>(row: Row<TData>): number {\n  return (row as Row<TData> & TreeRowMeta)._treeDepth ?? row.depth\n}\n\n/**\n * Check if a row is a leaf node (no children).\n */\nexport function isLeafRow<TData extends RowData>(row: Row<TData>): boolean {\n  return (row as Row<TData> & TreeRowMeta)._isLeaf ?? row.subRows.length === 0\n}\n\n/**\n * Get the parent row by looking up parentId in the row model.\n */\nexport function getParentRow<TData extends RowData>(\n  row: Row<TData>,\n  table: Table<TData>,\n): Row<TData> | undefined {\n  if (!row.parentId) return undefined\n  try {\n    return table.getRow(row.parentId, true)\n  } catch {\n    return undefined\n  }\n}\n\n/**\n * Aggregate values from leaf rows to parent nodes.\n */\nexport function aggregateTreeValues<TData extends RowData>(\n  nodes: TreeNode<TData>[],\n  _columnId: string,\n  aggregationFn: (values: unknown[]) => unknown,\n  getValueFromData: (data: TData) => unknown,\n): Map<string, unknown> {\n  const aggregated = new Map<string, unknown>()\n\n  function walk(nodeList: TreeNode<TData>[]): unknown[] {\n    const values: unknown[] = []\n    for (const node of nodeList) {\n      if (node.isLeaf) {\n        const val = getValueFromData(node.data)\n        values.push(val)\n        aggregated.set(node.key, val)\n      } else {\n        const childValues = walk(node.children)\n        const aggValue = aggregationFn(childValues)\n        aggregated.set(node.key, aggValue)\n        values.push(aggValue)\n      }\n    }\n    return values\n  }\n\n  walk(nodes)\n  return aggregated\n}\n"]}