@tanstack/table-core 9.0.0-beta.50 → 9.0.0-beta.52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/dist/features/column-grouping/createGroupedRowModel.cjs +22 -14
  2. package/dist/features/column-grouping/createGroupedRowModel.cjs.map +1 -1
  3. package/dist/features/column-grouping/createGroupedRowModel.d.cts +1 -1
  4. package/dist/features/column-grouping/createGroupedRowModel.d.ts +1 -1
  5. package/dist/features/column-grouping/createGroupedRowModel.js +21 -13
  6. package/dist/features/column-grouping/createGroupedRowModel.js.map +1 -1
  7. package/dist/features/{aggregation → row-aggregation}/aggregationFns.cjs +93 -48
  8. package/dist/features/row-aggregation/aggregationFns.cjs.map +1 -0
  9. package/dist/features/{aggregation → row-aggregation}/aggregationFns.d.cts +2 -2
  10. package/dist/features/{aggregation → row-aggregation}/aggregationFns.d.ts +2 -2
  11. package/dist/features/{aggregation → row-aggregation}/aggregationFns.js +82 -37
  12. package/dist/features/row-aggregation/aggregationFns.js.map +1 -0
  13. package/dist/features/row-aggregation/rowAggregationFeature.cjs +36 -0
  14. package/dist/features/row-aggregation/rowAggregationFeature.cjs.map +1 -0
  15. package/dist/features/row-aggregation/rowAggregationFeature.d.cts +10 -0
  16. package/dist/features/row-aggregation/rowAggregationFeature.d.ts +10 -0
  17. package/dist/features/{aggregation/aggregationFeature.js → row-aggregation/rowAggregationFeature.js} +8 -11
  18. package/dist/features/row-aggregation/rowAggregationFeature.js.map +1 -0
  19. package/dist/features/{aggregation/aggregationFeature.types.cjs → row-aggregation/rowAggregationFeature.types.cjs} +2 -2
  20. package/dist/features/row-aggregation/rowAggregationFeature.types.cjs.map +1 -0
  21. package/dist/features/{aggregation/aggregationFeature.types.d.cts → row-aggregation/rowAggregationFeature.types.d.cts} +8 -8
  22. package/dist/features/{aggregation/aggregationFeature.types.d.ts → row-aggregation/rowAggregationFeature.types.d.ts} +8 -8
  23. package/dist/features/{aggregation/aggregationFeature.types.js → row-aggregation/rowAggregationFeature.types.js} +2 -2
  24. package/dist/features/row-aggregation/rowAggregationFeature.types.js.map +1 -0
  25. package/dist/features/{aggregation/aggregationFeature.utils.cjs → row-aggregation/rowAggregationFeature.utils.cjs} +37 -6
  26. package/dist/features/row-aggregation/rowAggregationFeature.utils.cjs.map +1 -0
  27. package/dist/features/{aggregation/aggregationFeature.utils.d.cts → row-aggregation/rowAggregationFeature.utils.d.cts} +18 -4
  28. package/dist/features/{aggregation/aggregationFeature.utils.d.ts → row-aggregation/rowAggregationFeature.utils.d.ts} +18 -4
  29. package/dist/features/{aggregation/aggregationFeature.utils.js → row-aggregation/rowAggregationFeature.utils.js} +37 -7
  30. package/dist/features/row-aggregation/rowAggregationFeature.utils.js.map +1 -0
  31. package/dist/features/stockFeatures.cjs +2 -2
  32. package/dist/features/stockFeatures.cjs.map +1 -1
  33. package/dist/features/stockFeatures.d.cts +2 -2
  34. package/dist/features/stockFeatures.d.ts +2 -2
  35. package/dist/features/stockFeatures.js +2 -2
  36. package/dist/features/stockFeatures.js.map +1 -1
  37. package/dist/index.cjs +5 -5
  38. package/dist/index.d.cts +4 -4
  39. package/dist/index.d.ts +4 -4
  40. package/dist/index.js +4 -4
  41. package/dist/static-functions.cjs +9 -8
  42. package/dist/static-functions.d.cts +2 -2
  43. package/dist/static-functions.d.ts +2 -2
  44. package/dist/static-functions.js +2 -2
  45. package/dist/types/Cell.d.cts +2 -2
  46. package/dist/types/Cell.d.ts +2 -2
  47. package/dist/types/Column.d.cts +2 -2
  48. package/dist/types/Column.d.ts +2 -2
  49. package/dist/types/ColumnDef.d.cts +2 -2
  50. package/dist/types/ColumnDef.d.ts +2 -2
  51. package/dist/types/Row.d.cts +2 -2
  52. package/dist/types/Row.d.ts +2 -2
  53. package/dist/types/RowModelFns.d.cts +2 -2
  54. package/dist/types/RowModelFns.d.ts +2 -2
  55. package/dist/types/TableFeatures.d.cts +2 -2
  56. package/dist/types/TableFeatures.d.ts +2 -2
  57. package/dist/types/TableOptions.d.cts +3 -3
  58. package/dist/types/TableOptions.d.ts +3 -3
  59. package/dist/worker/initTableWorker.cjs.map +1 -1
  60. package/dist/worker/initTableWorker.js.map +1 -1
  61. package/package.json +1 -1
  62. package/skills/aggregation/SKILL.md +6 -6
  63. package/skills/api-not-found/SKILL.md +1 -1
  64. package/skills/client-vs-server/SKILL.md +1 -1
  65. package/skills/column-faceting/SKILL.md +1 -1
  66. package/skills/column-filtering/SKILL.md +1 -1
  67. package/skills/column-ordering/SKILL.md +1 -1
  68. package/skills/column-pinning/SKILL.md +1 -1
  69. package/skills/column-resizing/SKILL.md +1 -1
  70. package/skills/column-sizing/SKILL.md +1 -1
  71. package/skills/column-visibility/SKILL.md +1 -1
  72. package/skills/core/SKILL.md +1 -1
  73. package/skills/custom-features/SKILL.md +1 -1
  74. package/skills/expanding/SKILL.md +1 -1
  75. package/skills/global-filtering/SKILL.md +1 -1
  76. package/skills/grouping/SKILL.md +1 -1
  77. package/skills/migrate-v8-to-v9/SKILL.md +8 -8
  78. package/skills/pagination/SKILL.md +1 -1
  79. package/skills/row-pinning/SKILL.md +1 -1
  80. package/skills/row-selection/SKILL.md +1 -1
  81. package/skills/sorting/SKILL.md +1 -1
  82. package/skills/table-features/SKILL.md +5 -5
  83. package/skills/typescript/SKILL.md +1 -1
  84. package/src/features/column-grouping/createGroupedRowModel.ts +49 -12
  85. package/src/features/{aggregation → row-aggregation}/aggregationFns.ts +81 -43
  86. package/src/features/{aggregation/aggregationFeature.ts → row-aggregation/rowAggregationFeature.ts} +5 -9
  87. package/src/features/{aggregation/aggregationFeature.types.ts → row-aggregation/rowAggregationFeature.types.ts} +6 -6
  88. package/src/features/{aggregation/aggregationFeature.utils.ts → row-aggregation/rowAggregationFeature.utils.ts} +61 -4
  89. package/src/features/stockFeatures.ts +3 -3
  90. package/src/index.ts +4 -4
  91. package/src/static-functions.ts +1 -1
  92. package/src/types/Cell.ts +2 -2
  93. package/src/types/Column.ts +2 -2
  94. package/src/types/ColumnDef.ts +2 -2
  95. package/src/types/Row.ts +2 -2
  96. package/src/types/RowModelFns.ts +2 -2
  97. package/src/types/TableFeatures.ts +2 -2
  98. package/src/types/TableOptions.ts +3 -3
  99. package/src/worker/initTableWorker.ts +1 -1
  100. package/dist/features/aggregation/aggregationFeature.cjs +0 -39
  101. package/dist/features/aggregation/aggregationFeature.cjs.map +0 -1
  102. package/dist/features/aggregation/aggregationFeature.d.cts +0 -10
  103. package/dist/features/aggregation/aggregationFeature.d.ts +0 -10
  104. package/dist/features/aggregation/aggregationFeature.js.map +0 -1
  105. package/dist/features/aggregation/aggregationFeature.types.cjs.map +0 -1
  106. package/dist/features/aggregation/aggregationFeature.types.js.map +0 -1
  107. package/dist/features/aggregation/aggregationFeature.utils.cjs.map +0 -1
  108. package/dist/features/aggregation/aggregationFeature.utils.js.map +0 -1
  109. package/dist/features/aggregation/aggregationFns.cjs.map +0 -1
  110. package/dist/features/aggregation/aggregationFns.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"initTableWorker.cjs","names":["makeObjectMap","constructTable","storeReactivityBindings","serializeRowModel"],"sources":["../../src/worker/initTableWorker.ts"],"sourcesContent":["import { constructTable } from '../core/table/constructTable'\nimport { storeReactivityBindings } from '../store-reactivity-bindings'\nimport { makeObjectMap } from '../utils'\nimport { serializeRowModel } from './serializeRowModel'\nimport type { RowData } from '../types/type-utils'\nimport type { TableFeatures } from '../types/TableFeatures'\nimport type { TableOptions } from '../types/TableOptions'\nimport type { Table_Internal } from '../types/Table'\nimport type {\n TableWorkerRequest,\n TableWorkerResult,\n TableWorkerStage,\n TableWorkerStagePayload,\n} from './tableWorkerProtocol'\n\nexport type TableWorkerConfig<\n TFeatures extends TableFeatures,\n TData extends RowData,\n> = Omit<TableOptions<TFeatures, TData>, 'data'>\n\nfunction capitalize(stage: string) {\n return stage.charAt(0).toUpperCase() + stage.slice(1)\n}\n\n/** Flatten column-group defs to leaf defs (mirrors core's id resolution). */\nfunction flattenColumnDefs(defs: Array<any>): Array<any> {\n return defs.flatMap((def) =>\n def.columns ? flattenColumnDefs(def.columns) : [def],\n )\n}\n\n/**\n * Runs a headless \"shadow table\" inside a dedicated Web Worker.\n *\n * Call this from a user-authored worker entry file, passing the same columns\n * and processing features used on the main thread. The shadow table runs the\n * real table-core row model pipeline (real fns, real Row objects) off the\n * main thread and posts back one payload per stage the main thread requested:\n * a transferable index permutation for flat results, a serialized row tree\n * (with eagerly computed aggregates) when grouping produces synthetic rows.\n *\n * Everything passed here must be thread-portable: `accessorKey` columns or\n * accessors defined in a shared module, and fns from registries or shared\n * modules (no closures over app state).\n *\n * @example\n * ```ts\n * // table.worker.ts\n * import { initTableWorker } from '@tanstack/table-core/experimental-worker-plugin'\n * import { columns, sharedFeatures } from './tableConfig'\n *\n * initTableWorker({ features: sharedFeatures, columns })\n * ```\n */\nexport function initTableWorker<\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(config: TableWorkerConfig<TFeatures, TData>): void {\n let table: Table_Internal<TFeatures, TData> | undefined\n let dataVersion = 0\n let coreIndexById: Record<string, number> = makeObjectMap()\n let aggregateColumnIds: Array<string> = []\n // Last-sent model identity per stage: the memoized getters return stable\n // objects when their inputs did not change, so identity equality is exactly\n // \"this stage's result is unchanged\".\n let lastSentModels: { [K in TableWorkerStage]?: unknown } = {}\n\n self.onmessage = (event: MessageEvent<TableWorkerRequest<TData>>) => {\n const message = event.data\n\n if (message.type === 'data') {\n dataVersion = message.dataVersion\n lastSentModels = {}\n if (!table) {\n table = constructTable<TFeatures, TData>({\n ...(config as TableOptions<TFeatures, TData>),\n features: {\n coreReactivityFeature: storeReactivityBindings(),\n ...config.features,\n },\n data: message.data,\n })\n // Only columns with an explicit aggregation get eagerly aggregated\n // per group. Sync tables aggregate lazily (visible cells only), so\n // auto-aggregating every column would explode on high-cardinality\n // grouping for values nothing renders. Read the RAW column defs:\n // aggregationFeature injects default aggregatedCell/aggregationFn\n // into every resolved columnDef, so the resolved defs can't tell\n // explicit from default.\n aggregateColumnIds = flattenColumnDefs(config.columns as Array<any>)\n .filter(\n (def) => def.aggregationFn != null || def.aggregatedCell != null,\n )\n .map(\n (def) =>\n def.id ??\n (typeof def.accessorKey === 'string'\n ? def.accessorKey.replaceAll('.', '_')\n : undefined),\n )\n .filter((id): id is string => id != null)\n } else {\n table.setOptions((prev) => ({ ...prev, data: message.data }))\n }\n // Map row ids to data positions once per dataset; serialization uses it\n // to express every stage result in terms of core row positions.\n const coreFlatRows = table.getCoreRowModel().flatRows\n coreIndexById = makeObjectMap()\n for (let i = 0; i < coreFlatRows.length; i++) {\n coreIndexById[coreFlatRows[i]!.id] = i\n }\n return\n }\n\n if (!table) return\n\n const start = performance.now()\n\n // Apply the serializable state slices to the shadow table's base atoms.\n table._reactivity.batch(() => {\n for (const [key, value] of Object.entries(message.state)) {\n const baseAtom = (table!.baseAtoms as Record<string, any>)[key]\n if (baseAtom && value !== undefined) {\n baseAtom.set(value)\n }\n }\n })\n\n // Compute exactly the stages the main thread requested, skipping any this\n // shadow table has no row model factory for (the main thread warns).\n const stages: { [K in TableWorkerStage]?: TableWorkerStagePayload } = {}\n const transfer: Array<Transferable> = []\n\n for (const stage of message.stages) {\n if (!(config.features as Record<string, unknown>)[`${stage}RowModel`]) {\n continue\n }\n const model = (table as any)[`get${capitalize(stage)}RowModel`]()\n // Memoized getters return the same object when inputs are unchanged;\n // skip re-serializing (and the main thread skips rebuilding). Safe under\n // single-flight: results are never dropped within a dataVersion.\n if (lastSentModels[stage] === model) {\n stages[stage] = { kind: 'unchanged' }\n continue\n }\n lastSentModels[stage] = model\n stages[stage] = serializeRowModel(\n model,\n coreIndexById,\n aggregateColumnIds,\n transfer,\n )\n }\n\n const response: TableWorkerResult = {\n type: 'result',\n requestId: message.requestId,\n dataVersion,\n stages,\n computeMs: performance.now() - start,\n }\n postMessage(response, { transfer })\n }\n}\n"],"mappings":";;;;;;AAoBA,SAAS,WAAW,OAAe;CACjC,OAAO,MAAM,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,MAAM,MAAM,CAAC;AACtD;;AAGA,SAAS,kBAAkB,MAA8B;CACvD,OAAO,KAAK,SAAS,QACnB,IAAI,UAAU,kBAAkB,IAAI,OAAO,IAAI,CAAC,GAAG,CACrD;AACF;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,SAAgB,gBAGd,QAAmD;CACnD,IAAI;CACJ,IAAI,cAAc;CAClB,IAAI,gBAAwCA,4BAAc;CAC1D,IAAI,qBAAoC,CAAC;CAIzC,IAAI,iBAAwD,CAAC;CAE7D,KAAK,aAAa,UAAmD;EACnE,MAAM,UAAU,MAAM;EAEtB,IAAI,QAAQ,SAAS,QAAQ;GAC3B,cAAc,QAAQ;GACtB,iBAAiB,CAAC;GAClB,IAAI,CAAC,OAAO;IACV,QAAQC,sCAAiC;KACvC,GAAI;KACJ,UAAU;MACR,uBAAuBC,0DAAwB;MAC/C,GAAG,OAAO;KACZ;KACA,MAAM,QAAQ;IAChB,CAAC;IAQD,qBAAqB,kBAAkB,OAAO,OAAqB,CAAC,CACjE,QACE,QAAQ,IAAI,iBAAiB,QAAQ,IAAI,kBAAkB,IAC9D,CAAC,CACA,KACE,QACC,IAAI,OACH,OAAO,IAAI,gBAAgB,WACxB,IAAI,YAAY,WAAW,KAAK,GAAG,IACnC,OACR,CAAC,CACA,QAAQ,OAAqB,MAAM,IAAI;GAC5C,OACE,MAAM,YAAY,UAAU;IAAE,GAAG;IAAM,MAAM,QAAQ;GAAK,EAAE;GAI9D,MAAM,eAAe,MAAM,gBAAgB,CAAC,CAAC;GAC7C,gBAAgBF,4BAAc;GAC9B,KAAK,IAAI,IAAI,GAAG,IAAI,aAAa,QAAQ,KACvC,cAAc,aAAa,EAAE,CAAE,MAAM;GAEvC;EACF;EAEA,IAAI,CAAC,OAAO;EAEZ,MAAM,QAAQ,YAAY,IAAI;EAG9B,MAAM,YAAY,YAAY;GAC5B,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,KAAK,GAAG;IACxD,MAAM,WAAY,MAAO,UAAkC;IAC3D,IAAI,YAAY,UAAU,QACxB,SAAS,IAAI,KAAK;GAEtB;EACF,CAAC;EAID,MAAM,SAAgE,CAAC;EACvE,MAAM,WAAgC,CAAC;EAEvC,KAAK,MAAM,SAAS,QAAQ,QAAQ;GAClC,IAAI,CAAE,OAAO,SAAqC,GAAG,MAAM,YACzD;GAEF,MAAM,QAAS,MAAc,MAAM,WAAW,KAAK,EAAE,UAAU,CAAC;GAIhE,IAAI,eAAe,WAAW,OAAO;IACnC,OAAO,SAAS,EAAE,MAAM,YAAY;IACpC;GACF;GACA,eAAe,SAAS;GACxB,OAAO,SAASG,4CACd,OACA,eACA,oBACA,QACF;EACF;EAEA,MAAM,WAA8B;GAClC,MAAM;GACN,WAAW,QAAQ;GACnB;GACA;GACA,WAAW,YAAY,IAAI,IAAI;EACjC;EACA,YAAY,UAAU,EAAE,SAAS,CAAC;CACpC;AACF"}
