@tanstack/table-core 9.0.0-beta.47 → 9.0.0-beta.49
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.
- package/dist/core/row-models/coreRowModelsFeature.types.d.cts +1 -1
- package/dist/core/row-models/coreRowModelsFeature.types.d.ts +1 -1
- package/dist/core/row-models/coreRowModelsFeature.utils.cjs +1 -1
- package/dist/core/row-models/coreRowModelsFeature.utils.cjs.map +1 -1
- package/dist/core/row-models/coreRowModelsFeature.utils.d.cts +1 -1
- package/dist/core/row-models/coreRowModelsFeature.utils.d.ts +1 -1
- package/dist/core/row-models/coreRowModelsFeature.utils.js +1 -1
- package/dist/core/row-models/coreRowModelsFeature.utils.js.map +1 -1
- package/dist/features/aggregation/aggregationFeature.cjs +38 -0
- package/dist/features/aggregation/aggregationFeature.cjs.map +1 -0
- package/dist/features/aggregation/aggregationFeature.d.cts +10 -0
- package/dist/features/aggregation/aggregationFeature.d.ts +10 -0
- package/dist/features/aggregation/aggregationFeature.js +38 -0
- package/dist/features/aggregation/aggregationFeature.js.map +1 -0
- package/dist/features/aggregation/aggregationFeature.types.cjs +13 -0
- package/dist/features/aggregation/aggregationFeature.types.cjs.map +1 -0
- package/dist/features/aggregation/aggregationFeature.types.d.cts +172 -0
- package/dist/features/aggregation/aggregationFeature.types.d.ts +172 -0
- package/dist/features/aggregation/aggregationFeature.types.js +12 -0
- package/dist/features/aggregation/aggregationFeature.types.js.map +1 -0
- package/dist/features/aggregation/aggregationFeature.utils.cjs +198 -0
- package/dist/features/aggregation/aggregationFeature.utils.cjs.map +1 -0
- package/dist/features/aggregation/aggregationFeature.utils.d.cts +33 -0
- package/dist/features/aggregation/aggregationFeature.utils.d.ts +33 -0
- package/dist/features/aggregation/aggregationFeature.utils.js +192 -0
- package/dist/features/aggregation/aggregationFeature.utils.js.map +1 -0
- package/dist/features/aggregation/aggregationFns.cjs +240 -0
- package/dist/features/aggregation/aggregationFns.cjs.map +1 -0
- package/dist/features/aggregation/aggregationFns.d.cts +67 -0
- package/dist/features/aggregation/aggregationFns.d.ts +67 -0
- package/dist/features/aggregation/aggregationFns.js +229 -0
- package/dist/features/aggregation/aggregationFns.js.map +1 -0
- package/dist/features/column-faceting/createFacetedMinMaxValues.cjs +7 -4
- package/dist/features/column-faceting/createFacetedMinMaxValues.cjs.map +1 -1
- package/dist/features/column-faceting/createFacetedMinMaxValues.js +8 -5
- package/dist/features/column-faceting/createFacetedMinMaxValues.js.map +1 -1
- package/dist/features/column-faceting/createFacetedRowModel.cjs +1 -1
- package/dist/features/column-faceting/createFacetedRowModel.cjs.map +1 -1
- package/dist/features/column-faceting/createFacetedRowModel.js +1 -1
- package/dist/features/column-faceting/createFacetedRowModel.js.map +1 -1
- package/dist/features/column-faceting/createFacetedUniqueValues.cjs +8 -4
- package/dist/features/column-faceting/createFacetedUniqueValues.cjs.map +1 -1
- package/dist/features/column-faceting/createFacetedUniqueValues.js +9 -5
- package/dist/features/column-faceting/createFacetedUniqueValues.js.map +1 -1
- package/dist/features/column-filtering/columnFilteringFeature.types.d.cts +1 -1
- package/dist/features/column-filtering/columnFilteringFeature.types.d.ts +1 -1
- package/dist/{fns → features/column-filtering}/filterFns.cjs +1 -1
- package/dist/features/column-filtering/filterFns.cjs.map +1 -0
- package/dist/{fns → features/column-filtering}/filterFns.d.cts +4 -4
- package/dist/{fns → features/column-filtering}/filterFns.d.ts +4 -4
- package/dist/{fns → features/column-filtering}/filterFns.js +1 -1
- package/dist/features/column-filtering/filterFns.js.map +1 -0
- package/dist/features/column-grouping/columnGroupingFeature.cjs +3 -12
- package/dist/features/column-grouping/columnGroupingFeature.cjs.map +1 -1
- package/dist/features/column-grouping/columnGroupingFeature.d.cts +1 -1
- package/dist/features/column-grouping/columnGroupingFeature.d.ts +1 -1
- package/dist/features/column-grouping/columnGroupingFeature.js +4 -13
- package/dist/features/column-grouping/columnGroupingFeature.js.map +1 -1
- package/dist/features/column-grouping/columnGroupingFeature.types.d.cts +6 -87
- package/dist/features/column-grouping/columnGroupingFeature.types.d.ts +6 -87
- package/dist/features/column-grouping/columnGroupingFeature.utils.cjs +0 -64
- package/dist/features/column-grouping/columnGroupingFeature.utils.cjs.map +1 -1
- package/dist/features/column-grouping/columnGroupingFeature.utils.d.cts +2 -44
- package/dist/features/column-grouping/columnGroupingFeature.utils.d.ts +2 -44
- package/dist/features/column-grouping/columnGroupingFeature.utils.js +2 -63
- package/dist/features/column-grouping/columnGroupingFeature.utils.js.map +1 -1
- package/dist/features/column-grouping/createGroupedRowModel.cjs +23 -16
- package/dist/features/column-grouping/createGroupedRowModel.cjs.map +1 -1
- package/dist/features/column-grouping/createGroupedRowModel.d.cts +2 -6
- package/dist/features/column-grouping/createGroupedRowModel.d.ts +2 -6
- package/dist/features/column-grouping/createGroupedRowModel.js +25 -18
- package/dist/features/column-grouping/createGroupedRowModel.js.map +1 -1
- package/dist/features/global-filtering/globalFilteringFeature.utils.cjs +1 -1
- package/dist/features/global-filtering/globalFilteringFeature.utils.cjs.map +1 -1
- package/dist/features/global-filtering/globalFilteringFeature.utils.js +1 -1
- package/dist/features/global-filtering/globalFilteringFeature.utils.js.map +1 -1
- package/dist/features/row-sorting/rowSortingFeature.types.d.cts +1 -1
- package/dist/features/row-sorting/rowSortingFeature.types.d.ts +1 -1
- package/dist/features/row-sorting/rowSortingFeature.utils.cjs +1 -1
- package/dist/features/row-sorting/rowSortingFeature.utils.cjs.map +1 -1
- package/dist/features/row-sorting/rowSortingFeature.utils.js +1 -1
- package/dist/features/row-sorting/rowSortingFeature.utils.js.map +1 -1
- package/dist/{fns → features/row-sorting}/sortFns.cjs +1 -1
- package/dist/{fns/sortFns.js.map → features/row-sorting/sortFns.cjs.map} +1 -1
- package/dist/{fns → features/row-sorting}/sortFns.d.cts +4 -4
- package/dist/{fns → features/row-sorting}/sortFns.d.ts +4 -4
- package/dist/{fns → features/row-sorting}/sortFns.js +1 -1
- package/dist/features/row-sorting/sortFns.js.map +1 -0
- package/dist/features/stockFeatures.cjs +2 -0
- package/dist/features/stockFeatures.cjs.map +1 -1
- package/dist/features/stockFeatures.d.cts +2 -0
- package/dist/features/stockFeatures.d.ts +2 -0
- package/dist/features/stockFeatures.js +2 -0
- package/dist/features/stockFeatures.js.map +1 -1
- package/dist/index.cjs +7 -4
- package/dist/index.d.cts +7 -5
- package/dist/index.d.ts +7 -5
- package/dist/index.js +6 -4
- package/dist/static-functions.cjs +8 -3
- package/dist/static-functions.d.cts +3 -2
- package/dist/static-functions.d.ts +3 -2
- package/dist/static-functions.js +3 -2
- package/dist/types/Cell.d.cts +3 -1
- package/dist/types/Cell.d.ts +3 -1
- package/dist/types/Column.d.cts +4 -2
- package/dist/types/Column.d.ts +4 -2
- package/dist/types/ColumnDef.d.cts +5 -3
- package/dist/types/ColumnDef.d.ts +5 -3
- package/dist/types/Row.d.cts +3 -1
- package/dist/types/Row.d.ts +3 -1
- package/dist/types/RowModel.d.cts +1 -1
- package/dist/types/RowModel.d.ts +1 -1
- package/dist/types/RowModelFns.d.cts +3 -3
- package/dist/types/RowModelFns.d.ts +3 -3
- package/dist/types/Table.d.cts +1 -1
- package/dist/types/Table.d.ts +1 -1
- package/dist/types/TableFeatures.d.cts +4 -4
- package/dist/types/TableFeatures.d.ts +4 -4
- package/dist/types/TableOptions.d.cts +5 -3
- package/dist/types/TableOptions.d.ts +5 -3
- package/dist/types/TableState.d.cts +1 -1
- package/dist/types/TableState.d.ts +1 -1
- package/dist/worker/initTableWorker.cjs.map +1 -1
- package/dist/worker/initTableWorker.js.map +1 -1
- package/package.json +1 -1
- package/skills/aggregation/SKILL.md +131 -0
- package/skills/api-not-found/SKILL.md +1 -1
- package/skills/client-vs-server/SKILL.md +1 -1
- package/skills/column-faceting/SKILL.md +1 -1
- package/skills/column-filtering/SKILL.md +1 -1
- package/skills/column-ordering/SKILL.md +1 -1
- package/skills/column-pinning/SKILL.md +1 -1
- package/skills/column-resizing/SKILL.md +1 -1
- package/skills/column-sizing/SKILL.md +1 -1
- package/skills/column-visibility/SKILL.md +1 -1
- package/skills/core/SKILL.md +1 -1
- package/skills/custom-features/SKILL.md +1 -1
- package/skills/expanding/SKILL.md +1 -1
- package/skills/global-filtering/SKILL.md +1 -1
- package/skills/grouping/SKILL.md +12 -18
- package/skills/migrate-v8-to-v9/SKILL.md +15 -2
- package/skills/pagination/SKILL.md +1 -1
- package/skills/row-pinning/SKILL.md +1 -1
- package/skills/row-selection/SKILL.md +1 -1
- package/skills/sorting/SKILL.md +1 -1
- package/skills/table-features/SKILL.md +5 -2
- package/skills/typescript/SKILL.md +1 -1
- package/src/core/row-models/coreRowModelsFeature.utils.ts +1 -1
- package/src/features/aggregation/aggregationFeature.ts +59 -0
- package/src/features/aggregation/aggregationFeature.types.ts +312 -0
- package/src/features/aggregation/aggregationFeature.utils.ts +401 -0
- package/src/features/aggregation/aggregationFns.ts +336 -0
- package/src/features/column-faceting/createFacetedMinMaxValues.ts +33 -7
- package/src/features/column-faceting/createFacetedRowModel.ts +4 -1
- package/src/features/column-faceting/createFacetedUniqueValues.ts +45 -11
- package/src/features/column-filtering/columnFilteringFeature.types.ts +1 -1
- package/src/{fns → features/column-filtering}/filterFns.ts +4 -4
- package/src/features/column-grouping/columnGroupingFeature.ts +1 -20
- package/src/features/column-grouping/columnGroupingFeature.types.ts +4 -141
- package/src/features/column-grouping/columnGroupingFeature.utils.ts +1 -122
- package/src/features/column-grouping/createGroupedRowModel.ts +32 -41
- package/src/features/global-filtering/globalFilteringFeature.utils.ts +1 -1
- package/src/features/row-sorting/rowSortingFeature.types.ts +1 -1
- package/src/features/row-sorting/rowSortingFeature.utils.ts +1 -1
- package/src/{fns → features/row-sorting}/sortFns.ts +4 -7
- package/src/features/stockFeatures.ts +3 -0
- package/src/index.ts +7 -8
- package/src/static-functions.ts +1 -0
- package/src/types/Cell.ts +2 -0
- package/src/types/Column.ts +3 -1
- package/src/types/ColumnDef.ts +6 -3
- package/src/types/Row.ts +2 -0
- package/src/types/RowModelFns.ts +3 -3
- package/src/types/TableFeatures.ts +4 -4
- package/src/types/TableOptions.ts +5 -1
- package/src/worker/initTableWorker.ts +1 -1
- package/dist/fns/aggregationFns.cjs +0 -234
- package/dist/fns/aggregationFns.cjs.map +0 -1
- package/dist/fns/aggregationFns.d.cts +0 -139
- package/dist/fns/aggregationFns.d.ts +0 -139
- package/dist/fns/aggregationFns.js +0 -221
- package/dist/fns/aggregationFns.js.map +0 -1
- package/dist/fns/filterFns.cjs.map +0 -1
- package/dist/fns/filterFns.js.map +0 -1
- package/dist/fns/sortFns.cjs.map +0 -1
- package/src/fns/aggregationFns.ts +0 -303
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
//#region src/fns/aggregationFns.ts
|
|
2
|
-
/**
|
|
3
|
-
* Builds an `AggregationFn` from a value-level reducer plus optional
|
|
4
|
-
* `resolveDataValue` and `fromRows` settings.
|
|
5
|
-
*
|
|
6
|
-
* The `aggregate` reducer receives an array of the group rows' values, each
|
|
7
|
-
* already passed through `resolveDataValue` when one is defined. Keeping
|
|
8
|
-
* normalization in the resolver means a variant of an existing aggregation
|
|
9
|
-
* function only has to swap the resolver, not re-implement the computation.
|
|
10
|
-
*
|
|
11
|
-
* The definition is attached to the returned function, so a variant can be
|
|
12
|
-
* created by spreading a built-in aggregation function and overriding what
|
|
13
|
-
* differs. For example, a `min` that works on date columns:
|
|
14
|
-
*
|
|
15
|
-
* ```ts
|
|
16
|
-
* const earliest = constructAggregationFn({
|
|
17
|
-
* ...aggregationFn_min,
|
|
18
|
-
* resolveDataValue: (value) =>
|
|
19
|
-
* value instanceof Date ? value.getTime() : value,
|
|
20
|
-
* })
|
|
21
|
-
* ```
|
|
22
|
-
*
|
|
23
|
-
* The built-in `count`, `first`, and `last` aggregation functions are plain
|
|
24
|
-
* row-level functions instead: they read group position or size and never
|
|
25
|
-
* look at every value, so materializing a values array would be wasted work.
|
|
26
|
-
*/
|
|
27
|
-
function constructAggregationFn(def) {
|
|
28
|
-
const aggregationFn = Object.assign((columnId, leafRows, childRows) => {
|
|
29
|
-
const rows = aggregationFn.fromRows === "childRows" ? childRows : leafRows;
|
|
30
|
-
const resolveDataValue = aggregationFn.resolveDataValue;
|
|
31
|
-
const values = new Array(rows.length);
|
|
32
|
-
for (let i = 0; i < rows.length; i++) {
|
|
33
|
-
const value = rows[i].getValue(columnId);
|
|
34
|
-
values[i] = resolveDataValue ? resolveDataValue(value) : value;
|
|
35
|
-
}
|
|
36
|
-
return aggregationFn.aggregate(values, rows, columnId);
|
|
37
|
-
}, def);
|
|
38
|
-
return aggregationFn;
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Sums numeric child-row values for a grouped column.
|
|
42
|
-
*
|
|
43
|
-
* Non-number values contribute `0`. Child rows are used so nested group totals
|
|
44
|
-
* can reuse already aggregated values.
|
|
45
|
-
*/
|
|
46
|
-
const aggregationFn_sum = constructAggregationFn({
|
|
47
|
-
fromRows: "childRows",
|
|
48
|
-
aggregate: (values) => {
|
|
49
|
-
let sumValue = 0;
|
|
50
|
-
for (let i = 0; i < values.length; i++) {
|
|
51
|
-
const nextValue = values[i];
|
|
52
|
-
sumValue += typeof nextValue === "number" ? nextValue : 0;
|
|
53
|
-
}
|
|
54
|
-
return sumValue;
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
/**
|
|
58
|
-
* Finds the minimum numeric child-row value for a grouped column.
|
|
59
|
-
*
|
|
60
|
-
* Nullish and non-number values are ignored. Returns `undefined` when no
|
|
61
|
-
* numeric value is found.
|
|
62
|
-
*/
|
|
63
|
-
const aggregationFn_min = constructAggregationFn({
|
|
64
|
-
fromRows: "childRows",
|
|
65
|
-
aggregate: (values) => {
|
|
66
|
-
let minValue;
|
|
67
|
-
for (let i = 0; i < values.length; i++) {
|
|
68
|
-
const value = values[i];
|
|
69
|
-
if (typeof value === "number" && (minValue === void 0 || value < minValue)) minValue = value;
|
|
70
|
-
}
|
|
71
|
-
return minValue;
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
/**
|
|
75
|
-
* Finds the maximum numeric child-row value for a grouped column.
|
|
76
|
-
*
|
|
77
|
-
* Nullish and non-number values are ignored. Returns `undefined` when no
|
|
78
|
-
* numeric value is found.
|
|
79
|
-
*/
|
|
80
|
-
const aggregationFn_max = constructAggregationFn({
|
|
81
|
-
fromRows: "childRows",
|
|
82
|
-
aggregate: (values) => {
|
|
83
|
-
let maxValue;
|
|
84
|
-
for (let i = 0; i < values.length; i++) {
|
|
85
|
-
const value = values[i];
|
|
86
|
-
if (typeof value === "number" && (maxValue === void 0 || value > maxValue)) maxValue = value;
|
|
87
|
-
}
|
|
88
|
-
return maxValue;
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
/**
|
|
92
|
-
* Finds the numeric extent for a grouped column.
|
|
93
|
-
*
|
|
94
|
-
* Returns `[min, max]`, where each entry is `undefined` when no numeric value is
|
|
95
|
-
* present.
|
|
96
|
-
*/
|
|
97
|
-
const aggregationFn_extent = constructAggregationFn({
|
|
98
|
-
fromRows: "childRows",
|
|
99
|
-
aggregate: (values) => {
|
|
100
|
-
let minValue;
|
|
101
|
-
let maxValue;
|
|
102
|
-
for (let i = 0; i < values.length; i++) {
|
|
103
|
-
const value = values[i];
|
|
104
|
-
if (typeof value === "number") if (minValue === void 0) minValue = maxValue = value;
|
|
105
|
-
else {
|
|
106
|
-
if (minValue > value) minValue = value;
|
|
107
|
-
if (maxValue < value) maxValue = value;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
return [minValue, maxValue];
|
|
111
|
-
}
|
|
112
|
-
});
|
|
113
|
-
/**
|
|
114
|
-
* Averages numeric leaf-row values for a grouped column.
|
|
115
|
-
*
|
|
116
|
-
* Number-like values are coerced with unary `+`; nullish and non-numeric values
|
|
117
|
-
* are ignored.
|
|
118
|
-
*/
|
|
119
|
-
const aggregationFn_mean = constructAggregationFn({ aggregate: (values) => {
|
|
120
|
-
let count = 0;
|
|
121
|
-
let sumValue = 0;
|
|
122
|
-
for (let i = 0; i < values.length; i++) {
|
|
123
|
-
const value = values[i];
|
|
124
|
-
if (value != null && typeof value === "number") {
|
|
125
|
-
++count;
|
|
126
|
-
sumValue += value;
|
|
127
|
-
} else if (value != null) {
|
|
128
|
-
const numValue = +value;
|
|
129
|
-
if (!Number.isNaN(numValue)) {
|
|
130
|
-
++count;
|
|
131
|
-
sumValue += numValue;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
if (count) return sumValue / count;
|
|
136
|
-
} });
|
|
137
|
-
/**
|
|
138
|
-
* Computes the median of numeric leaf-row values for a grouped column.
|
|
139
|
-
*
|
|
140
|
-
* All values must be numbers. If any value is non-numeric, or no leaf rows are
|
|
141
|
-
* present, the result is `undefined`.
|
|
142
|
-
*/
|
|
143
|
-
const aggregationFn_median = constructAggregationFn({ aggregate: (values) => {
|
|
144
|
-
if (!values.length) return;
|
|
145
|
-
for (let i = 0; i < values.length; i++) if (typeof values[i] !== "number") return;
|
|
146
|
-
if (values.length === 1) return values[0];
|
|
147
|
-
const mid = Math.floor(values.length / 2);
|
|
148
|
-
values.sort((a, b) => a - b);
|
|
149
|
-
return values.length % 2 !== 0 ? values[mid] : (values[mid - 1] + values[mid]) / 2;
|
|
150
|
-
} });
|
|
151
|
-
/**
|
|
152
|
-
* Collects unique leaf-row values for a grouped column.
|
|
153
|
-
*
|
|
154
|
-
* Values are compared with JavaScript `Set` semantics.
|
|
155
|
-
*/
|
|
156
|
-
const aggregationFn_unique = constructAggregationFn({ aggregate: (values) => Array.from(new Set(values).values()) });
|
|
157
|
-
/**
|
|
158
|
-
* Counts unique leaf-row values for a grouped column.
|
|
159
|
-
*
|
|
160
|
-
* Values are compared with JavaScript `Set` semantics.
|
|
161
|
-
*/
|
|
162
|
-
const aggregationFn_uniqueCount = constructAggregationFn({ aggregate: (values) => new Set(values).size });
|
|
163
|
-
/**
|
|
164
|
-
* Counts the number of leaf rows in the group.
|
|
165
|
-
*
|
|
166
|
-
* The column id is ignored because the result is based only on group size.
|
|
167
|
-
* This is a plain row-level function (not built with
|
|
168
|
-
* `constructAggregationFn`) because it never reads row values.
|
|
169
|
-
*/
|
|
170
|
-
function aggregationFn_count(_columnId, leafRows) {
|
|
171
|
-
return leafRows.length;
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* Returns the first leaf-row value for a grouped column.
|
|
175
|
-
*
|
|
176
|
-
* This is a plain row-level function (not built with
|
|
177
|
-
* `constructAggregationFn`) because it only reads one positional value.
|
|
178
|
-
*/
|
|
179
|
-
function aggregationFn_first(columnId, leafRows) {
|
|
180
|
-
return leafRows[0]?.getValue(columnId);
|
|
181
|
-
}
|
|
182
|
-
/**
|
|
183
|
-
* Returns the last leaf-row value for a grouped column.
|
|
184
|
-
*
|
|
185
|
-
* This is a plain row-level function (not built with
|
|
186
|
-
* `constructAggregationFn`) because it only reads one positional value.
|
|
187
|
-
*/
|
|
188
|
-
function aggregationFn_last(columnId, leafRows) {
|
|
189
|
-
return leafRows[leafRows.length - 1]?.getValue(columnId);
|
|
190
|
-
}
|
|
191
|
-
/**
|
|
192
|
-
* The built-in aggregation function registry.
|
|
193
|
-
*
|
|
194
|
-
* Registering this full object opts out of tree-shaking: every built-in
|
|
195
|
-
* aggregation function ends up in your bundle. Prefer importing the
|
|
196
|
-
* `aggregationFn_*` functions you actually use and registering just those in
|
|
197
|
-
* the `aggregationFns` slot, or passing them directly to the `aggregationFn`
|
|
198
|
-
* column option.
|
|
199
|
-
*
|
|
200
|
-
* @deprecated Import individual `aggregationFn_*` functions instead for a
|
|
201
|
-
* smaller bundle. This export still works and is not going away in v9, but
|
|
202
|
-
* built-in name resolution (including `aggregationFn: 'auto'`) only finds
|
|
203
|
-
* functions you register yourself.
|
|
204
|
-
*/
|
|
205
|
-
const aggregationFns = {
|
|
206
|
-
sum: aggregationFn_sum,
|
|
207
|
-
min: aggregationFn_min,
|
|
208
|
-
max: aggregationFn_max,
|
|
209
|
-
extent: aggregationFn_extent,
|
|
210
|
-
mean: aggregationFn_mean,
|
|
211
|
-
median: aggregationFn_median,
|
|
212
|
-
unique: aggregationFn_unique,
|
|
213
|
-
uniqueCount: aggregationFn_uniqueCount,
|
|
214
|
-
count: aggregationFn_count,
|
|
215
|
-
first: aggregationFn_first,
|
|
216
|
-
last: aggregationFn_last
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
//#endregion
|
|
220
|
-
export { aggregationFn_count, aggregationFn_extent, aggregationFn_first, aggregationFn_last, aggregationFn_max, aggregationFn_mean, aggregationFn_median, aggregationFn_min, aggregationFn_sum, aggregationFn_unique, aggregationFn_uniqueCount, aggregationFns, constructAggregationFn };
|
|
221
|
-
//# sourceMappingURL=aggregationFns.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"aggregationFns.js","names":[],"sources":["../../src/fns/aggregationFns.ts"],"sourcesContent":["import type {\n AggregationFnDef,\n CreatedAggregationFn,\n} from '../features/column-grouping/columnGroupingFeature.types'\nimport type { RowData } from '../types/type-utils'\nimport type { TableFeatures } from '../types/TableFeatures'\nimport type { Row } from '../types/Row'\n\n/**\n * Builds an `AggregationFn` from a value-level reducer plus optional\n * `resolveDataValue` and `fromRows` settings.\n *\n * The `aggregate` reducer receives an array of the group rows' values, each\n * already passed through `resolveDataValue` when one is defined. Keeping\n * normalization in the resolver means a variant of an existing aggregation\n * function only has to swap the resolver, not re-implement the computation.\n *\n * The definition is attached to the returned function, so a variant can be\n * created by spreading a built-in aggregation function and overriding what\n * differs. For example, a `min` that works on date columns:\n *\n * ```ts\n * const earliest = constructAggregationFn({\n * ...aggregationFn_min,\n * resolveDataValue: (value) =>\n * value instanceof Date ? value.getTime() : value,\n * })\n * ```\n *\n * The built-in `count`, `first`, and `last` aggregation functions are plain\n * row-level functions instead: they read group position or size and never\n * look at every value, so materializing a values array would be wasted work.\n */\nexport function constructAggregationFn<\n TFeatures extends TableFeatures = any,\n TData extends RowData = any,\n>(\n def: AggregationFnDef<TFeatures, TData>,\n): CreatedAggregationFn<TFeatures, TData> {\n const aggregationFn: CreatedAggregationFn<TFeatures, TData> = Object.assign(\n <TRowFeatures extends TableFeatures, TRowData extends RowData>(\n columnId: string,\n leafRows: Array<Row<TRowFeatures, TRowData>>,\n childRows: Array<Row<TRowFeatures, TRowData>>,\n ): any => {\n const rows = aggregationFn.fromRows === 'childRows' ? childRows : leafRows\n const resolveDataValue = aggregationFn.resolveDataValue\n const values: Array<any> = new Array(rows.length)\n for (let i = 0; i < rows.length; i++) {\n const value = rows[i]!.getValue(columnId)\n values[i] = resolveDataValue ? resolveDataValue(value) : value\n }\n // The def's reducer is typed against the factory's TFeatures/TData;\n // the caller's row generics are erased at this boundary.\n return aggregationFn.aggregate(values, rows as any, columnId)\n },\n def,\n )\n return aggregationFn\n}\n\n/**\n * Sums numeric child-row values for a grouped column.\n *\n * Non-number values contribute `0`. Child rows are used so nested group totals\n * can reuse already aggregated values.\n */\nexport const aggregationFn_sum = constructAggregationFn({\n fromRows: 'childRows',\n aggregate: (values) => {\n let sumValue = 0\n for (let i = 0; i < values.length; i++) {\n const nextValue = values[i]\n sumValue += typeof nextValue === 'number' ? nextValue : 0\n }\n return sumValue\n },\n})\n\n/**\n * Finds the minimum numeric child-row value for a grouped column.\n *\n * Nullish and non-number values are ignored. Returns `undefined` when no\n * numeric value is found.\n */\nexport const aggregationFn_min = constructAggregationFn({\n fromRows: 'childRows',\n aggregate: (values) => {\n let minValue: number | undefined\n\n for (let i = 0; i < values.length; i++) {\n const value = values[i]\n if (\n typeof value === 'number' &&\n (minValue === undefined || value < minValue)\n ) {\n minValue = value\n }\n }\n\n return minValue\n },\n})\n\n/**\n * Finds the maximum numeric child-row value for a grouped column.\n *\n * Nullish and non-number values are ignored. Returns `undefined` when no\n * numeric value is found.\n */\nexport const aggregationFn_max = constructAggregationFn({\n fromRows: 'childRows',\n aggregate: (values) => {\n let maxValue: number | undefined\n\n for (let i = 0; i < values.length; i++) {\n const value = values[i]\n if (\n typeof value === 'number' &&\n (maxValue === undefined || value > maxValue)\n ) {\n maxValue = value\n }\n }\n\n return maxValue\n },\n})\n\n/**\n * Finds the numeric extent for a grouped column.\n *\n * Returns `[min, max]`, where each entry is `undefined` when no numeric value is\n * present.\n */\nexport const aggregationFn_extent = constructAggregationFn({\n fromRows: 'childRows',\n aggregate: (values) => {\n let minValue: number | undefined\n let maxValue: number | undefined\n\n for (let i = 0; i < values.length; i++) {\n const value = values[i]\n if (typeof value === 'number') {\n if (minValue === undefined) {\n minValue = maxValue = value\n } else {\n if (minValue > value) minValue = value\n if (maxValue! < value) maxValue = value\n }\n }\n }\n\n return [minValue, maxValue]\n },\n})\n\n/**\n * Averages numeric leaf-row values for a grouped column.\n *\n * Number-like values are coerced with unary `+`; nullish and non-numeric values\n * are ignored.\n */\nexport const aggregationFn_mean = constructAggregationFn({\n aggregate: (values) => {\n let count = 0\n let sumValue = 0\n\n for (let i = 0; i < values.length; i++) {\n const value = values[i]\n if (value != null && typeof value === 'number') {\n ++count\n sumValue += value\n } else if (value != null) {\n const numValue = +value\n if (!Number.isNaN(numValue)) {\n ++count\n sumValue += numValue\n }\n }\n }\n\n if (count) return sumValue / count\n\n return\n },\n})\n\n/**\n * Computes the median of numeric leaf-row values for a grouped column.\n *\n * All values must be numbers. If any value is non-numeric, or no leaf rows are\n * present, the result is `undefined`.\n */\nexport const aggregationFn_median = constructAggregationFn({\n aggregate: (values: Array<number>) => {\n if (!values.length) {\n return\n }\n\n for (let i = 0; i < values.length; i++) {\n if (typeof values[i] !== 'number') return\n }\n\n if (values.length === 1) {\n return values[0]\n }\n\n const mid = Math.floor(values.length / 2)\n values.sort((a, b) => a - b)\n return values.length % 2 !== 0\n ? values[mid]\n : (values[mid - 1]! + values[mid]!) / 2\n },\n})\n\n/**\n * Collects unique leaf-row values for a grouped column.\n *\n * Values are compared with JavaScript `Set` semantics.\n */\nexport const aggregationFn_unique = constructAggregationFn({\n aggregate: (values) => Array.from(new Set(values).values()),\n})\n\n/**\n * Counts unique leaf-row values for a grouped column.\n *\n * Values are compared with JavaScript `Set` semantics.\n */\nexport const aggregationFn_uniqueCount = constructAggregationFn({\n aggregate: (values) => new Set(values).size,\n})\n\n/**\n * Counts the number of leaf rows in the group.\n *\n * The column id is ignored because the result is based only on group size.\n * This is a plain row-level function (not built with\n * `constructAggregationFn`) because it never reads row values.\n */\nexport function aggregationFn_count<\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(_columnId: string, leafRows: Array<Row<TFeatures, TData>>) {\n return leafRows.length\n}\n\n/**\n * Returns the first leaf-row value for a grouped column.\n *\n * This is a plain row-level function (not built with\n * `constructAggregationFn`) because it only reads one positional value.\n */\nexport function aggregationFn_first<\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(columnId: string, leafRows: Array<Row<TFeatures, TData>>) {\n return leafRows[0]?.getValue(columnId)\n}\n\n/**\n * Returns the last leaf-row value for a grouped column.\n *\n * This is a plain row-level function (not built with\n * `constructAggregationFn`) because it only reads one positional value.\n */\nexport function aggregationFn_last<\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(columnId: string, leafRows: Array<Row<TFeatures, TData>>) {\n return leafRows[leafRows.length - 1]?.getValue(columnId)\n}\n\n/**\n * The built-in aggregation function registry.\n *\n * Registering this full object opts out of tree-shaking: every built-in\n * aggregation function ends up in your bundle. Prefer importing the\n * `aggregationFn_*` functions you actually use and registering just those in\n * the `aggregationFns` slot, or passing them directly to the `aggregationFn`\n * column option.\n *\n * @deprecated Import individual `aggregationFn_*` functions instead for a\n * smaller bundle. This export still works and is not going away in v9, but\n * built-in name resolution (including `aggregationFn: 'auto'`) only finds\n * functions you register yourself.\n */\nexport const aggregationFns = {\n sum: aggregationFn_sum,\n min: aggregationFn_min,\n max: aggregationFn_max,\n extent: aggregationFn_extent,\n mean: aggregationFn_mean,\n median: aggregationFn_median,\n unique: aggregationFn_unique,\n uniqueCount: aggregationFn_uniqueCount,\n count: aggregationFn_count,\n first: aggregationFn_first,\n last: aggregationFn_last,\n}\n\nexport type BuiltInAggregationFn = keyof typeof aggregationFns\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"filterFns.cjs","names":[],"sources":["../../src/fns/filterFns.ts"],"sourcesContent":["import type {\n CreatedFilterFn,\n ExtractFilterMeta,\n FilterFnDef,\n} from '../features/column-filtering/columnFilteringFeature.types'\nimport type { RowData } from '../types/type-utils'\nimport type { TableFeatures } from '../types/TableFeatures'\nimport type { Row } from '../types/Row'\n\n/**\n * Builds a `FilterFn` from a value-level comparator plus optional resolvers.\n *\n * The `filter` comparator receives the row's data value (already passed\n * through `resolveDataValue` when one is defined) and the filter value\n * (already passed through `resolveFilterValue` by the table). Keeping\n * normalization in the resolvers means a variant of an existing filter\n * function only has to swap the resolvers, not re-implement the comparison.\n *\n * The definition is attached to the returned function, so a variant can be\n * created by spreading a built-in filter function and overriding what differs:\n *\n * ```ts\n * const normalize = (value: unknown) =>\n * String(value ?? '')\n * .toLowerCase()\n * .normalize('NFD')\n * .replace(/\\p{Diacritic}/gu, '')\n *\n * const includesStringIgnoreDiacritics = constructFilterFn({\n * ...filterFn_includesString,\n * resolveFilterValue: normalize,\n * resolveDataValue: normalize,\n * })\n * ```\n *\n * Note: the table applies `resolveFilterValue` once per filter before any rows\n * are tested. When calling a filter function directly (outside of a table),\n * apply it yourself: `fn(row, columnId, fn.resolveFilterValue?.(value) ?? value)`.\n */\nexport function constructFilterFn<\n TFeatures extends TableFeatures = any,\n TData extends RowData = any,\n>(def: FilterFnDef<TFeatures, TData>): CreatedFilterFn<TFeatures, TData> {\n const filterFn: CreatedFilterFn<TFeatures, TData> = Object.assign(\n <TRowFeatures extends TableFeatures, TRowData extends RowData>(\n row: Row<TRowFeatures, TRowData>,\n columnId: string,\n filterValue: any,\n addMeta?: (meta: ExtractFilterMeta<TRowFeatures>) => void,\n ): boolean => {\n const rawValue = row.getValue(columnId)\n const dataValue = filterFn.resolveDataValue\n ? filterFn.resolveDataValue(rawValue)\n : rawValue\n // The def's comparator is typed against the factory's TFeatures/TData;\n // the caller's row generics are erased at this boundary.\n return filterFn.filter(\n dataValue,\n filterValue,\n row as any,\n columnId,\n addMeta as any,\n )\n },\n def,\n )\n return filterFn\n}\n\n// Basic filters\n\n/**\n * Keeps rows whose column value is strictly equal to the filter value.\n *\n * Uses JavaScript `===` comparison and auto-removes empty filter values.\n */\nexport const filterFn_equals = constructFilterFn({\n filter: (dataValue, filterValue) => dataValue === filterValue,\n autoRemove: (val: any) => testFalsy(val),\n})\n\n/**\n * Keeps rows whose column value is loosely equal to the filter value.\n *\n * Uses JavaScript `==` comparison and auto-removes empty filter values. This is\n * useful for matching string input against numeric row values.\n */\nexport const filterFn_weakEquals = constructFilterFn({\n filter: (dataValue, filterValue) => dataValue == filterValue,\n autoRemove: (val: any) => testFalsy(val),\n})\n\n// String filters\n\n/**\n * Keeps rows whose stringified column value includes the filter text.\n *\n * Matching is case-sensitive and empty filter values are auto-removed.\n */\nexport const filterFn_includesStringSensitive = constructFilterFn({\n filter: (dataValue, filterValue) => Boolean(dataValue?.includes(filterValue)),\n autoRemove: (val: any) => testFalsy(val),\n resolveFilterValue: (val: any) => String(val),\n resolveDataValue: (val: any) => (val == null ? undefined : String(val)),\n})\n\n/**\n * Keeps rows whose stringified column value includes the filter text.\n *\n * Both values are lowercased before comparison, and empty filter values are\n * auto-removed.\n */\nexport const filterFn_includesString = constructFilterFn({\n filter: (dataValue, filterValue) => Boolean(dataValue?.includes(filterValue)),\n autoRemove: (val: any) => testFalsy(val),\n resolveFilterValue: (val: any) => String(val).toLowerCase(),\n resolveDataValue: (val: any) =>\n val == null ? undefined : String(val).toLowerCase(),\n})\n\n/**\n * Keeps rows whose stringified column value equals the filter text.\n *\n * Both values are lowercased before comparison, and empty filter values are\n * auto-removed.\n */\nexport const filterFn_equalsString = constructFilterFn({\n filter: (dataValue, filterValue) => dataValue === filterValue,\n autoRemove: (val: any) => testFalsy(val),\n resolveFilterValue: (val: any) => String(val).toLowerCase(),\n resolveDataValue: (val: any) =>\n val == null ? undefined : String(val).toLowerCase(),\n})\n\n/**\n * Keeps rows whose stringified column value exactly equals the filter text.\n *\n * Matching is case-sensitive and empty filter values are auto-removed.\n */\nexport const filterFn_equalsStringSensitive = constructFilterFn({\n filter: (dataValue, filterValue) => dataValue === filterValue,\n autoRemove: (val: any) => testFalsy(val),\n resolveFilterValue: (val: any) => String(val),\n resolveDataValue: (val: any) => (val == null ? undefined : String(val)),\n})\n\n/**\n * Keeps rows whose stringified column value starts with the filter text.\n *\n * Both values are lowercased before comparison, and empty filter values are\n * auto-removed.\n */\nexport const filterFn_startsWith = constructFilterFn({\n filter: (dataValue, filterValue) =>\n Boolean(dataValue?.startsWith(filterValue)),\n autoRemove: (val: any) => testFalsy(val),\n resolveFilterValue: (val: any) => String(val).toLowerCase(),\n resolveDataValue: (val: any) =>\n val == null ? undefined : String(val).toLowerCase(),\n})\n\n/**\n * Keeps rows whose stringified column value ends with the filter text.\n *\n * Both values are lowercased before comparison, and empty filter values are\n * auto-removed.\n */\nexport const filterFn_endsWith = constructFilterFn({\n filter: (dataValue, filterValue) => Boolean(dataValue?.endsWith(filterValue)),\n autoRemove: (val: any) => testFalsy(val),\n resolveFilterValue: (val: any) => String(val).toLowerCase(),\n resolveDataValue: (val: any) =>\n val == null ? undefined : String(val).toLowerCase(),\n})\n\n// Blank filters\n\n/**\n * Keeps rows whose column value is empty.\n *\n * A value is empty when it is nullish or stringifies to whitespace only. The\n * filter value acts as an on/off flag: `false` and blank values are\n * auto-removed.\n */\nexport const filterFn_empty = constructFilterFn({\n filter: (dataValue) => testValueEmpty(dataValue),\n autoRemove: (val: any) => testFalsy(val) || val === false,\n})\n\n/**\n * Keeps rows whose column value is not empty.\n *\n * A value is empty when it is nullish or stringifies to whitespace only. The\n * filter value acts as an on/off flag: `false` and blank values are\n * auto-removed.\n */\nexport const filterFn_notEmpty = constructFilterFn({\n filter: (dataValue) => !testValueEmpty(dataValue),\n autoRemove: (val: any) => testFalsy(val) || val === false,\n})\n\n// Number filters\n\n/**\n * Keeps rows whose value is greater than the filter value.\n *\n * Numeric values are compared numerically when both sides can be coerced to\n * numbers; otherwise normalized strings are compared.\n */\nexport const filterFn_greaterThan = constructFilterFn({\n filter: (dataValue, filterValue) =>\n compareGreaterThan(dataValue, filterValue),\n autoRemove: (val: any) => testFalsy(val),\n})\n\n/**\n * Keeps rows whose value is greater than or equal to the filter value.\n *\n * Delegates to the built-in greater-than and strict-equality comparisons.\n */\nexport const filterFn_greaterThanOrEqualTo = constructFilterFn({\n filter: (dataValue, filterValue) =>\n compareGreaterThanOrEqualTo(dataValue, filterValue),\n autoRemove: (val: any) => testFalsy(val),\n})\n\n/**\n * Keeps rows whose value is less than the filter value.\n *\n * This is implemented as the inverse of greater-than-or-equal comparison.\n */\nexport const filterFn_lessThan = constructFilterFn({\n filter: (dataValue, filterValue) =>\n !compareGreaterThanOrEqualTo(dataValue, filterValue),\n autoRemove: (val: any) => testFalsy(val),\n})\n\n/**\n * Keeps rows whose value is less than or equal to the filter value.\n *\n * This is implemented as the inverse of greater-than comparison.\n */\nexport const filterFn_lessThanOrEqualTo = constructFilterFn({\n filter: (dataValue, filterValue) =>\n !compareGreaterThan(dataValue, filterValue),\n autoRemove: (val: any) => testFalsy(val),\n})\n\n// Range filters\n\n/**\n * Keeps rows whose value falls between an exclusive min/max pair.\n *\n * Blank range endpoints are treated as open-ended.\n */\nexport const filterFn_between = constructFilterFn({\n filter: (dataValue, filterValues: [unknown, unknown]) =>\n compareBetween(dataValue, filterValues, false),\n autoRemove: (val: any) =>\n testFalsy(val) ||\n (Array.isArray(val) && testFalsy(val[0]) && testFalsy(val[1])),\n})\n\n/**\n * Keeps rows whose value falls between an inclusive min/max pair.\n *\n * Blank range endpoints are treated as open-ended.\n */\nexport const filterFn_betweenInclusive = constructFilterFn({\n filter: (dataValue, filterValues: [unknown, unknown]) =>\n compareBetween(dataValue, filterValues, true),\n autoRemove: (val: any) =>\n testFalsy(val) ||\n (Array.isArray(val) && testFalsy(val[0]) && testFalsy(val[1])),\n})\n\n/**\n * Keeps rows whose numeric value is inside an inclusive `[min, max]` range.\n *\n * Filter values are normalized so blank endpoints become open-ended and\n * reversed endpoints are swapped.\n */\nexport const filterFn_inNumberRange = constructFilterFn({\n filter: (dataValue: number, filterValue: [number, number]) => {\n const [min, max] = filterValue\n return dataValue >= min && dataValue <= max\n },\n resolveFilterValue: (val: [any, any]) => {\n const [unsafeMin, unsafeMax] = val\n\n const parsedMin =\n typeof unsafeMin !== 'number' ? parseFloat(unsafeMin) : unsafeMin\n const parsedMax =\n typeof unsafeMax !== 'number' ? parseFloat(unsafeMax) : unsafeMax\n\n let min =\n unsafeMin === null || Number.isNaN(parsedMin) ? -Infinity : parsedMin\n let max =\n unsafeMax === null || Number.isNaN(parsedMax) ? Infinity : parsedMax\n\n if (min > max) {\n const temp = min\n min = max\n max = temp\n }\n\n return [min, max] as const\n },\n autoRemove: (val: any) =>\n testFalsy(val) ||\n (Array.isArray(val) && testFalsy(val[0]) && testFalsy(val[1])),\n})\n\n// Date filters\n\n/**\n * Keeps rows whose date value is inside an inclusive `[min, max]` date range.\n *\n * Row values and range endpoints may be `Date` objects, timestamps, or\n * parseable date strings. Blank or invalid endpoints become open-ended and\n * reversed endpoints are swapped. Rows without a valid date never match.\n */\nexport const filterFn_inDateRange = constructFilterFn({\n filter: (dataValue: number, filterValue: [number, number]) => {\n const [min, max] = filterValue\n return dataValue >= min && dataValue <= max\n },\n resolveFilterValue: (val: [any, any]) => {\n const [unsafeMin, unsafeMax] = val\n\n const parsedMin = toDateTimestamp(unsafeMin)\n const parsedMax = toDateTimestamp(unsafeMax)\n\n let min = Number.isNaN(parsedMin) ? -Infinity : parsedMin\n let max = Number.isNaN(parsedMax) ? Infinity : parsedMax\n\n if (min > max) {\n const temp = min\n min = max\n max = temp\n }\n\n return [min, max] as const\n },\n resolveDataValue: (val: any) => toDateTimestamp(val),\n autoRemove: (val: any) =>\n testFalsy(val) ||\n (Array.isArray(val) && testFalsy(val[0]) && testFalsy(val[1])),\n})\n\n// Array filters\n\n/**\n * Keeps rows whose scalar column value equals at least one filter value.\n */\nexport const filterFn_arrHas = constructFilterFn({\n filter: (dataValue, filterValue: Array<unknown>) => {\n for (let i = 0; i < filterValue.length; i++) {\n if (dataValue === filterValue[i]) {\n return true\n }\n }\n return false\n },\n autoRemove: (val: any) => testFalsy(val) || !val?.length,\n})\n\n/**\n * Keeps rows whose array or string column value includes at least one filter value.\n */\nexport const filterFn_arrIncludes = constructFilterFn({\n filter: (dataValue, filterValue: Array<unknown>) => {\n if (typeof dataValue !== 'string' && !Array.isArray(dataValue)) {\n return false\n }\n\n for (let i = 0; i < filterValue.length; i++) {\n if (dataValue.includes(filterValue[i] as any)) {\n return true\n }\n }\n return false\n },\n autoRemove: (val: any) => testFalsy(val) || !val?.length,\n})\n\n/**\n * Keeps rows whose array column value includes every filter value.\n */\nexport const filterFn_arrIncludesAll = constructFilterFn({\n filter: (dataValue, filterValue: Array<unknown>) => {\n if (!Array.isArray(dataValue)) return false\n for (let i = 0; i < filterValue.length; i++) {\n if (!dataValue.includes(filterValue[i])) {\n return false\n }\n }\n return true\n },\n autoRemove: (val: any) => testFalsy(val) || !val?.length,\n})\n\n/**\n * Keeps rows whose array column value includes at least one filter value.\n */\nexport const filterFn_arrIncludesSome = constructFilterFn({\n filter: (dataValue, filterValue: Array<unknown>) => {\n if (!Array.isArray(dataValue)) return false\n for (let i = 0; i < filterValue.length; i++) {\n if (dataValue.includes(filterValue[i])) {\n return true\n }\n }\n return false\n },\n autoRemove: (val: any) => testFalsy(val) || !val?.length,\n})\n\n// Export\n\n/**\n * The built-in filter function registry.\n *\n * Registering this full object opts out of tree-shaking: every built-in\n * filter function ends up in your bundle. Prefer importing the `filterFn_*`\n * functions you actually use and registering just those in the `filterFns`\n * slot, or passing them directly to the `filterFn` column option.\n *\n * @deprecated Import individual `filterFn_*` functions instead for a smaller\n * bundle. This export still works and is not going away in v9, but built-in\n * name resolution (including `filterFn: 'auto'`) only finds functions you\n * register yourself.\n */\nexport const filterFns = {\n arrIncludes: filterFn_arrIncludes,\n arrIncludesAll: filterFn_arrIncludesAll,\n arrHas: filterFn_arrHas,\n arrIncludesSome: filterFn_arrIncludesSome,\n between: filterFn_between,\n betweenInclusive: filterFn_betweenInclusive,\n empty: filterFn_empty,\n endsWith: filterFn_endsWith,\n equals: filterFn_equals,\n equalsString: filterFn_equalsString,\n equalsStringSensitive: filterFn_equalsStringSensitive,\n inDateRange: filterFn_inDateRange,\n inNumberRange: filterFn_inNumberRange,\n includesString: filterFn_includesString,\n includesStringSensitive: filterFn_includesStringSensitive,\n notEmpty: filterFn_notEmpty,\n startsWith: filterFn_startsWith,\n weakEquals: filterFn_weakEquals,\n}\n\nexport type BuiltInFilterFn = keyof typeof filterFns\n\n// Utils\n\nfunction testFalsy(val: any) {\n return val === undefined || val === null || val === ''\n}\n\nfunction testValueEmpty(dataValue: any) {\n return dataValue == null || String(dataValue).trim() === ''\n}\n\nfunction toDateTimestamp(value: any): number {\n if (value instanceof Date) {\n return value.getTime()\n }\n if (typeof value === 'number') {\n return value\n }\n // Guard nullish and blank values explicitly: `new Date(null)` is the epoch,\n // not an invalid date.\n if (value == null || value === '') {\n return NaN\n }\n return new Date(value).getTime()\n}\n\nfunction compareGreaterThan(dataValue: any, filterValue: any): boolean {\n const numericDataValue = dataValue == null ? 0 : +dataValue\n const numericFilterValue = Number(filterValue)\n\n if (!isNaN(numericFilterValue) && !isNaN(numericDataValue)) {\n return numericDataValue > numericFilterValue\n }\n\n const stringDataValue = String(dataValue ?? '')\n .toLowerCase()\n .trim()\n const stringFilterValue = String(filterValue).toLowerCase().trim()\n return stringDataValue > stringFilterValue\n}\n\nfunction compareGreaterThanOrEqualTo(dataValue: any, filterValue: any) {\n return dataValue === filterValue || compareGreaterThan(dataValue, filterValue)\n}\n\nfunction compareBetween(\n dataValue: any,\n filterValues: [unknown, unknown],\n inclusive: boolean,\n): boolean {\n const min = filterValues[0]\n const hasMin = min !== '' && min !== undefined\n if (hasMin) {\n const passesMin = inclusive\n ? compareGreaterThanOrEqualTo(dataValue, min)\n : compareGreaterThan(dataValue, min)\n if (!passesMin) {\n return false\n }\n }\n\n const max = filterValues[1]\n if (max === '' || max === undefined) {\n return true\n }\n\n if (hasMin) {\n const numericMin = Number(min)\n const numericMax = Number(max)\n if (!isNaN(numericMin) && !isNaN(numericMax) && numericMin > numericMax) {\n return true\n }\n }\n\n return inclusive\n ? !compareGreaterThan(dataValue, max)\n : !compareGreaterThanOrEqualTo(dataValue, max)\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"filterFns.js","names":[],"sources":["../../src/fns/filterFns.ts"],"sourcesContent":["import type {\n CreatedFilterFn,\n ExtractFilterMeta,\n FilterFnDef,\n} from '../features/column-filtering/columnFilteringFeature.types'\nimport type { RowData } from '../types/type-utils'\nimport type { TableFeatures } from '../types/TableFeatures'\nimport type { Row } from '../types/Row'\n\n/**\n * Builds a `FilterFn` from a value-level comparator plus optional resolvers.\n *\n * The `filter` comparator receives the row's data value (already passed\n * through `resolveDataValue` when one is defined) and the filter value\n * (already passed through `resolveFilterValue` by the table). Keeping\n * normalization in the resolvers means a variant of an existing filter\n * function only has to swap the resolvers, not re-implement the comparison.\n *\n * The definition is attached to the returned function, so a variant can be\n * created by spreading a built-in filter function and overriding what differs:\n *\n * ```ts\n * const normalize = (value: unknown) =>\n * String(value ?? '')\n * .toLowerCase()\n * .normalize('NFD')\n * .replace(/\\p{Diacritic}/gu, '')\n *\n * const includesStringIgnoreDiacritics = constructFilterFn({\n * ...filterFn_includesString,\n * resolveFilterValue: normalize,\n * resolveDataValue: normalize,\n * })\n * ```\n *\n * Note: the table applies `resolveFilterValue` once per filter before any rows\n * are tested. When calling a filter function directly (outside of a table),\n * apply it yourself: `fn(row, columnId, fn.resolveFilterValue?.(value) ?? value)`.\n */\nexport function constructFilterFn<\n TFeatures extends TableFeatures = any,\n TData extends RowData = any,\n>(def: FilterFnDef<TFeatures, TData>): CreatedFilterFn<TFeatures, TData> {\n const filterFn: CreatedFilterFn<TFeatures, TData> = Object.assign(\n <TRowFeatures extends TableFeatures, TRowData extends RowData>(\n row: Row<TRowFeatures, TRowData>,\n columnId: string,\n filterValue: any,\n addMeta?: (meta: ExtractFilterMeta<TRowFeatures>) => void,\n ): boolean => {\n const rawValue = row.getValue(columnId)\n const dataValue = filterFn.resolveDataValue\n ? filterFn.resolveDataValue(rawValue)\n : rawValue\n // The def's comparator is typed against the factory's TFeatures/TData;\n // the caller's row generics are erased at this boundary.\n return filterFn.filter(\n dataValue,\n filterValue,\n row as any,\n columnId,\n addMeta as any,\n )\n },\n def,\n )\n return filterFn\n}\n\n// Basic filters\n\n/**\n * Keeps rows whose column value is strictly equal to the filter value.\n *\n * Uses JavaScript `===` comparison and auto-removes empty filter values.\n */\nexport const filterFn_equals = constructFilterFn({\n filter: (dataValue, filterValue) => dataValue === filterValue,\n autoRemove: (val: any) => testFalsy(val),\n})\n\n/**\n * Keeps rows whose column value is loosely equal to the filter value.\n *\n * Uses JavaScript `==` comparison and auto-removes empty filter values. This is\n * useful for matching string input against numeric row values.\n */\nexport const filterFn_weakEquals = constructFilterFn({\n filter: (dataValue, filterValue) => dataValue == filterValue,\n autoRemove: (val: any) => testFalsy(val),\n})\n\n// String filters\n\n/**\n * Keeps rows whose stringified column value includes the filter text.\n *\n * Matching is case-sensitive and empty filter values are auto-removed.\n */\nexport const filterFn_includesStringSensitive = constructFilterFn({\n filter: (dataValue, filterValue) => Boolean(dataValue?.includes(filterValue)),\n autoRemove: (val: any) => testFalsy(val),\n resolveFilterValue: (val: any) => String(val),\n resolveDataValue: (val: any) => (val == null ? undefined : String(val)),\n})\n\n/**\n * Keeps rows whose stringified column value includes the filter text.\n *\n * Both values are lowercased before comparison, and empty filter values are\n * auto-removed.\n */\nexport const filterFn_includesString = constructFilterFn({\n filter: (dataValue, filterValue) => Boolean(dataValue?.includes(filterValue)),\n autoRemove: (val: any) => testFalsy(val),\n resolveFilterValue: (val: any) => String(val).toLowerCase(),\n resolveDataValue: (val: any) =>\n val == null ? undefined : String(val).toLowerCase(),\n})\n\n/**\n * Keeps rows whose stringified column value equals the filter text.\n *\n * Both values are lowercased before comparison, and empty filter values are\n * auto-removed.\n */\nexport const filterFn_equalsString = constructFilterFn({\n filter: (dataValue, filterValue) => dataValue === filterValue,\n autoRemove: (val: any) => testFalsy(val),\n resolveFilterValue: (val: any) => String(val).toLowerCase(),\n resolveDataValue: (val: any) =>\n val == null ? undefined : String(val).toLowerCase(),\n})\n\n/**\n * Keeps rows whose stringified column value exactly equals the filter text.\n *\n * Matching is case-sensitive and empty filter values are auto-removed.\n */\nexport const filterFn_equalsStringSensitive = constructFilterFn({\n filter: (dataValue, filterValue) => dataValue === filterValue,\n autoRemove: (val: any) => testFalsy(val),\n resolveFilterValue: (val: any) => String(val),\n resolveDataValue: (val: any) => (val == null ? undefined : String(val)),\n})\n\n/**\n * Keeps rows whose stringified column value starts with the filter text.\n *\n * Both values are lowercased before comparison, and empty filter values are\n * auto-removed.\n */\nexport const filterFn_startsWith = constructFilterFn({\n filter: (dataValue, filterValue) =>\n Boolean(dataValue?.startsWith(filterValue)),\n autoRemove: (val: any) => testFalsy(val),\n resolveFilterValue: (val: any) => String(val).toLowerCase(),\n resolveDataValue: (val: any) =>\n val == null ? undefined : String(val).toLowerCase(),\n})\n\n/**\n * Keeps rows whose stringified column value ends with the filter text.\n *\n * Both values are lowercased before comparison, and empty filter values are\n * auto-removed.\n */\nexport const filterFn_endsWith = constructFilterFn({\n filter: (dataValue, filterValue) => Boolean(dataValue?.endsWith(filterValue)),\n autoRemove: (val: any) => testFalsy(val),\n resolveFilterValue: (val: any) => String(val).toLowerCase(),\n resolveDataValue: (val: any) =>\n val == null ? undefined : String(val).toLowerCase(),\n})\n\n// Blank filters\n\n/**\n * Keeps rows whose column value is empty.\n *\n * A value is empty when it is nullish or stringifies to whitespace only. The\n * filter value acts as an on/off flag: `false` and blank values are\n * auto-removed.\n */\nexport const filterFn_empty = constructFilterFn({\n filter: (dataValue) => testValueEmpty(dataValue),\n autoRemove: (val: any) => testFalsy(val) || val === false,\n})\n\n/**\n * Keeps rows whose column value is not empty.\n *\n * A value is empty when it is nullish or stringifies to whitespace only. The\n * filter value acts as an on/off flag: `false` and blank values are\n * auto-removed.\n */\nexport const filterFn_notEmpty = constructFilterFn({\n filter: (dataValue) => !testValueEmpty(dataValue),\n autoRemove: (val: any) => testFalsy(val) || val === false,\n})\n\n// Number filters\n\n/**\n * Keeps rows whose value is greater than the filter value.\n *\n * Numeric values are compared numerically when both sides can be coerced to\n * numbers; otherwise normalized strings are compared.\n */\nexport const filterFn_greaterThan = constructFilterFn({\n filter: (dataValue, filterValue) =>\n compareGreaterThan(dataValue, filterValue),\n autoRemove: (val: any) => testFalsy(val),\n})\n\n/**\n * Keeps rows whose value is greater than or equal to the filter value.\n *\n * Delegates to the built-in greater-than and strict-equality comparisons.\n */\nexport const filterFn_greaterThanOrEqualTo = constructFilterFn({\n filter: (dataValue, filterValue) =>\n compareGreaterThanOrEqualTo(dataValue, filterValue),\n autoRemove: (val: any) => testFalsy(val),\n})\n\n/**\n * Keeps rows whose value is less than the filter value.\n *\n * This is implemented as the inverse of greater-than-or-equal comparison.\n */\nexport const filterFn_lessThan = constructFilterFn({\n filter: (dataValue, filterValue) =>\n !compareGreaterThanOrEqualTo(dataValue, filterValue),\n autoRemove: (val: any) => testFalsy(val),\n})\n\n/**\n * Keeps rows whose value is less than or equal to the filter value.\n *\n * This is implemented as the inverse of greater-than comparison.\n */\nexport const filterFn_lessThanOrEqualTo = constructFilterFn({\n filter: (dataValue, filterValue) =>\n !compareGreaterThan(dataValue, filterValue),\n autoRemove: (val: any) => testFalsy(val),\n})\n\n// Range filters\n\n/**\n * Keeps rows whose value falls between an exclusive min/max pair.\n *\n * Blank range endpoints are treated as open-ended.\n */\nexport const filterFn_between = constructFilterFn({\n filter: (dataValue, filterValues: [unknown, unknown]) =>\n compareBetween(dataValue, filterValues, false),\n autoRemove: (val: any) =>\n testFalsy(val) ||\n (Array.isArray(val) && testFalsy(val[0]) && testFalsy(val[1])),\n})\n\n/**\n * Keeps rows whose value falls between an inclusive min/max pair.\n *\n * Blank range endpoints are treated as open-ended.\n */\nexport const filterFn_betweenInclusive = constructFilterFn({\n filter: (dataValue, filterValues: [unknown, unknown]) =>\n compareBetween(dataValue, filterValues, true),\n autoRemove: (val: any) =>\n testFalsy(val) ||\n (Array.isArray(val) && testFalsy(val[0]) && testFalsy(val[1])),\n})\n\n/**\n * Keeps rows whose numeric value is inside an inclusive `[min, max]` range.\n *\n * Filter values are normalized so blank endpoints become open-ended and\n * reversed endpoints are swapped.\n */\nexport const filterFn_inNumberRange = constructFilterFn({\n filter: (dataValue: number, filterValue: [number, number]) => {\n const [min, max] = filterValue\n return dataValue >= min && dataValue <= max\n },\n resolveFilterValue: (val: [any, any]) => {\n const [unsafeMin, unsafeMax] = val\n\n const parsedMin =\n typeof unsafeMin !== 'number' ? parseFloat(unsafeMin) : unsafeMin\n const parsedMax =\n typeof unsafeMax !== 'number' ? parseFloat(unsafeMax) : unsafeMax\n\n let min =\n unsafeMin === null || Number.isNaN(parsedMin) ? -Infinity : parsedMin\n let max =\n unsafeMax === null || Number.isNaN(parsedMax) ? Infinity : parsedMax\n\n if (min > max) {\n const temp = min\n min = max\n max = temp\n }\n\n return [min, max] as const\n },\n autoRemove: (val: any) =>\n testFalsy(val) ||\n (Array.isArray(val) && testFalsy(val[0]) && testFalsy(val[1])),\n})\n\n// Date filters\n\n/**\n * Keeps rows whose date value is inside an inclusive `[min, max]` date range.\n *\n * Row values and range endpoints may be `Date` objects, timestamps, or\n * parseable date strings. Blank or invalid endpoints become open-ended and\n * reversed endpoints are swapped. Rows without a valid date never match.\n */\nexport const filterFn_inDateRange = constructFilterFn({\n filter: (dataValue: number, filterValue: [number, number]) => {\n const [min, max] = filterValue\n return dataValue >= min && dataValue <= max\n },\n resolveFilterValue: (val: [any, any]) => {\n const [unsafeMin, unsafeMax] = val\n\n const parsedMin = toDateTimestamp(unsafeMin)\n const parsedMax = toDateTimestamp(unsafeMax)\n\n let min = Number.isNaN(parsedMin) ? -Infinity : parsedMin\n let max = Number.isNaN(parsedMax) ? Infinity : parsedMax\n\n if (min > max) {\n const temp = min\n min = max\n max = temp\n }\n\n return [min, max] as const\n },\n resolveDataValue: (val: any) => toDateTimestamp(val),\n autoRemove: (val: any) =>\n testFalsy(val) ||\n (Array.isArray(val) && testFalsy(val[0]) && testFalsy(val[1])),\n})\n\n// Array filters\n\n/**\n * Keeps rows whose scalar column value equals at least one filter value.\n */\nexport const filterFn_arrHas = constructFilterFn({\n filter: (dataValue, filterValue: Array<unknown>) => {\n for (let i = 0; i < filterValue.length; i++) {\n if (dataValue === filterValue[i]) {\n return true\n }\n }\n return false\n },\n autoRemove: (val: any) => testFalsy(val) || !val?.length,\n})\n\n/**\n * Keeps rows whose array or string column value includes at least one filter value.\n */\nexport const filterFn_arrIncludes = constructFilterFn({\n filter: (dataValue, filterValue: Array<unknown>) => {\n if (typeof dataValue !== 'string' && !Array.isArray(dataValue)) {\n return false\n }\n\n for (let i = 0; i < filterValue.length; i++) {\n if (dataValue.includes(filterValue[i] as any)) {\n return true\n }\n }\n return false\n },\n autoRemove: (val: any) => testFalsy(val) || !val?.length,\n})\n\n/**\n * Keeps rows whose array column value includes every filter value.\n */\nexport const filterFn_arrIncludesAll = constructFilterFn({\n filter: (dataValue, filterValue: Array<unknown>) => {\n if (!Array.isArray(dataValue)) return false\n for (let i = 0; i < filterValue.length; i++) {\n if (!dataValue.includes(filterValue[i])) {\n return false\n }\n }\n return true\n },\n autoRemove: (val: any) => testFalsy(val) || !val?.length,\n})\n\n/**\n * Keeps rows whose array column value includes at least one filter value.\n */\nexport const filterFn_arrIncludesSome = constructFilterFn({\n filter: (dataValue, filterValue: Array<unknown>) => {\n if (!Array.isArray(dataValue)) return false\n for (let i = 0; i < filterValue.length; i++) {\n if (dataValue.includes(filterValue[i])) {\n return true\n }\n }\n return false\n },\n autoRemove: (val: any) => testFalsy(val) || !val?.length,\n})\n\n// Export\n\n/**\n * The built-in filter function registry.\n *\n * Registering this full object opts out of tree-shaking: every built-in\n * filter function ends up in your bundle. Prefer importing the `filterFn_*`\n * functions you actually use and registering just those in the `filterFns`\n * slot, or passing them directly to the `filterFn` column option.\n *\n * @deprecated Import individual `filterFn_*` functions instead for a smaller\n * bundle. This export still works and is not going away in v9, but built-in\n * name resolution (including `filterFn: 'auto'`) only finds functions you\n * register yourself.\n */\nexport const filterFns = {\n arrIncludes: filterFn_arrIncludes,\n arrIncludesAll: filterFn_arrIncludesAll,\n arrHas: filterFn_arrHas,\n arrIncludesSome: filterFn_arrIncludesSome,\n between: filterFn_between,\n betweenInclusive: filterFn_betweenInclusive,\n empty: filterFn_empty,\n endsWith: filterFn_endsWith,\n equals: filterFn_equals,\n equalsString: filterFn_equalsString,\n equalsStringSensitive: filterFn_equalsStringSensitive,\n inDateRange: filterFn_inDateRange,\n inNumberRange: filterFn_inNumberRange,\n includesString: filterFn_includesString,\n includesStringSensitive: filterFn_includesStringSensitive,\n notEmpty: filterFn_notEmpty,\n startsWith: filterFn_startsWith,\n weakEquals: filterFn_weakEquals,\n}\n\nexport type BuiltInFilterFn = keyof typeof filterFns\n\n// Utils\n\nfunction testFalsy(val: any) {\n return val === undefined || val === null || val === ''\n}\n\nfunction testValueEmpty(dataValue: any) {\n return dataValue == null || String(dataValue).trim() === ''\n}\n\nfunction toDateTimestamp(value: any): number {\n if (value instanceof Date) {\n return value.getTime()\n }\n if (typeof value === 'number') {\n return value\n }\n // Guard nullish and blank values explicitly: `new Date(null)` is the epoch,\n // not an invalid date.\n if (value == null || value === '') {\n return NaN\n }\n return new Date(value).getTime()\n}\n\nfunction compareGreaterThan(dataValue: any, filterValue: any): boolean {\n const numericDataValue = dataValue == null ? 0 : +dataValue\n const numericFilterValue = Number(filterValue)\n\n if (!isNaN(numericFilterValue) && !isNaN(numericDataValue)) {\n return numericDataValue > numericFilterValue\n }\n\n const stringDataValue = String(dataValue ?? '')\n .toLowerCase()\n .trim()\n const stringFilterValue = String(filterValue).toLowerCase().trim()\n return stringDataValue > stringFilterValue\n}\n\nfunction compareGreaterThanOrEqualTo(dataValue: any, filterValue: any) {\n return dataValue === filterValue || compareGreaterThan(dataValue, filterValue)\n}\n\nfunction compareBetween(\n dataValue: any,\n filterValues: [unknown, unknown],\n inclusive: boolean,\n): boolean {\n const min = filterValues[0]\n const hasMin = min !== '' && min !== undefined\n if (hasMin) {\n const passesMin = inclusive\n ? compareGreaterThanOrEqualTo(dataValue, min)\n : compareGreaterThan(dataValue, min)\n if (!passesMin) {\n return false\n }\n }\n\n const max = filterValues[1]\n if (max === '' || max === undefined) {\n return true\n }\n\n if (hasMin) {\n const numericMin = Number(min)\n const numericMax = Number(max)\n if (!isNaN(numericMin) && !isNaN(numericMax) && numericMin > numericMax) {\n return true\n }\n }\n\n return inclusive\n ? !compareGreaterThan(dataValue, max)\n : !compareGreaterThanOrEqualTo(dataValue, max)\n}\n"],"mappings":"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"}
|
package/dist/fns/sortFns.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sortFns.cjs","names":[],"sources":["../../src/fns/sortFns.ts"],"sourcesContent":["import type {\n CreatedSortFn,\n SortFnDef,\n} from '../features/row-sorting/rowSortingFeature.types'\nimport type { RowData } from '../types/type-utils'\nimport type { TableFeatures } from '../types/TableFeatures'\nimport type { Row } from '../types/Row'\n\n/**\n * Regular expression used to split mixed text and numeric chunks.\n *\n * The alphanumeric sort functions use these chunks for natural sorting of\n * strings like `item2` before `item10`.\n */\nexport const reSplitAlphaNumeric = /([0-9]+)/gm\n\n/**\n * Builds a `SortFn` from a value-level comparator plus an optional\n * `resolveDataValue` normalizer.\n *\n * The `sort` comparator receives both rows' data values, each already passed\n * through `resolveDataValue` when one is defined. Keeping normalization in the\n * resolver means a variant of an existing sorting function only has to swap\n * the resolver, not re-implement the comparison.\n *\n * The definition is attached to the returned function, so a variant can be\n * created by spreading a built-in sorting function and overriding what\n * differs:\n *\n * ```ts\n * const stripDiacritics = (value: string) =>\n * value.normalize('NFD').replace(/\\p{Diacritic}/gu, '')\n *\n * const alphanumericIgnoreDiacritics = constructSortFn({\n * ...sortFn_alphanumeric,\n * resolveDataValue: (value) =>\n * stripDiacritics(sortFn_alphanumeric.resolveDataValue!(value)),\n * })\n * ```\n */\nexport function constructSortFn<\n TFeatures extends TableFeatures = any,\n TData extends RowData = any,\n>(def: SortFnDef<TFeatures, TData>): CreatedSortFn<TFeatures, TData> {\n const sortFn: CreatedSortFn<TFeatures, TData> = Object.assign(\n <TRowFeatures extends TableFeatures, TRowData extends RowData>(\n rowA: Row<TRowFeatures, TRowData>,\n rowB: Row<TRowFeatures, TRowData>,\n columnId: string,\n ): number => {\n let dataValueA = rowA.getValue(columnId)\n let dataValueB = rowB.getValue(columnId)\n const resolveDataValue = sortFn.resolveDataValue\n if (resolveDataValue) {\n dataValueA = resolveDataValue(dataValueA)\n dataValueB = resolveDataValue(dataValueB)\n }\n // The def's comparator is typed against the factory's TFeatures/TData;\n // the caller's row generics are erased at this boundary.\n return sortFn.sort(\n dataValueA,\n dataValueB,\n rowA as any,\n rowB as any,\n columnId,\n )\n },\n def,\n )\n return sortFn\n}\n\n/**\n * Sorts rows with the built-in alphanumeric strategy.\n *\n * This comparator returns ascending-order results; descending order is applied by the sorting row model.\n */\nexport const sortFn_alphanumeric = constructSortFn({\n resolveDataValue: (dataValue) => toString(dataValue).toLowerCase(),\n sort: (dataValueA, dataValueB) => compareAlphanumeric(dataValueA, dataValueB),\n})\n\n/**\n * Sorts rows with the built-in alphanumeric case sensitive strategy.\n *\n * This comparator returns ascending-order results; descending order is applied by the sorting row model.\n */\nexport const sortFn_alphanumericCaseSensitive = constructSortFn({\n resolveDataValue: (dataValue) => toString(dataValue),\n sort: (dataValueA, dataValueB) => compareAlphanumeric(dataValueA, dataValueB),\n})\n\n// The text sort is more basic (less numeric support)\n// but is much faster\n/**\n * Sorts rows with the built-in text strategy.\n *\n * This comparator returns ascending-order results; descending order is applied by the sorting row model.\n */\nexport const sortFn_text = constructSortFn({\n resolveDataValue: (dataValue) => toString(dataValue).toLowerCase(),\n sort: (dataValueA, dataValueB) => compareBasic(dataValueA, dataValueB),\n})\n\n// The text sort is more basic (less numeric support)\n// but is much faster\n/**\n * Sorts rows with the built-in text case sensitive strategy.\n *\n * This comparator returns ascending-order results; descending order is applied by the sorting row model.\n */\nexport const sortFn_textCaseSensitive = constructSortFn({\n resolveDataValue: (dataValue) => toString(dataValue),\n sort: (dataValueA, dataValueB) => compareBasic(dataValueA, dataValueB),\n})\n\n/**\n * Sorts rows with the built-in datetime strategy.\n *\n * This comparator returns ascending-order results; descending order is applied by the sorting row model.\n */\nexport const sortFn_datetime = constructSortFn({\n resolveDataValue: (dataValue) => toDateSortValue(dataValue),\n // Can handle nullish values\n // Use > and < because == (and ===) doesn't work with\n // Date objects (would require calling getTime()).\n sort: (dataValueA, dataValueB) =>\n dataValueA > dataValueB ? 1 : dataValueA < dataValueB ? -1 : 0,\n})\n\n/**\n * Sorts rows with the built-in basic strategy.\n *\n * This comparator returns ascending-order results; descending order is applied by the sorting row model.\n */\nexport const sortFn_basic = constructSortFn({\n sort: (dataValueA, dataValueB) => compareBasic(dataValueA, dataValueB),\n})\n\n// Utils\n\nfunction compareBasic(a: any, b: any) {\n return a === b ? 0 : a > b ? 1 : -1\n}\n\nfunction toDateSortValue(value: any) {\n return value instanceof Date ? value.getTime() : value\n}\n\nfunction toString(a: any) {\n if (typeof a === 'number') {\n if (isNaN(a) || a === Infinity || a === -Infinity) {\n return ''\n }\n return String(a)\n }\n if (typeof a === 'string') {\n return a\n }\n return ''\n}\n\n// Mixed sorting is slow, but very inclusive of many edge cases.\n// It handles numbers, mixed alphanumeric combinations, and even\n// null, undefined, and Infinity\nfunction compareAlphanumeric(aStr: string, bStr: string) {\n let ai = 0\n let bi = 0\n const aLen = aStr.length\n const bLen = bStr.length\n\n while (ai < aLen && bi < bLen) {\n const aIsNumeric = isDigit(aStr.charCodeAt(ai))\n const bIsNumeric = isDigit(bStr.charCodeAt(bi))\n\n const aEnd = findChunkEnd(aStr, ai, aIsNumeric)\n const bEnd = findChunkEnd(bStr, bi, bIsNumeric)\n\n // Both are string chunks\n if (!aIsNumeric && !bIsNumeric) {\n const stringComparison = compareStringChunks(\n aStr,\n ai,\n aEnd,\n bStr,\n bi,\n bEnd,\n )\n if (stringComparison) {\n return stringComparison\n }\n ai = aEnd\n bi = bEnd\n continue\n }\n\n // One is a string chunk, one is a number chunk — the string sorts first\n if (aIsNumeric !== bIsNumeric) {\n return aIsNumeric ? 1 : -1\n }\n\n // Both are numeric chunks\n const numericComparison = compareNumericChunks(\n aStr,\n ai,\n aEnd,\n bStr,\n bi,\n bEnd,\n )\n if (numericComparison) {\n return numericComparison\n }\n\n ai = aEnd\n bi = bEnd\n }\n\n // One side is exhausted — compare the counts of remaining non-empty chunks\n return countRemainingChunks(aStr, ai) - countRemainingChunks(bStr, bi)\n}\n\nfunction isDigit(charCode: number) {\n return charCode >= 48 && charCode <= 57\n}\n\nfunction findChunkEnd(str: string, start: number, isNumeric: boolean) {\n let end = start + 1\n while (end < str.length && isDigit(str.charCodeAt(end)) === isNumeric) {\n end++\n }\n return end\n}\n\nfunction compareStringChunks(\n aStr: string,\n aStart: number,\n aEnd: number,\n bStr: string,\n bStart: number,\n bEnd: number,\n) {\n const aLength = aEnd - aStart\n const bLength = bEnd - bStart\n const minLength = aLength < bLength ? aLength : bLength\n\n for (let i = 0; i < minLength; i++) {\n const aCode = aStr.charCodeAt(aStart + i)\n const bCode = bStr.charCodeAt(bStart + i)\n\n if (aCode > bCode) {\n return 1\n }\n if (bCode > aCode) {\n return -1\n }\n }\n\n if (aLength > bLength) {\n return 1\n }\n if (bLength > aLength) {\n return -1\n }\n return 0\n}\n\nfunction compareNumericChunks(\n aStr: string,\n aStart: number,\n aEnd: number,\n bStr: string,\n bStart: number,\n bEnd: number,\n) {\n let aSignificantStart = aStart\n while (\n aSignificantStart < aEnd &&\n aStr.charCodeAt(aSignificantStart) === 48\n ) {\n aSignificantStart++\n }\n\n let bSignificantStart = bStart\n while (\n bSignificantStart < bEnd &&\n bStr.charCodeAt(bSignificantStart) === 48\n ) {\n bSignificantStart++\n }\n\n const aSignificantLength = aEnd - aSignificantStart\n const bSignificantLength = bEnd - bSignificantStart\n\n if (aSignificantLength === 0 && bSignificantLength === 0) {\n return 0\n }\n\n if (aSignificantLength <= 15 && bSignificantLength <= 15) {\n const an = parseSmallInt(aStr, aSignificantStart, aEnd)\n const bn = parseSmallInt(bStr, bSignificantStart, bEnd)\n\n if (an > bn) {\n return 1\n }\n if (bn > an) {\n return -1\n }\n return 0\n }\n\n // Preserve parseInt precision-collapse behavior for unusually large chunks.\n const an = parseInt(aStr.slice(aStart, aEnd), 10)\n const bn = parseInt(bStr.slice(bStart, bEnd), 10)\n\n if (an > bn) {\n return 1\n }\n if (bn > an) {\n return -1\n }\n return 0\n}\n\nfunction parseSmallInt(str: string, start: number, end: number) {\n let result = 0\n for (let i = start; i < end; i++) {\n result = result * 10 + str.charCodeAt(i) - 48\n }\n return result\n}\n\nfunction countRemainingChunks(str: string, start: number) {\n let count = 0\n let index = start\n\n while (index < str.length) {\n count++\n index = findChunkEnd(str, index, isDigit(str.charCodeAt(index)))\n }\n\n return count\n}\n\n// Exports\n\n/**\n * The built-in sorting function registry.\n *\n * Registering this full object opts out of tree-shaking: every built-in\n * sorting function ends up in your bundle. Prefer importing the `sortFn_*`\n * functions you actually use and registering just those in the `sortFns`\n * slot, or passing them directly to the `sortFn` column option.\n *\n * @deprecated Import individual `sortFn_*` functions instead for a smaller\n * bundle. This export still works and is not going away in v9, but built-in\n * name resolution (including `sortFn: 'auto'`) only finds functions you\n * register yourself.\n */\nexport const sortFns = {\n alphanumeric: sortFn_alphanumeric,\n alphanumericCaseSensitive: sortFn_alphanumericCaseSensitive,\n basic: sortFn_basic,\n datetime: sortFn_datetime,\n text: sortFn_text,\n textCaseSensitive: sortFn_textCaseSensitive,\n}\n\nexport type BuiltInSortFn = keyof typeof sortFns\n"],"mappings":"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"}
|