1
+ {"version":3,"file":"initTableWorker.cjs","names":["makeObjectMap","constructTable","storeReactivityBindings","serializeRowModel"],"sources":["../../src/worker/initTableWorker.ts"],"sourcesContent":["import { constructTable } from '../core/table/constructTable'\nimport { storeReactivityBindings } from '../store-reactivity-bindings'\nimport { makeObjectMap } from '../utils'\nimport { serializeRowModel } from './serializeRowModel'\nimport type { RowData } from '../types/type-utils'\nimport type { TableFeatures } from '../types/TableFeatures'\nimport type { TableOptions } from '../types/TableOptions'\nimport type { Table_Internal } from '../types/Table'\nimport type {\n TableWorkerRequest,\n TableWorkerResult,\n TableWorkerStage,\n TableWorkerStagePayload,\n} from './tableWorkerProtocol'\n\nexport type TableWorkerConfig<\n TFeatures extends TableFeatures,\n TData extends RowData,\n> = Omit<TableOptions<TFeatures, TData>, 'data'>\n\nfunction capitalize(stage: string) {\n return stage.charAt(0).toUpperCase() + stage.slice(1)\n}\n\n/** Flatten column-group defs to leaf defs (mirrors core's id resolution). */\nfunction flattenColumnDefs(defs: Array<any>): Array<any> {\n return defs.flatMap((def) =>\n def.columns ? flattenColumnDefs(def.columns) : [def],\n )\n}\n\n/**\n * Runs a headless \"shadow table\" inside a dedicated Web Worker.\n *\n * Call this from a user-authored worker entry file, passing the same columns\n * and processing features used on the main thread. The shadow table runs the\n * real table-core row model pipeline (real fns, real Row objects) off the\n * main thread and posts back one payload per stage the main thread requested:\n * a transferable index permutation for flat results, a serialized row tree\n * (with eagerly computed aggregates) when grouping produces synthetic rows.\n *\n * Everything passed here must be thread-portable: `accessorKey` columns or\n * accessors defined in a shared module, and fns from registries or shared\n * modules (no closures over app state).\n *\n * @example\n * ```ts\n * // table.worker.ts\n * import { initTableWorker } from '@tanstack/table-core/experimental-worker-plugin'\n * import { columns, sharedFeatures } from './tableConfig'\n *\n * initTableWorker({ features: sharedFeatures, columns })\n * ```\n */\nexport function initTableWorker<\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(config: TableWorkerConfig<TFeatures, TData>): void {\n let table: Table_Internal<TFeatures, TData> | undefined\n let dataVersion = 0\n let coreIndexById: Record<string, number> = makeObjectMap()\n let aggregateColumnIds: Array<string> = []\n // Last-sent model identity per stage: the memoized getters return stable\n // objects when their inputs did not change, so identity equality is exactly\n // \"this stage's result is unchanged\".\n let lastSentModels: { [K in TableWorkerStage]?: unknown } = {}\n\n self.onmessage = (event: MessageEvent<TableWorkerRequest<TData>>) => {\n const message = event.data\n\n if (message.type === 'data') {\n dataVersion = message.dataVersion\n lastSentModels = {}\n if (!table) {\n table = constructTable<TFeatures, TData>({\n ...(config as TableOptions<TFeatures, TData>),\n features: {\n coreReactivityFeature: storeReactivityBindings(),\n ...config.features,\n },\n data: message.data,\n })\n // Only columns with an explicit aggregation get eagerly aggregated\n // per group. Sync tables aggregate lazily (visible cells only), so\n // auto-aggregating every column would explode on high-cardinality\n // grouping for values nothing renders. Read the RAW column defs:\n // rowAggregationFeature injects default aggregatedCell/aggregationFn\n // into every resolved columnDef, so the resolved defs can't tell\n // explicit from default.\n aggregateColumnIds = flattenColumnDefs(config.columns as Array<any>)\n .filter(\n (def) => def.aggregationFn != null || def.aggregatedCell != null,\n )\n .map(\n (def) =>\n def.id ??\n (typeof def.accessorKey === 'string'\n ? def.accessorKey.replaceAll('.', '_')\n : undefined),\n )\n .filter((id): id is string => id != null)\n } else {\n table.setOptions((prev) => ({ ...prev, data: message.data }))\n }\n // Map row ids to data positions once per dataset; serialization uses it\n // to express every stage result in terms of core row positions.\n const coreFlatRows = table.getCoreRowModel().flatRows\n coreIndexById = makeObjectMap()\n for (let i = 0; i < coreFlatRows.length; i++) {\n coreIndexById[coreFlatRows[i]!.id] = i\n }\n return\n }\n\n if (!table) return\n\n const start = performance.now()\n\n // Apply the serializable state slices to the shadow table's base atoms.\n table._reactivity.batch(() => {\n for (const [key, value] of Object.entries(message.state)) {\n const baseAtom = (table!.baseAtoms as Record<string, any>)[key]\n if (baseAtom && value !== undefined) {\n baseAtom.set(value)\n }\n }\n })\n\n // Compute exactly the stages the main thread requested, skipping any this\n // shadow table has no row model factory for (the main thread warns).\n const stages: { [K in TableWorkerStage]?: TableWorkerStagePayload } = {}\n const transfer: Array<Transferable> = []\n\n for (const stage of message.stages) {\n if (!(config.features as Record<string, unknown>)[`${stage}RowModel`]) {\n continue\n }\n const model = (table as any)[`get${capitalize(stage)}RowModel`]()\n // Memoized getters return the same object when inputs are unchanged;\n // skip re-serializing (and the main thread skips rebuilding). Safe under\n // single-flight: results are never dropped within a dataVersion.\n if (lastSentModels[stage] === model) {\n stages[stage] = { kind: 'unchanged' }\n continue\n }\n lastSentModels[stage] = model\n stages[stage] = serializeRowModel(\n model,\n coreIndexById,\n aggregateColumnIds,\n transfer,\n )\n }\n\n const response: TableWorkerResult = {\n type: 'result',\n requestId: message.requestId,\n dataVersion,\n stages,\n computeMs: performance.now() - start,\n }\n postMessage(response, { transfer })\n }\n}\n"],"mappings":";;;;;;AAoBA,SAAS,WAAW,OAAe;CACjC,OAAO,MAAM,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,MAAM,MAAM,CAAC;AACtD;;AAGA,SAAS,kBAAkB,MAA8B;CACvD,OAAO,KAAK,SAAS,QACnB,IAAI,UAAU,kBAAkB,IAAI,OAAO,IAAI,CAAC,GAAG,CACrD;AACF;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,SAAgB,gBAGd,QAAmD;CACnD,IAAI;CACJ,IAAI,cAAc;CAClB,IAAI,gBAAwCA,4BAAc;CAC1D,IAAI,qBAAoC,CAAC;CAIzC,IAAI,iBAAwD,CAAC;CAE7D,KAAK,aAAa,UAAmD;EACnE,MAAM,UAAU,MAAM;EAEtB,IAAI,QAAQ,SAAS,QAAQ;GAC3B,cAAc,QAAQ;GACtB,iBAAiB,CAAC;GAClB,IAAI,CAAC,OAAO;IACV,QAAQC,sCAAiC;KACvC,GAAI;KACJ,UAAU;MACR,uBAAuBC,0DAAwB;MAC/C,GAAG,OAAO;KACZ;KACA,MAAM,QAAQ;IAChB,CAAC;IAQD,qBAAqB,kBAAkB,OAAO,OAAqB,CAAC,CACjE,QACE,QAAQ,IAAI,iBAAiB,QAAQ,IAAI,kBAAkB,IAC9D,CAAC,CACA,KACE,QACC,IAAI,OACH,OAAO,IAAI,gBAAgB,WACxB,IAAI,YAAY,WAAW,KAAK,GAAG,IACnC,OACR,CAAC,CACA,QAAQ,OAAqB,MAAM,IAAI;GAC5C,OACE,MAAM,YAAY,UAAU;IAAE,GAAG;IAAM,MAAM,QAAQ;GAAK,EAAE;GAI9D,MAAM,eAAe,MAAM,gBAAgB,CAAC,CAAC;GAC7C,gBAAgBF,4BAAc;GAC9B,KAAK,IAAI,IAAI,GAAG,IAAI,aAAa,QAAQ,KACvC,cAAc,aAAa,EAAE,CAAE,MAAM;GAEvC;EACF;EAEA,IAAI,CAAC,OAAO;EAEZ,MAAM,QAAQ,YAAY,IAAI;EAG9B,MAAM,YAAY,YAAY;GAC5B,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,KAAK,GAAG;IACxD,MAAM,WAAY,MAAO,UAAkC;IAC3D,IAAI,YAAY,UAAU,QACxB,SAAS,IAAI,KAAK;GAEtB;EACF,CAAC;EAID,MAAM,SAAgE,CAAC;EACvE,MAAM,WAAgC,CAAC;EAEvC,KAAK,MAAM,SAAS,QAAQ,QAAQ;GAClC,IAAI,CAAE,OAAO,SAAqC,GAAG,MAAM,YACzD;GAEF,MAAM,QAAS,MAAc,MAAM,WAAW,KAAK,EAAE,UAAU,CAAC;GAIhE,IAAI,eAAe,WAAW,OAAO;IACnC,OAAO,SAAS,EAAE,MAAM,YAAY;IACpC;GACF;GACA,eAAe,SAAS;GACxB,OAAO,SAASG,4CACd,OACA,eACA,oBACA,QACF;EACF;EAEA,MAAM,WAA8B;GAClC,MAAM;GACN,WAAW,QAAQ;GACnB;GACA;GACA,WAAW,YAAY,IAAI,IAAI;EACjC;EACA,YAAY,UAAU,EAAE,SAAS,CAAC;CACpC;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"initTableWorker.js","names":[],"sources":["../../src/worker/initTableWorker.ts"],"sourcesContent":["import { constructTable } from '../core/table/constructTable'\nimport { storeReactivityBindings } from '../store-reactivity-bindings'\nimport { makeObjectMap } from '../utils'\nimport { serializeRowModel } from './serializeRowModel'\nimport type { RowData } from '../types/type-utils'\nimport type { TableFeatures } from '../types/TableFeatures'\nimport type { TableOptions } from '../types/TableOptions'\nimport type { Table_Internal } from '../types/Table'\nimport type {\n TableWorkerRequest,\n TableWorkerResult,\n TableWorkerStage,\n TableWorkerStagePayload,\n} from './tableWorkerProtocol'\n\nexport type TableWorkerConfig<\n TFeatures extends TableFeatures,\n TData extends RowData,\n> = Omit<TableOptions<TFeatures, TData>, 'data'>\n\nfunction capitalize(stage: string) {\n return stage.charAt(0).toUpperCase() + stage.slice(1)\n}\n\n/** Flatten column-group defs to leaf defs (mirrors core's id resolution). */\nfunction flattenColumnDefs(defs: Array<any>): Array<any> {\n return defs.flatMap((def) =>\n def.columns ? flattenColumnDefs(def.columns) : [def],\n )\n}\n\n/**\n * Runs a headless \"shadow table\" inside a dedicated Web Worker.\n *\n * Call this from a user-authored worker entry file, passing the same columns\n * and processing features used on the main thread. The shadow table runs the\n * real table-core row model pipeline (real fns, real Row objects) off the\n * main thread and posts back one payload per stage the main thread requested:\n * a transferable index permutation for flat results, a serialized row tree\n * (with eagerly computed aggregates) when grouping produces synthetic rows.\n *\n * Everything passed here must be thread-portable: `accessorKey` columns or\n * accessors defined in a shared module, and fns from registries or shared\n * modules (no closures over app state).\n *\n * @example\n * ```ts\n * // table.worker.ts\n * import { initTableWorker } from '@tanstack/table-core/experimental-worker-plugin'\n * import { columns, sharedFeatures } from './tableConfig'\n *\n * initTableWorker({ features: sharedFeatures, columns })\n * ```\n */\nexport function initTableWorker<\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(config: TableWorkerConfig<TFeatures, TData>): void {\n let table: Table_Internal<TFeatures, TData> | undefined\n let dataVersion = 0\n let coreIndexById: Record<string, number> = makeObjectMap()\n let aggregateColumnIds: Array<string> = []\n // Last-sent model identity per stage: the memoized getters return stable\n // objects when their inputs did not change, so identity equality is exactly\n // \"this stage's result is unchanged\".\n let lastSentModels: { [K in TableWorkerStage]?: unknown } = {}\n\n self.onmessage = (event: MessageEvent<TableWorkerRequest<TData>>) => {\n const message = event.data\n\n if (message.type === 'data') {\n dataVersion = message.dataVersion\n lastSentModels = {}\n if (!table) {\n table = constructTable<TFeatures, TData>({\n ...(config as TableOptions<TFeatures, TData>),\n features: {\n coreReactivityFeature: storeReactivityBindings(),\n ...config.features,\n },\n data: message.data,\n })\n // Only columns with an explicit aggregation get eagerly aggregated\n // per group. Sync tables aggregate lazily (visible cells only), so\n // auto-aggregating every column would explode on high-cardinality\n // grouping for values nothing renders. Read the RAW column defs:\n // aggregationFeature injects default aggregatedCell/aggregationFn\n // into every resolved columnDef, so the resolved defs can't tell\n // explicit from default.\n aggregateColumnIds = flattenColumnDefs(config.columns as Array<any>)\n .filter(\n (def) => def.aggregationFn != null || def.aggregatedCell != null,\n )\n .map(\n (def) =>\n def.id ??\n (typeof def.accessorKey === 'string'\n ? def.accessorKey.replaceAll('.', '_')\n : undefined),\n )\n .filter((id): id is string => id != null)\n } else {\n table.setOptions((prev) => ({ ...prev, data: message.data }))\n }\n // Map row ids to data positions once per dataset; serialization uses it\n // to express every stage result in terms of core row positions.\n const coreFlatRows = table.getCoreRowModel().flatRows\n coreIndexById = makeObjectMap()\n for (let i = 0; i < coreFlatRows.length; i++) {\n coreIndexById[coreFlatRows[i]!.id] = i\n }\n return\n }\n\n if (!table) return\n\n const start = performance.now()\n\n // Apply the serializable state slices to the shadow table's base atoms.\n table._reactivity.batch(() => {\n for (const [key, value] of Object.entries(message.state)) {\n const baseAtom = (table!.baseAtoms as Record<string, any>)[key]\n if (baseAtom && value !== undefined) {\n baseAtom.set(value)\n }\n }\n })\n\n // Compute exactly the stages the main thread requested, skipping any this\n // shadow table has no row model factory for (the main thread warns).\n const stages: { [K in TableWorkerStage]?: TableWorkerStagePayload } = {}\n const transfer: Array<Transferable> = []\n\n for (const stage of message.stages) {\n if (!(config.features as Record<string, unknown>)[`${stage}RowModel`]) {\n continue\n }\n const model = (table as any)[`get${capitalize(stage)}RowModel`]()\n // Memoized getters return the same object when inputs are unchanged;\n // skip re-serializing (and the main thread skips rebuilding). Safe under\n // single-flight: results are never dropped within a dataVersion.\n if (lastSentModels[stage] === model) {\n stages[stage] = { kind: 'unchanged' }\n continue\n }\n lastSentModels[stage] = model\n stages[stage] = serializeRowModel(\n model,\n coreIndexById,\n aggregateColumnIds,\n transfer,\n )\n }\n\n const response: TableWorkerResult = {\n type: 'result',\n requestId: message.requestId,\n dataVersion,\n stages,\n computeMs: performance.now() - start,\n }\n postMessage(response, { transfer })\n }\n}\n"],"mappings":";;;;;;AAoBA,SAAS,WAAW,OAAe;CACjC,OAAO,MAAM,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,MAAM,MAAM,CAAC;AACtD;;AAGA,SAAS,kBAAkB,MAA8B;CACvD,OAAO,KAAK,SAAS,QACnB,IAAI,UAAU,kBAAkB,IAAI,OAAO,IAAI,CAAC,GAAG,CACrD;AACF;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,SAAgB,gBAGd,QAAmD;CACnD,IAAI;CACJ,IAAI,cAAc;CAClB,IAAI,gBAAwC,cAAc;CAC1D,IAAI,qBAAoC,CAAC;CAIzC,IAAI,iBAAwD,CAAC;CAE7D,KAAK,aAAa,UAAmD;EACnE,MAAM,UAAU,MAAM;EAEtB,IAAI,QAAQ,SAAS,QAAQ;GAC3B,cAAc,QAAQ;GACtB,iBAAiB,CAAC;GAClB,IAAI,CAAC,OAAO;IACV,QAAQ,eAAiC;KACvC,GAAI;KACJ,UAAU;MACR,uBAAuB,wBAAwB;MAC/C,GAAG,OAAO;KACZ;KACA,MAAM,QAAQ;IAChB,CAAC;IAQD,qBAAqB,kBAAkB,OAAO,OAAqB,CAAC,CACjE,QACE,QAAQ,IAAI,iBAAiB,QAAQ,IAAI,kBAAkB,IAC9D,CAAC,CACA,KACE,QACC,IAAI,OACH,OAAO,IAAI,gBAAgB,WACxB,IAAI,YAAY,WAAW,KAAK,GAAG,IACnC,OACR,CAAC,CACA,QAAQ,OAAqB,MAAM,IAAI;GAC5C,OACE,MAAM,YAAY,UAAU;IAAE,GAAG;IAAM,MAAM,QAAQ;GAAK,EAAE;GAI9D,MAAM,eAAe,MAAM,gBAAgB,CAAC,CAAC;GAC7C,gBAAgB,cAAc;GAC9B,KAAK,IAAI,IAAI,GAAG,IAAI,aAAa,QAAQ,KACvC,cAAc,aAAa,EAAE,CAAE,MAAM;GAEvC;EACF;EAEA,IAAI,CAAC,OAAO;EAEZ,MAAM,QAAQ,YAAY,IAAI;EAG9B,MAAM,YAAY,YAAY;GAC5B,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,KAAK,GAAG;IACxD,MAAM,WAAY,MAAO,UAAkC;IAC3D,IAAI,YAAY,UAAU,QACxB,SAAS,IAAI,KAAK;GAEtB;EACF,CAAC;EAID,MAAM,SAAgE,CAAC;EACvE,MAAM,WAAgC,CAAC;EAEvC,KAAK,MAAM,SAAS,QAAQ,QAAQ;GAClC,IAAI,CAAE,OAAO,SAAqC,GAAG,MAAM,YACzD;GAEF,MAAM,QAAS,MAAc,MAAM,WAAW,KAAK,EAAE,UAAU,CAAC;GAIhE,IAAI,eAAe,WAAW,OAAO;IACnC,OAAO,SAAS,EAAE,MAAM,YAAY;IACpC;GACF;GACA,eAAe,SAAS;GACxB,OAAO,SAAS,kBACd,OACA,eACA,oBACA,QACF;EACF;EAEA,MAAM,WAA8B;GAClC,MAAM;GACN,WAAW,QAAQ;GACnB;GACA;GACA,WAAW,YAAY,IAAI,IAAI;EACjC;EACA,YAAY,UAAU,EAAE,SAAS,CAAC;CACpC;AACF"}
1
+ {"version":3,"file":"initTableWorker.js","names":[],"sources":["../../src/worker/initTableWorker.ts"],"sourcesContent":["import { constructTable } from '../core/table/constructTable'\nimport { storeReactivityBindings } from '../store-reactivity-bindings'\nimport { makeObjectMap } from '../utils'\nimport { serializeRowModel } from './serializeRowModel'\nimport type { RowData } from '../types/type-utils'\nimport type { TableFeatures } from '../types/TableFeatures'\nimport type { TableOptions } from '../types/TableOptions'\nimport type { Table_Internal } from '../types/Table'\nimport type {\n TableWorkerRequest,\n TableWorkerResult,\n TableWorkerStage,\n TableWorkerStagePayload,\n} from './tableWorkerProtocol'\n\nexport type TableWorkerConfig<\n TFeatures extends TableFeatures,\n TData extends RowData,\n> = Omit<TableOptions<TFeatures, TData>, 'data'>\n\nfunction capitalize(stage: string) {\n return stage.charAt(0).toUpperCase() + stage.slice(1)\n}\n\n/** Flatten column-group defs to leaf defs (mirrors core's id resolution). */\nfunction flattenColumnDefs(defs: Array<any>): Array<any> {\n return defs.flatMap((def) =>\n def.columns ? flattenColumnDefs(def.columns) : [def],\n )\n}\n\n/**\n * Runs a headless \"shadow table\" inside a dedicated Web Worker.\n *\n * Call this from a user-authored worker entry file, passing the same columns\n * and processing features used on the main thread. The shadow table runs the\n * real table-core row model pipeline (real fns, real Row objects) off the\n * main thread and posts back one payload per stage the main thread requested:\n * a transferable index permutation for flat results, a serialized row tree\n * (with eagerly computed aggregates) when grouping produces synthetic rows.\n *\n * Everything passed here must be thread-portable: `accessorKey` columns or\n * accessors defined in a shared module, and fns from registries or shared\n * modules (no closures over app state).\n *\n * @example\n * ```ts\n * // table.worker.ts\n * import { initTableWorker } from '@tanstack/table-core/experimental-worker-plugin'\n * import { columns, sharedFeatures } from './tableConfig'\n *\n * initTableWorker({ features: sharedFeatures, columns })\n * ```\n */\nexport function initTableWorker<\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(config: TableWorkerConfig<TFeatures, TData>): void {\n let table: Table_Internal<TFeatures, TData> | undefined\n let dataVersion = 0\n let coreIndexById: Record<string, number> = makeObjectMap()\n let aggregateColumnIds: Array<string> = []\n // Last-sent model identity per stage: the memoized getters return stable\n // objects when their inputs did not change, so identity equality is exactly\n // \"this stage's result is unchanged\".\n let lastSentModels: { [K in TableWorkerStage]?: unknown } = {}\n\n self.onmessage = (event: MessageEvent<TableWorkerRequest<TData>>) => {\n const message = event.data\n\n if (message.type === 'data') {\n dataVersion = message.dataVersion\n lastSentModels = {}\n if (!table) {\n table = constructTable<TFeatures, TData>({\n ...(config as TableOptions<TFeatures, TData>),\n features: {\n coreReactivityFeature: storeReactivityBindings(),\n ...config.features,\n },\n data: message.data,\n })\n // Only columns with an explicit aggregation get eagerly aggregated\n // per group. Sync tables aggregate lazily (visible cells only), so\n // auto-aggregating every column would explode on high-cardinality\n // grouping for values nothing renders. Read the RAW column defs:\n // rowAggregationFeature injects default aggregatedCell/aggregationFn\n // into every resolved columnDef, so the resolved defs can't tell\n // explicit from default.\n aggregateColumnIds = flattenColumnDefs(config.columns as Array<any>)\n .filter(\n (def) => def.aggregationFn != null || def.aggregatedCell != null,\n )\n .map(\n (def) =>\n def.id ??\n (typeof def.accessorKey === 'string'\n ? def.accessorKey.replaceAll('.', '_')\n : undefined),\n )\n .filter((id): id is string => id != null)\n } else {\n table.setOptions((prev) => ({ ...prev, data: message.data }))\n }\n // Map row ids to data positions once per dataset; serialization uses it\n // to express every stage result in terms of core row positions.\n const coreFlatRows = table.getCoreRowModel().flatRows\n coreIndexById = makeObjectMap()\n for (let i = 0; i < coreFlatRows.length; i++) {\n coreIndexById[coreFlatRows[i]!.id] = i\n }\n return\n }\n\n if (!table) return\n\n const start = performance.now()\n\n // Apply the serializable state slices to the shadow table's base atoms.\n table._reactivity.batch(() => {\n for (const [key, value] of Object.entries(message.state)) {\n const baseAtom = (table!.baseAtoms as Record<string, any>)[key]\n if (baseAtom && value !== undefined) {\n baseAtom.set(value)\n }\n }\n })\n\n // Compute exactly the stages the main thread requested, skipping any this\n // shadow table has no row model factory for (the main thread warns).\n const stages: { [K in TableWorkerStage]?: TableWorkerStagePayload } = {}\n const transfer: Array<Transferable> = []\n\n for (const stage of message.stages) {\n if (!(config.features as Record<string, unknown>)[`${stage}RowModel`]) {\n continue\n }\n const model = (table as any)[`get${capitalize(stage)}RowModel`]()\n // Memoized getters return the same object when inputs are unchanged;\n // skip re-serializing (and the main thread skips rebuilding). Safe under\n // single-flight: results are never dropped within a dataVersion.\n if (lastSentModels[stage] === model) {\n stages[stage] = { kind: 'unchanged' }\n continue\n }\n lastSentModels[stage] = model\n stages[stage] = serializeRowModel(\n model,\n coreIndexById,\n aggregateColumnIds,\n transfer,\n )\n }\n\n const response: TableWorkerResult = {\n type: 'result',\n requestId: message.requestId,\n dataVersion,\n stages,\n computeMs: performance.now() - start,\n }\n postMessage(response, { transfer })\n }\n}\n"],"mappings":";;;;;;AAoBA,SAAS,WAAW,OAAe;CACjC,OAAO,MAAM,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,MAAM,MAAM,CAAC;AACtD;;AAGA,SAAS,kBAAkB,MAA8B;CACvD,OAAO,KAAK,SAAS,QACnB,IAAI,UAAU,kBAAkB,IAAI,OAAO,IAAI,CAAC,GAAG,CACrD;AACF;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,SAAgB,gBAGd,QAAmD;CACnD,IAAI;CACJ,IAAI,cAAc;CAClB,IAAI,gBAAwC,cAAc;CAC1D,IAAI,qBAAoC,CAAC;CAIzC,IAAI,iBAAwD,CAAC;CAE7D,KAAK,aAAa,UAAmD;EACnE,MAAM,UAAU,MAAM;EAEtB,IAAI,QAAQ,SAAS,QAAQ;GAC3B,cAAc,QAAQ;GACtB,iBAAiB,CAAC;GAClB,IAAI,CAAC,OAAO;IACV,QAAQ,eAAiC;KACvC,GAAI;KACJ,UAAU;MACR,uBAAuB,wBAAwB;MAC/C,GAAG,OAAO;KACZ;KACA,MAAM,QAAQ;IAChB,CAAC;IAQD,qBAAqB,kBAAkB,OAAO,OAAqB,CAAC,CACjE,QACE,QAAQ,IAAI,iBAAiB,QAAQ,IAAI,kBAAkB,IAC9D,CAAC,CACA,KACE,QACC,IAAI,OACH,OAAO,IAAI,gBAAgB,WACxB,IAAI,YAAY,WAAW,KAAK,GAAG,IACnC,OACR,CAAC,CACA,QAAQ,OAAqB,MAAM,IAAI;GAC5C,OACE,MAAM,YAAY,UAAU;IAAE,GAAG;IAAM,MAAM,QAAQ;GAAK,EAAE;GAI9D,MAAM,eAAe,MAAM,gBAAgB,CAAC,CAAC;GAC7C,gBAAgB,cAAc;GAC9B,KAAK,IAAI,IAAI,GAAG,IAAI,aAAa,QAAQ,KACvC,cAAc,aAAa,EAAE,CAAE,MAAM;GAEvC;EACF;EAEA,IAAI,CAAC,OAAO;EAEZ,MAAM,QAAQ,YAAY,IAAI;EAG9B,MAAM,YAAY,YAAY;GAC5B,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,KAAK,GAAG;IACxD,MAAM,WAAY,MAAO,UAAkC;IAC3D,IAAI,YAAY,UAAU,QACxB,SAAS,IAAI,KAAK;GAEtB;EACF,CAAC;EAID,MAAM,SAAgE,CAAC;EACvE,MAAM,WAAgC,CAAC;EAEvC,KAAK,MAAM,SAAS,QAAQ,QAAQ;GAClC,IAAI,CAAE,OAAO,SAAqC,GAAG,MAAM,YACzD;GAEF,MAAM,QAAS,MAAc,MAAM,WAAW,KAAK,EAAE,UAAU,CAAC;GAIhE,IAAI,eAAe,WAAW,OAAO;IACnC,OAAO,SAAS,EAAE,MAAM,YAAY;IACpC;GACF;GACA,eAAe,SAAS;GACxB,OAAO,SAAS,kBACd,OACA,eACA,oBACA,QACF;EACF;EAEA,MAAM,WAA8B;GAClC,MAAM;GACN,WAAW,QAAQ;GACnB;GACA;GACA,WAAW,YAAY,IAAI,IAAI;EACjC;EACA,YAAY,UAAU,EAAE,SAAS,CAAC;CACpC;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/table-core",
3
- "version": "9.0.0-beta.50",
3
+ "version": "9.0.0-beta.52",
4
4
  "description": "Headless UI for building powerful tables & datagrids for TS/JS.",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -6,13 +6,13 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.50',
9
+ library_version: '9.0.0-beta.52',
10
10
  }
11
11
  requires: ['core', 'table-features']
12
12
  sources:
13
13
  - 'TanStack/table:docs/guide/aggregation.md'
14
14
  - 'TanStack/table:docs/framework/react/guide/aggregation.md'
15
- - 'TanStack/table:packages/table-core/src/features/aggregation'
15
+ - 'TanStack/table:packages/table-core/src/features/row-aggregation'
16
16
  - 'TanStack/table:examples/react/aggregation'
17
17
  - 'TanStack/table:examples/react/grouped-aggregation'
18
18
  ---
@@ -27,14 +27,14 @@ for synthetic grouped rows.
27
27
 
28
28
  ```ts
29
29
  import {
30
- aggregationFeature,
30
+ rowAggregationFeature,
31
31
  aggregationFn_mean,
32
32
  aggregationFn_sum,
33
33
  tableFeatures,
34
34
  } from '@tanstack/table-core'
35
35
 
36
36
  export const features = tableFeatures({
37
- aggregationFeature,
37
+ rowAggregationFeature,
38
38
  aggregationFns: {
39
39
  mean: aggregationFn_mean,
40
40
  sum: aggregationFn_sum,
@@ -113,7 +113,7 @@ disables that local fallback.
113
113
 
114
114
  Wrong: registering `columnGroupingFeature` solely to total a column.
115
115
 
116
- Correct: register `aggregationFeature` and call
116
+ Correct: register `rowAggregationFeature` and call
117
117
  `column.getAggregationValue()`. Grouping is only required for grouped rows.
118
118
 
119
119
  ### [HIGH] Passing a scope label and rows
@@ -136,6 +136,6 @@ grouped results sent by the worker must be structured-cloneable.
136
136
 
137
137
  ## API Discovery
138
138
 
139
- Inspect `node_modules/@tanstack/table-core/src/features/aggregation/` and the
139
+ Inspect `node_modules/@tanstack/table-core/src/features/row-aggregation/` and the
140
140
  Aggregation Guide. Use `Column_Aggregation`, `AggregationFnDef`,
141
141
  `AggregationContext`, and `AggregationResult` for the typed public surface.
@@ -5,7 +5,7 @@ description: >
5
5
  metadata:
6
6
  type: sub-skill
7
7
  library: '@tanstack/table-core'
8
- library_version: '9.0.0-beta.50'
8
+ library_version: '9.0.0-beta.52'
9
9
  requires: ['core', 'table-features']
10
10
  sources:
11
11
  - 'TanStack/table:packages/table-core/src/index.ts'
@@ -5,7 +5,7 @@ description: >
5
5
  metadata:
6
6
  type: sub-skill
7
7
  library: '@tanstack/table-core'
8
- library_version: '9.0.0-beta.50'
8
+ library_version: '9.0.0-beta.52'
9
9
  requires: ['core', 'table-features']
10
10
  sources:
11
11
  - 'TanStack/table:docs/guide/row-models.md'
@@ -6,7 +6,7 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.50',
9
+ library_version: '9.0.0-beta.52',
10
10
  }
11
11
  requires: ['core', 'table-features', 'column-filtering']
12
12
  sources:
@@ -6,7 +6,7 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.50',
9
+ library_version: '9.0.0-beta.52',
10
10
  }
11
11
  requires: ['core', 'table-features', 'client-vs-server']
12
12
  sources:
@@ -6,7 +6,7 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.50',
9
+ library_version: '9.0.0-beta.52',
10
10
  }
11
11
  requires: ['core', 'table-features']
12
12
  sources:
@@ -6,7 +6,7 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.50',
9
+ library_version: '9.0.0-beta.52',
10
10
  }
11
11
  requires: ['core', 'table-features', 'column-sizing']
12
12
  sources:
@@ -6,7 +6,7 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.50',
9
+ library_version: '9.0.0-beta.52',
10
10
  }
11
11
  requires: ['core', 'table-features', 'column-sizing']
12
12
  sources:
@@ -6,7 +6,7 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.50',
9
+ library_version: '9.0.0-beta.52',
10
10
  }
11
11
  requires: ['core', 'table-features']
12
12
  sources:
@@ -6,7 +6,7 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.50',
9
+ library_version: '9.0.0-beta.52',
10
10
  }
11
11
  requires: ['core', 'table-features']
12
12
  sources:
@@ -5,7 +5,7 @@ description: >
5
5
  metadata:
6
6
  type: core
7
7
  library: '@tanstack/table-core'
8
- library_version: '9.0.0-beta.50'
8
+ library_version: '9.0.0-beta.52'
9
9
  sources:
10
10
  - 'TanStack/table:docs/overview.md'
11
11
  - 'TanStack/table:docs/guide/tables.md'
@@ -5,7 +5,7 @@ description: >
5
5
  metadata:
6
6
  type: sub-skill
7
7
  library: '@tanstack/table-core'
8
- library_version: '9.0.0-beta.50'
8
+ library_version: '9.0.0-beta.52'
9
9
  requires: ['core', 'table-features', 'typescript']
10
10
  sources:
11
11
  - 'TanStack/table:docs/framework/react/guide/custom-features.md'
@@ -6,7 +6,7 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.50',
9
+ library_version: '9.0.0-beta.52',
10
10
  }
11
11
  requires: ['core', 'table-features', 'client-vs-server']
12
12
  sources:
@@ -6,7 +6,7 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.50',
9
+ library_version: '9.0.0-beta.52',
10
10
  }
11
11
  requires: ['core', 'table-features', 'client-vs-server', 'column-filtering']
12
12
  sources:
@@ -6,7 +6,7 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.50',
9
+ library_version: '9.0.0-beta.52',
10
10
  }
11
11
  requires: ['core', 'table-features', 'client-vs-server']
12
12
  sources:
@@ -5,7 +5,7 @@ description: >
5
5
  metadata:
6
6
  type: lifecycle
7
7
  library: '@tanstack/table-core'
8
- library_version: '9.0.0-beta.50'
8
+ library_version: '9.0.0-beta.52'
9
9
  requires: ['core', 'table-features', 'typescript']
10
10
  sources:
11
11
  - 'TanStack/table:docs/framework/react/guide/migrating.md'
@@ -68,18 +68,18 @@ V8 bundled all stock features. V9 exposes an API only when its feature is presen
68
68
 
69
69
  | Capability | V9 feature |
70
70
  | --------------------------- | ------------------------- |
71
+ | Aggregation | `rowAggregationFeature` |
71
72
  | Column faceting | `columnFacetingFeature` |
72
73
  | Column filtering | `columnFilteringFeature` |
73
- | Aggregation | `aggregationFeature` |
74
- | Grouping | `columnGroupingFeature` |
75
74
  | Column ordering | `columnOrderingFeature` |
76
75
  | Column pinning | `columnPinningFeature` |
77
- | Interactive column resizing | `columnResizingFeature` |
78
76
  | Column sizes and offsets | `columnSizingFeature` |
79
77
  | Column visibility | `columnVisibilityFeature` |
80
78
  | Global filtering | `globalFilteringFeature` |
81
- | Row expansion | `rowExpandingFeature` |
79
+ | Grouping | `columnGroupingFeature` |
80
+ | Interactive column resizing | `columnResizingFeature` |
82
81
  | Pagination | `rowPaginationFeature` |
82
+ | Row expansion | `rowExpandingFeature` |
83
83
  | Row pinning | `rowPinningFeature` |
84
84
  | Row selection | `rowSelectionFeature` |
85
85
  | Sorting | `rowSortingFeature` |
@@ -91,7 +91,7 @@ Honor feature prerequisites in the same `tableFeatures` call:
91
91
  - `columnResizingFeature` requires `columnSizingFeature`.
92
92
  - `globalFilteringFeature` requires `columnFilteringFeature`.
93
93
  - Every row-model or function-registry slot requires its associated feature.
94
- - `aggregationFns` requires `aggregationFeature`; grouped aggregation uses both `aggregationFeature` and `columnGroupingFeature`.
94
+ - `aggregationFns` requires `rowAggregationFeature`; grouped aggregation uses both `rowAggregationFeature` and `columnGroupingFeature`.
95
95
  - Put prerequisite feature properties before dependent slots so inference and diagnostics remain clear.
96
96
 
97
97
  ### 2. Move row models into feature slots and rename factories
@@ -122,7 +122,7 @@ Move registries from table options or factory arguments into these feature slots
122
122
 
123
123
  Register only the built-ins the table references by string name, importing each individually (`filterFn_includesString`, `sortFn_alphanumeric`, `aggregationFn_sum`, and so on) alongside any custom functions. The full registry objects (`filterFns`, `sortFns`, `aggregationFns` exports) still work but bundle every built-in. A slot's keys become the valid string names in column definitions, and `'auto'` resolves only registered functions.
124
124
 
125
- Aggregation is independent from grouping. Add `aggregationFeature` for
125
+ Aggregation is independent from grouping. Add `rowAggregationFeature` for
126
126
  `aggregationFn`, `aggregatedCell`, `column.getAggregationValue(options?)`, and
127
127
  `cell.getIsAggregated`. A root total does not require grouping. Convert legacy
128
128
  custom callables `(columnId, leafRows, childRows) => result` to
@@ -300,7 +300,7 @@ Do not confuse new capabilities with required breakages. After the table works,
300
300
  - [ ] Move all remaining `get*RowModel()` options or earlier-beta `rowModels` entries to `create*RowModel()` feature slots.
301
301
  - [ ] Register each dependent feature before its row-model slot.
302
302
  - [ ] Move `filterFns`, `sortingFns`/`sortFns`, and `aggregationFns` into feature slots, registering individually imported built-ins; pass no registries to factories.
303
- - [ ] Register `aggregationFeature` independently and migrate custom aggregation callables to context-based `AggregationFnDef` definitions.
303
+ - [ ] Register `rowAggregationFeature` independently and migrate custom aggregation callables to context-based `AggregationFnDef` definitions.
304
304
  - [ ] Register `columnFilteringFeature` before global filtering and filter/facet dependencies.
305
305
  - [ ] Register `columnSizingFeature` before `columnResizingFeature`.
306
306
  - [ ] Replace `table.getState()` and top-level `onStateChange` according to the adapter state guide.
@@ -6,7 +6,7 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.50',
9
+ library_version: '9.0.0-beta.52',
10
10
  }
11
11
  requires: ['core', 'table-features', 'client-vs-server']
12
12
  sources:
@@ -6,7 +6,7 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.50',
9
+ library_version: '9.0.0-beta.52',
10
10
  }
11
11
  requires: ['core', 'table-features']
12
12
  sources:
@@ -6,7 +6,7 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.50',
9
+ library_version: '9.0.0-beta.52',
10
10
  }
11
11
  requires: ['core', 'table-features']
12
12
  sources:
@@ -6,7 +6,7 @@ metadata:
6
6
  {
7
7
  type: sub-skill,
8
8
  library: '@tanstack/table-core',
9
- library_version: '9.0.0-beta.50',
9
+ library_version: '9.0.0-beta.52',
10
10
  }
11
11
  requires: ['core', 'table-features', 'client-vs-server']
12
12
  sources:
@@ -5,7 +5,7 @@ description: >
5
5
  metadata:
6
6
  type: sub-skill
7
7
  library: '@tanstack/table-core'
8
- library_version: '9.0.0-beta.50'
8
+ library_version: '9.0.0-beta.52'
9
9
  requires: ['core']
10
10
  sources:
11
11
  - 'TanStack/table:docs/guide/row-models.md'
@@ -22,7 +22,7 @@ This skill builds on `core`. Read it first for the headless model and stable inp
22
22
 
23
23
  ```ts
24
24
  import {
25
- aggregationFeature,
25
+ rowAggregationFeature,
26
26
  aggregationFn_sum,
27
27
  columnGroupingFeature,
28
28
  createFilteredRowModel,
@@ -38,7 +38,7 @@ export const features = tableFeatures({
38
38
  columnFilteringFeature,
39
39
  filteredRowModel: createFilteredRowModel(),
40
40
  filterFns: { includesString: filterFn_includesString },
41
- aggregationFeature,
41
+ rowAggregationFeature,
42
42
  columnGroupingFeature,
43
43
  aggregationFns: { sum: aggregationFn_sum },
44
44
  rowSortingFeature,
@@ -68,7 +68,7 @@ const features = tableFeatures({
68
68
  filterFns: { includesString: filterFn_includesString },
69
69
  rowSortingFeature,
70
70
  sortFns: { alphanumeric: sortFn_alphanumeric },
71
- aggregationFeature,
71
+ rowAggregationFeature,
72
72
  columnGroupingFeature,
73
73
  aggregationFns: { sum: aggregationFn_sum },
74
74
  })
@@ -76,7 +76,7 @@ const features = tableFeatures({
76
76
 
77
77
  `filterFns`, `sortFns`, and `aggregationFns` are feature slots, not table
78
78
  options. They respectively require `columnFilteringFeature`,
79
- `rowSortingFeature`, and `aggregationFeature`. Import individual built-ins
79
+ `rowSortingFeature`, and `rowAggregationFeature`. Import individual built-ins
80
80
  (`filterFn_*`, `sortFn_*`, `aggregationFn_*`) and register them under their
81
81
  conventional keys; the full registry objects (`filterFns`, `sortFns`,
82
82
  `aggregationFns` exports) still work but bundle every built-in. A registered
@@ -5,7 +5,7 @@ description: >
5
5
  metadata:
6
6
  type: sub-skill
7
7
  library: '@tanstack/table-core'
8
- library_version: '9.0.0-beta.50'
8
+ library_version: '9.0.0-beta.52'
9
9
  requires: ['core', 'table-features']
10
10
  sources:
11
11
  - 'TanStack/table:docs/guide/helpers.md'
@@ -5,10 +5,10 @@ import { table_autoResetExpanded } from '../row-expanding/rowExpandingFeature.ut
5
5
  import { table_autoResetPageIndex } from '../row-pagination/rowPaginationFeature.utils'
6
6
  import {
7
7
  aggregateColumnValue,
8
- normalizeAggregationRows,
9
- } from '../aggregation/aggregationFeature.utils'
10
- import { row_getGroupingValue } from './columnGroupingFeature.utils'
8
+ normalizeUniqueAggregationRows,
9
+ } from '../row-aggregation/rowAggregationFeature.utils'
11
10
  import type { Row_ColumnGrouping } from './columnGroupingFeature.types'
11
+ import type { Column_Internal } from '../../types/Column'
12
12
  import type { TableFeatures } from '../../types/TableFeatures'
13
13
  import type { RowModel } from '../../core/row-models/coreRowModelsFeature.types'
14
14
  import type { Table, Table_Internal } from '../../types/Table'
@@ -20,7 +20,7 @@ import type { RowData } from '../../types/type-utils'
20
20
  *
21
21
  * The factory reads the relevant table state atoms and options, then returns a row model function used by the table row-model pipeline.
22
22
  *
23
- * When aggregationFeature is also registered, grouped rows use its shared
23
+ * When rowAggregationFeature is also registered, grouped rows use its shared
24
24
  * executor for non-group values. Grouping remains useful without aggregation.
25
25
  */
26
26
  export function createGroupedRowModel<
@@ -103,7 +103,7 @@ function _createGroupedRowModel<
103
103
  const columnId = existingGrouping[depth] as string
104
104
 
105
105
  // Group the rows together for this level
106
- const rowGroupsMap = groupBy(rows, columnId)
106
+ const rowGroupsMap = groupBy(table, rows, columnId)
107
107
 
108
108
  // Perform aggregations for each group
109
109
  const aggregatedGroupedRows = Array.from(rowGroupsMap.entries()).map(
@@ -118,7 +118,13 @@ function _createGroupedRowModel<
118
118
  subRow.parentId = id
119
119
  })
120
120
 
121
- const leafRows = normalizeAggregationRows(groupedRows, Infinity)
121
+ // Rows produced by groupBy are disjoint members of the pre-grouped
122
+ // row tree, so the duplicate-id guard is unnecessary; flat groups
123
+ // reuse the partition array as-is.
124
+ const leafRows = normalizeUniqueAggregationRows(
125
+ groupedRows,
126
+ Infinity,
127
+ ) as Array<Row<TFeatures, TData>>
122
128
 
123
129
  const row = constructRow(
124
130
  table,
@@ -171,6 +177,7 @@ function _createGroupedRowModel<
171
177
  column,
172
178
  groupingRow: row,
173
179
  rows: groupedRows,
180
+ uniqueRows: true,
174
181
  })
175
182
  return cache[colId]
176
183
  },
@@ -203,19 +210,49 @@ function _createGroupedRowModel<
203
210
  }
204
211
 
205
212
  function groupBy<TFeatures extends TableFeatures, TData extends RowData = any>(
213
+ table: Table_Internal<TFeatures, TData>,
206
214
  rows: Array<Row<TFeatures, TData>>,
207
215
  columnId: string,
208
216
  ) {
209
217
  const groupMap = new Map<any, Array<Row<TFeatures, TData>>>()
210
218
 
211
- return rows.reduce((map, row) => {
212
- const resKey = `${row_getGroupingValue(row, columnId)}`
213
- const previous = map.get(resKey)
219
+ // Resolve the column once instead of per row: `table.getColumn` goes
220
+ // through the memoized-API dispatcher, which is far too expensive to sit
221
+ // inside this per-row loop. The branches below mirror
222
+ // `row_getGroupingValue`'s caching contract exactly.
223
+ const column = table_getColumn(table, columnId) as
224
+ | Column_Internal<TFeatures, TData, unknown>
225
+ | undefined
226
+ const getGroupingValue = column?.columnDef.getGroupingValue
227
+
228
+ for (let i = 0; i < rows.length; i++) {
229
+ const row = rows[i]!
230
+ let groupingValue
231
+ if (getGroupingValue) {
232
+ const cache = (row as any)._groupingValuesCache as
233
+ | Record<string, unknown>
234
+ | undefined
235
+ if (cache && hasOwn(cache, columnId)) {
236
+ groupingValue = cache[columnId]
237
+ } else if (cache) {
238
+ groupingValue = cache[columnId] = getGroupingValue(
239
+ row.original,
240
+ row.index,
241
+ row,
242
+ )
243
+ }
244
+ } else {
245
+ groupingValue = row.getValue(columnId)
246
+ }
247
+
248
+ const resKey = `${groupingValue}`
249
+ const previous = groupMap.get(resKey)
214
250
  if (!previous) {
215
- map.set(resKey, [row])
251
+ groupMap.set(resKey, [row])
216
252
  } else {
217
253
  previous.push(row)
218
254
  }
219
- return map
220
- }, groupMap)
255
+ }
256
+
257
+ return groupMap
221
258
  }