@tanstack/table-core 9.0.0-beta.28 → 9.0.0-beta.30

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 (30) hide show
  1. package/dist/features/column-filtering/columnFilteringFeature.utils.cjs +1 -1
  2. package/dist/features/column-filtering/columnFilteringFeature.utils.cjs.map +1 -1
  3. package/dist/features/column-filtering/columnFilteringFeature.utils.js +1 -1
  4. package/dist/features/column-filtering/columnFilteringFeature.utils.js.map +1 -1
  5. package/dist/features/global-filtering/globalFilteringFeature.utils.d.cts +1 -0
  6. package/dist/features/global-filtering/globalFilteringFeature.utils.d.ts +1 -0
  7. package/dist/features/row-sorting/createSortedRowModel.cjs +41 -34
  8. package/dist/features/row-sorting/createSortedRowModel.cjs.map +1 -1
  9. package/dist/features/row-sorting/createSortedRowModel.js +42 -35
  10. package/dist/features/row-sorting/createSortedRowModel.js.map +1 -1
  11. package/dist/fns/aggregationFns.cjs +21 -19
  12. package/dist/fns/aggregationFns.cjs.map +1 -1
  13. package/dist/fns/aggregationFns.js +21 -19
  14. package/dist/fns/aggregationFns.js.map +1 -1
  15. package/dist/fns/filterFns.cjs +59 -14
  16. package/dist/fns/filterFns.cjs.map +1 -1
  17. package/dist/fns/filterFns.d.cts +11 -4
  18. package/dist/fns/filterFns.d.ts +11 -4
  19. package/dist/fns/filterFns.js +59 -14
  20. package/dist/fns/filterFns.js.map +1 -1
  21. package/dist/fns/sortFns.cjs +77 -28
  22. package/dist/fns/sortFns.cjs.map +1 -1
  23. package/dist/fns/sortFns.js +77 -28
  24. package/dist/fns/sortFns.js.map +1 -1
  25. package/package.json +1 -1
  26. package/src/features/column-filtering/columnFilteringFeature.utils.ts +4 -4
  27. package/src/features/row-sorting/createSortedRowModel.ts +65 -55
  28. package/src/fns/aggregationFns.ts +19 -19
  29. package/src/fns/filterFns.ts +96 -32
  30. package/src/fns/sortFns.ts +158 -46
@@ -24,7 +24,10 @@ const filterFn_weakEquals = Object.assign((row, columnId, filterValue) => {
24
24
  const filterFn_includesStringSensitive = Object.assign((row, columnId, filterValue) => {
25
25
  var _row$getValue;
26
26
  return Boolean((_row$getValue = row.getValue(columnId)) === null || _row$getValue === void 0 ? void 0 : _row$getValue.toString().includes(String(filterValue)));
27
- }, { autoRemove: (val) => testFalsy(val) });
27
+ }, {
28
+ autoRemove: (val) => testFalsy(val),
29
+ resolveFilterValue: (val) => String(val)
30
+ });
28
31
  /**
29
32
  * Keeps rows whose stringified column value includes the filter text.
30
33
  *
@@ -34,7 +37,10 @@ const filterFn_includesStringSensitive = Object.assign((row, columnId, filterVal
34
37
  const filterFn_includesString = Object.assign((row, columnId, filterValue) => {
35
38
  var _row$getValue2;
36
39
  return Boolean((_row$getValue2 = row.getValue(columnId)) === null || _row$getValue2 === void 0 ? void 0 : _row$getValue2.toString().toLowerCase().includes(String(filterValue).toLowerCase()));
37
- }, { autoRemove: (val) => testFalsy(val) });
40
+ }, {
41
+ autoRemove: (val) => testFalsy(val),
42
+ resolveFilterValue: (val) => String(val).toLowerCase()
43
+ });
38
44
  /**
39
45
  * Keeps rows whose stringified column value equals the filter text.
40
46
  *
@@ -44,7 +50,10 @@ const filterFn_includesString = Object.assign((row, columnId, filterValue) => {
44
50
  const filterFn_equalsString = Object.assign((row, columnId, filterValue) => {
45
51
  var _row$getValue3;
46
52
  return ((_row$getValue3 = row.getValue(columnId)) === null || _row$getValue3 === void 0 ? void 0 : _row$getValue3.toString().toLowerCase()) === String(filterValue).toLowerCase();
47
- }, { autoRemove: (val) => testFalsy(val) });
53
+ }, {
54
+ autoRemove: (val) => testFalsy(val),
55
+ resolveFilterValue: (val) => String(val).toLowerCase()
56
+ });
48
57
  /**
49
58
  * Keeps rows whose stringified column value exactly equals the filter text.
50
59
  *
@@ -53,7 +62,10 @@ const filterFn_equalsString = Object.assign((row, columnId, filterValue) => {
53
62
  const filterFn_equalsStringSensitive = Object.assign((row, columnId, filterValue) => {
54
63
  var _row$getValue4;
55
64
  return ((_row$getValue4 = row.getValue(columnId)) === null || _row$getValue4 === void 0 ? void 0 : _row$getValue4.toString()) === String(filterValue);
56
- }, { autoRemove: (val) => testFalsy(val) });
65
+ }, {
66
+ autoRemove: (val) => testFalsy(val),
67
+ resolveFilterValue: (val) => String(val)
68
+ });
57
69
  /**
58
70
  * Keeps rows whose value is greater than the filter value.
59
71
  *
@@ -66,7 +78,7 @@ const filterFn_greaterThan = Object.assign((row, columnId, filterValue) => {
66
78
  const numericFilterValue = Number(filterValue);
67
79
  if (!isNaN(numericFilterValue) && !isNaN(numericRowValue)) return numericRowValue > numericFilterValue;
68
80
  return (rowValue ?? "").toString().toLowerCase().trim() > String(filterValue).toLowerCase().trim();
69
- }, { resolveFilterValue: (val) => testFalsy(val) });
81
+ }, { autoRemove: (val) => testFalsy(val) });
70
82
  /**
71
83
  * Keeps rows whose value is greater than or equal to the filter value.
72
84
  *
@@ -74,7 +86,7 @@ const filterFn_greaterThan = Object.assign((row, columnId, filterValue) => {
74
86
  */
75
87
  const filterFn_greaterThanOrEqualTo = Object.assign((row, columnId, filterValue) => {
76
88
  return filterFn_greaterThan(row, columnId, filterValue) || filterFn_equals(row, columnId, filterValue);
77
- }, { resolveFilterValue: (val) => testFalsy(val) });
89
+ }, { autoRemove: (val) => testFalsy(val) });
78
90
  /**
79
91
  * Keeps rows whose value is less than the filter value.
80
92
  *
@@ -82,7 +94,7 @@ const filterFn_greaterThanOrEqualTo = Object.assign((row, columnId, filterValue)
82
94
  */
83
95
  const filterFn_lessThan = Object.assign((row, columnId, filterValue) => {
84
96
  return !filterFn_greaterThanOrEqualTo(row, columnId, filterValue);
85
- }, { resolveFilterValue: (val) => testFalsy(val) });
97
+ }, { autoRemove: (val) => testFalsy(val) });
86
98
  /**
87
99
  * Keeps rows whose value is less than or equal to the filter value.
88
100
  *
@@ -90,19 +102,45 @@ const filterFn_lessThan = Object.assign((row, columnId, filterValue) => {
90
102
  */
91
103
  const filterFn_lessThanOrEqualTo = Object.assign((row, columnId, filterValue) => {
92
104
  return !filterFn_greaterThan(row, columnId, filterValue);
93
- }, { resolveFilterValue: (val) => testFalsy(val) });
105
+ }, { autoRemove: (val) => testFalsy(val) });
94
106
  /**
95
107
  * Keeps rows whose value falls between an exclusive min/max pair.
96
108
  *
97
109
  * Blank range endpoints are treated as open-ended.
98
110
  */
99
- const filterFn_between = Object.assign((row, columnId, filterValues) => (["", void 0].includes(filterValues[0]) || filterFn_greaterThan(row, columnId, filterValues[0])) && (!isNaN(Number(filterValues[0])) && !isNaN(Number(filterValues[1])) && Number(filterValues[0]) > Number(filterValues[1]) || ["", void 0].includes(filterValues[1]) || filterFn_lessThan(row, columnId, filterValues[1])), { autoRemove: (val) => testFalsy(val) || testFalsy(val[0]) && testFalsy(val[1]) });
111
+ const filterFn_between = Object.assign((row, columnId, filterValues) => {
112
+ const min = filterValues[0];
113
+ if (min !== "" && min !== void 0) {
114
+ if (!filterFn_greaterThan(row, columnId, min)) return false;
115
+ }
116
+ const max = filterValues[1];
117
+ if (max === "" || max === void 0) return true;
118
+ if (min !== "" && min !== void 0) {
119
+ const numericMin = Number(min);
120
+ const numericMax = Number(max);
121
+ if (!isNaN(numericMin) && !isNaN(numericMax) && numericMin > numericMax) return true;
122
+ }
123
+ return filterFn_lessThan(row, columnId, max);
124
+ }, { autoRemove: (val) => testFalsy(val) || testFalsy(val[0]) && testFalsy(val[1]) });
100
125
  /**
101
126
  * Keeps rows whose value falls between an inclusive min/max pair.
102
127
  *
103
128
  * Blank range endpoints are treated as open-ended.
104
129
  */
105
- const filterFn_betweenInclusive = Object.assign((row, columnId, filterValues) => (["", void 0].includes(filterValues[0]) || filterFn_greaterThanOrEqualTo(row, columnId, filterValues[0])) && (!isNaN(Number(filterValues[0])) && !isNaN(Number(filterValues[1])) && Number(filterValues[0]) > Number(filterValues[1]) || ["", void 0].includes(filterValues[1]) || filterFn_lessThanOrEqualTo(row, columnId, filterValues[1])), { autoRemove: (val) => testFalsy(val) || testFalsy(val[0]) && testFalsy(val[1]) });
130
+ const filterFn_betweenInclusive = Object.assign((row, columnId, filterValues) => {
131
+ const min = filterValues[0];
132
+ if (min !== "" && min !== void 0) {
133
+ if (!filterFn_greaterThanOrEqualTo(row, columnId, min)) return false;
134
+ }
135
+ const max = filterValues[1];
136
+ if (max === "" || max === void 0) return true;
137
+ if (min !== "" && min !== void 0) {
138
+ const numericMin = Number(min);
139
+ const numericMax = Number(max);
140
+ if (!isNaN(numericMin) && !isNaN(numericMax) && numericMin > numericMax) return true;
141
+ }
142
+ return filterFn_lessThanOrEqualTo(row, columnId, max);
143
+ }, { autoRemove: (val) => testFalsy(val) || testFalsy(val[0]) && testFalsy(val[1]) });
106
144
  /**
107
145
  * Keeps rows whose numeric value is inside an inclusive `[min, max]` range.
108
146
  *
@@ -133,13 +171,18 @@ const filterFn_inNumberRange = Object.assign((row, columnId, filterValue) => {
133
171
  * Keeps rows whose scalar column value equals at least one filter value.
134
172
  */
135
173
  const filterFn_arrHas = Object.assign((row, columnId, filterValue) => {
136
- return filterValue.some((val) => row.getValue(columnId) === val);
174
+ const value = row.getValue(columnId);
175
+ for (let i = 0; i < filterValue.length; i++) if (value === filterValue[i]) return true;
176
+ return false;
137
177
  }, { autoRemove: (val) => testFalsy(val) || !(val === null || val === void 0 ? void 0 : val.length) });
138
178
  /**
139
179
  * Keeps rows whose array or string column value includes at least one filter value.
140
180
  */
141
181
  const filterFn_arrIncludes = Object.assign((row, columnId, filterValue) => {
142
- return filterValue.some((val) => row.getValue(columnId).includes(val));
182
+ const value = row.getValue(columnId);
183
+ if (typeof value !== "string" && !Array.isArray(value)) return false;
184
+ for (let i = 0; i < filterValue.length; i++) if (value.includes(filterValue[i])) return true;
185
+ return false;
143
186
  }, { autoRemove: (val) => testFalsy(val) || !(val === null || val === void 0 ? void 0 : val.length) });
144
187
  /**
145
188
  * Keeps rows whose array column value includes every filter value.
@@ -147,7 +190,8 @@ const filterFn_arrIncludes = Object.assign((row, columnId, filterValue) => {
147
190
  const filterFn_arrIncludesAll = Object.assign((row, columnId, filterValue) => {
148
191
  const value = row.getValue(columnId);
149
192
  if (!Array.isArray(value)) return false;
150
- return !filterValue.some((val) => !value.includes(val));
193
+ for (let i = 0; i < filterValue.length; i++) if (!value.includes(filterValue[i])) return false;
194
+ return true;
151
195
  }, { autoRemove: (val) => testFalsy(val) || !(val === null || val === void 0 ? void 0 : val.length) });
152
196
  /**
153
197
  * Keeps rows whose array column value includes at least one filter value.
@@ -155,7 +199,8 @@ const filterFn_arrIncludesAll = Object.assign((row, columnId, filterValue) => {
155
199
  const filterFn_arrIncludesSome = Object.assign((row, columnId, filterValue) => {
156
200
  const value = row.getValue(columnId);
157
201
  if (!Array.isArray(value)) return false;
158
- return filterValue.some((val) => value.includes(val));
202
+ for (let i = 0; i < filterValue.length; i++) if (value.includes(filterValue[i])) return true;
203
+ return false;
159
204
  }, { autoRemove: (val) => testFalsy(val) || !(val === null || val === void 0 ? void 0 : val.length) });
160
205
  /**
161
206
  * The built-in filter function registry.
@@ -1 +1 @@
1
- {"version":3,"file":"filterFns.js","names":[],"sources":["../../src/fns/filterFns.ts"],"sourcesContent":["import type { RowData } from '../types/type-utils'\nimport type { TableFeatures } from '../types/TableFeatures'\nimport type { Row } from '../types/Row'\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 = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: unknown,\n ) => {\n return row.getValue(columnId) === filterValue\n },\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 = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: unknown,\n ) => {\n return row.getValue(columnId) == filterValue\n },\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 = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: unknown,\n ) => {\n return Boolean(\n row.getValue(columnId)?.toString().includes(String(filterValue)),\n )\n },\n { autoRemove: (val: any) => testFalsy(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 = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: unknown,\n ) => {\n return Boolean(\n row\n .getValue(columnId)\n ?.toString()\n .toLowerCase()\n .includes(String(filterValue).toLowerCase()),\n )\n },\n { autoRemove: (val: any) => testFalsy(val) },\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 = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: unknown,\n ) => {\n return (\n row.getValue(columnId)?.toString().toLowerCase() ===\n String(filterValue).toLowerCase()\n )\n },\n { autoRemove: (val: any) => testFalsy(val) },\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 = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: unknown,\n ) => {\n return row.getValue(columnId)?.toString() === String(filterValue)\n },\n { autoRemove: (val: any) => testFalsy(val) },\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 = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: unknown,\n ) => {\n const rowValue = row.getValue(columnId)\n const numericRowValue =\n rowValue === null || rowValue === undefined ? 0 : +rowValue\n const numericFilterValue = Number(filterValue)\n\n if (!isNaN(numericFilterValue) && !isNaN(numericRowValue)) {\n return numericRowValue > numericFilterValue\n }\n\n const stringValue = (rowValue ?? '').toString().toLowerCase().trim()\n const stringFilterValue = String(filterValue).toLowerCase().trim()\n return stringValue > stringFilterValue\n },\n { resolveFilterValue: (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 equality comparisons.\n */\nexport const filterFn_greaterThanOrEqualTo = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: unknown,\n ) => {\n return (\n filterFn_greaterThan(row, columnId, filterValue) ||\n filterFn_equals(row, columnId, filterValue)\n )\n },\n { resolveFilterValue: (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 = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: unknown,\n ) => {\n return !filterFn_greaterThanOrEqualTo(row, columnId, filterValue)\n },\n { resolveFilterValue: (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 = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: unknown,\n ) => {\n return !filterFn_greaterThan(row, columnId, filterValue)\n },\n { resolveFilterValue: (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 */\nconst filterFn_between = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValues: [unknown, unknown],\n ): boolean =>\n ((['', undefined] as Array<any>).includes(filterValues[0]) ||\n filterFn_greaterThan(row, columnId, filterValues[0])) &&\n ((!isNaN(Number(filterValues[0])) &&\n !isNaN(Number(filterValues[1])) &&\n Number(filterValues[0]) > Number(filterValues[1])) ||\n (['', undefined] as Array<any>).includes(filterValues[1]) ||\n filterFn_lessThan(row, columnId, filterValues[1])),\n {\n autoRemove: (val: any) =>\n testFalsy(val) || (testFalsy(val[0]) && testFalsy(val[1])),\n },\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 */\nconst filterFn_betweenInclusive = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValues: [unknown, unknown],\n ): boolean =>\n ((['', undefined] as Array<any>).includes(filterValues[0]) ||\n filterFn_greaterThanOrEqualTo(row, columnId, filterValues[0])) &&\n ((!isNaN(Number(filterValues[0])) &&\n !isNaN(Number(filterValues[1])) &&\n Number(filterValues[0]) > Number(filterValues[1])) ||\n (['', undefined] as Array<any>).includes(filterValues[1]) ||\n filterFn_lessThanOrEqualTo(row, columnId, filterValues[1])),\n {\n autoRemove: (val: any) =>\n testFalsy(val) || (testFalsy(val[0]) && testFalsy(val[1])),\n },\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 = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: [number, number],\n ) => {\n const [min, max] = filterValue\n\n const rowValue: number = row.getValue(columnId)\n return rowValue >= min && rowValue <= max\n },\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) || (testFalsy(val[0]) && testFalsy(val[1])),\n },\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 = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: Array<unknown>,\n ) => {\n return filterValue.some((val) => row.getValue<unknown>(columnId) === val)\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 = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: Array<unknown>,\n ) => {\n return filterValue.some((val) =>\n (row.getValue<unknown>(columnId) as Array<unknown> | string).includes(\n val as any,\n ),\n )\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 = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: Array<unknown>,\n ) => {\n const value = row.getValue<Array<unknown>>(columnId)\n if (!Array.isArray(value)) return false\n return !filterValue.some((val) => !value.includes(val))\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 = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: Array<unknown>,\n ) => {\n const value = row.getValue<Array<unknown>>(columnId)\n if (!Array.isArray(value)) return false\n return filterValue.some((val) => value.includes(val))\n },\n { autoRemove: (val: any) => testFalsy(val) || !val?.length },\n)\n\n// Export\n\n/**\n * The built-in filter function registry.\n *\n * Pass this object to filtered row model creation or extend it with custom filter functions.\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 equals: filterFn_equals,\n equalsString: filterFn_equalsString,\n inNumberRange: filterFn_inNumberRange,\n includesString: filterFn_includesString,\n includesStringSensitive: filterFn_includesStringSensitive,\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"],"mappings":"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"}
1
+ {"version":3,"file":"filterFns.js","names":[],"sources":["../../src/fns/filterFns.ts"],"sourcesContent":["import type { RowData } from '../types/type-utils'\nimport type { TableFeatures } from '../types/TableFeatures'\nimport type { Row } from '../types/Row'\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 = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: unknown,\n ) => {\n return row.getValue(columnId) === filterValue\n },\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 = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: unknown,\n ) => {\n return row.getValue(columnId) == filterValue\n },\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 = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: unknown,\n ) => {\n return Boolean(\n row.getValue(columnId)?.toString().includes(String(filterValue)),\n )\n },\n {\n autoRemove: (val: any) => testFalsy(val),\n resolveFilterValue: (val: any) => String(val),\n },\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 = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: unknown,\n ) => {\n return Boolean(\n row\n .getValue(columnId)\n ?.toString()\n .toLowerCase()\n .includes(String(filterValue).toLowerCase()),\n )\n },\n {\n autoRemove: (val: any) => testFalsy(val),\n resolveFilterValue: (val: any) => String(val).toLowerCase(),\n },\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 = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: unknown,\n ) => {\n return (\n row.getValue(columnId)?.toString().toLowerCase() ===\n String(filterValue).toLowerCase()\n )\n },\n {\n autoRemove: (val: any) => testFalsy(val),\n resolveFilterValue: (val: any) => String(val).toLowerCase(),\n },\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 = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: unknown,\n ) => {\n return row.getValue(columnId)?.toString() === String(filterValue)\n },\n {\n autoRemove: (val: any) => testFalsy(val),\n resolveFilterValue: (val: any) => String(val),\n },\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 = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: unknown,\n ) => {\n const rowValue = row.getValue(columnId)\n const numericRowValue =\n rowValue === null || rowValue === undefined ? 0 : +rowValue\n const numericFilterValue = Number(filterValue)\n\n if (!isNaN(numericFilterValue) && !isNaN(numericRowValue)) {\n return numericRowValue > numericFilterValue\n }\n\n const stringValue = (rowValue ?? '').toString().toLowerCase().trim()\n const stringFilterValue = String(filterValue).toLowerCase().trim()\n return stringValue > stringFilterValue\n },\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 equality comparisons.\n */\nexport const filterFn_greaterThanOrEqualTo = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: unknown,\n ) => {\n return (\n filterFn_greaterThan(row, columnId, filterValue) ||\n filterFn_equals(row, columnId, filterValue)\n )\n },\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 = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: unknown,\n ) => {\n return !filterFn_greaterThanOrEqualTo(row, columnId, filterValue)\n },\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 = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: unknown,\n ) => {\n return !filterFn_greaterThan(row, columnId, filterValue)\n },\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 */\nconst filterFn_between = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValues: [unknown, unknown],\n ): boolean => {\n const min = filterValues[0]\n if (min !== '' && min !== undefined) {\n if (!filterFn_greaterThan(row, columnId, min)) {\n return false\n }\n }\n\n const max = filterValues[1]\n if (max === '' || max === undefined) {\n return true\n }\n\n if (min !== '' && min !== undefined) {\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 filterFn_lessThan(row, columnId, max)\n },\n {\n autoRemove: (val: any) =>\n testFalsy(val) || (testFalsy(val[0]) && testFalsy(val[1])),\n },\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 */\nconst filterFn_betweenInclusive = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValues: [unknown, unknown],\n ): boolean => {\n const min = filterValues[0]\n if (min !== '' && min !== undefined) {\n if (!filterFn_greaterThanOrEqualTo(row, columnId, min)) {\n return false\n }\n }\n\n const max = filterValues[1]\n if (max === '' || max === undefined) {\n return true\n }\n\n if (min !== '' && min !== undefined) {\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 filterFn_lessThanOrEqualTo(row, columnId, max)\n },\n {\n autoRemove: (val: any) =>\n testFalsy(val) || (testFalsy(val[0]) && testFalsy(val[1])),\n },\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 = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: [number, number],\n ) => {\n const [min, max] = filterValue\n\n const rowValue: number = row.getValue(columnId)\n return rowValue >= min && rowValue <= max\n },\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) || (testFalsy(val[0]) && testFalsy(val[1])),\n },\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 = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: Array<unknown>,\n ) => {\n const value = row.getValue<unknown>(columnId)\n for (let i = 0; i < filterValue.length; i++) {\n if (value === 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 = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: Array<unknown>,\n ) => {\n const value = row.getValue<unknown>(columnId)\n if (typeof value !== 'string' && !Array.isArray(value)) {\n return false\n }\n\n for (let i = 0; i < filterValue.length; i++) {\n if (value.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 = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: Array<unknown>,\n ) => {\n const value = row.getValue<Array<unknown>>(columnId)\n if (!Array.isArray(value)) return false\n for (let i = 0; i < filterValue.length; i++) {\n if (!value.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 = Object.assign(\n <TFeatures extends TableFeatures, TData extends RowData>(\n row: Row<TFeatures, TData>,\n columnId: string,\n filterValue: Array<unknown>,\n ) => {\n const value = row.getValue<Array<unknown>>(columnId)\n if (!Array.isArray(value)) return false\n for (let i = 0; i < filterValue.length; i++) {\n if (value.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 * Pass this object to filtered row model creation or extend it with custom filter functions.\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 equals: filterFn_equals,\n equalsString: filterFn_equalsString,\n inNumberRange: filterFn_inNumberRange,\n includesString: filterFn_includesString,\n includesStringSensitive: filterFn_includesStringSensitive,\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"],"mappings":"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"}
@@ -45,8 +45,8 @@ const sortFn_textCaseSensitive = (rowA, rowB, columnId) => {
45
45
  * This comparator returns ascending-order results; descending order is applied by the sorting row model.
46
46
  */
47
47
  const sortFn_datetime = (rowA, rowB, columnId) => {
48
- const a = rowA.getValue(columnId);
49
- const b = rowB.getValue(columnId);
48
+ const a = toDateSortValue(rowA.getValue(columnId));
49
+ const b = toDateSortValue(rowB.getValue(columnId));
50
50
  return a > b ? 1 : a < b ? -1 : 0;
51
51
  };
52
52
  /**
@@ -60,6 +60,9 @@ const sortFn_basic = (rowA, rowB, columnId) => {
60
60
  function compareBasic(a, b) {
61
61
  return a === b ? 0 : a > b ? 1 : -1;
62
62
  }
63
+ function toDateSortValue(value) {
64
+ return value instanceof Date ? value.getTime() : value;
65
+ }
63
66
  function toString(a) {
64
67
  if (typeof a === "number") {
65
68
  if (isNaN(a) || a === Infinity || a === -Infinity) return "";
@@ -69,40 +72,86 @@ function toString(a) {
69
72
  return "";
70
73
  }
71
74
  function compareAlphanumeric(aStr, bStr) {
72
- const a = aStr.split(reSplitAlphaNumeric);
73
- const b = bStr.split(reSplitAlphaNumeric);
74
75
  let ai = 0;
75
76
  let bi = 0;
76
- const aLen = a.length;
77
- const bLen = b.length;
77
+ const aLen = aStr.length;
78
+ const bLen = bStr.length;
78
79
  while (ai < aLen && bi < bLen) {
79
- if (!a[ai]) {
80
- ai++;
81
- continue;
82
- }
83
- if (!b[bi]) {
84
- bi++;
80
+ const aIsNumeric = isDigit(aStr.charCodeAt(ai));
81
+ const bIsNumeric = isDigit(bStr.charCodeAt(bi));
82
+ const aEnd = findChunkEnd(aStr, ai, aIsNumeric);
83
+ const bEnd = findChunkEnd(bStr, bi, bIsNumeric);
84
+ if (!aIsNumeric && !bIsNumeric) {
85
+ const stringComparison = compareStringChunks(aStr, ai, aEnd, bStr, bi, bEnd);
86
+ if (stringComparison) return stringComparison;
87
+ ai = aEnd;
88
+ bi = bEnd;
85
89
  continue;
86
90
  }
87
- const aa = a[ai++];
88
- const bb = b[bi++];
89
- const an = parseInt(aa, 10);
90
- const bn = parseInt(bb, 10);
91
- const aIsNaN = isNaN(an);
92
- const bIsNaN = isNaN(bn);
93
- if (aIsNaN && bIsNaN) {
94
- if (aa > bb) return 1;
95
- if (bb > aa) return -1;
96
- continue;
97
- }
98
- if (aIsNaN || bIsNaN) return aIsNaN ? -1 : 1;
91
+ if (aIsNumeric !== bIsNumeric) return aIsNumeric ? 1 : -1;
92
+ const numericComparison = compareNumericChunks(aStr, ai, aEnd, bStr, bi, bEnd);
93
+ if (numericComparison) return numericComparison;
94
+ ai = aEnd;
95
+ bi = bEnd;
96
+ }
97
+ return countRemainingChunks(aStr, ai) - countRemainingChunks(bStr, bi);
98
+ }
99
+ function isDigit(charCode) {
100
+ return charCode >= 48 && charCode <= 57;
101
+ }
102
+ function findChunkEnd(str, start, isNumeric) {
103
+ let end = start + 1;
104
+ while (end < str.length && isDigit(str.charCodeAt(end)) === isNumeric) end++;
105
+ return end;
106
+ }
107
+ function compareStringChunks(aStr, aStart, aEnd, bStr, bStart, bEnd) {
108
+ const aLength = aEnd - aStart;
109
+ const bLength = bEnd - bStart;
110
+ const minLength = aLength < bLength ? aLength : bLength;
111
+ for (let i = 0; i < minLength; i++) {
112
+ const aCode = aStr.charCodeAt(aStart + i);
113
+ const bCode = bStr.charCodeAt(bStart + i);
114
+ if (aCode > bCode) return 1;
115
+ if (bCode > aCode) return -1;
116
+ }
117
+ if (aLength > bLength) return 1;
118
+ if (bLength > aLength) return -1;
119
+ return 0;
120
+ }
121
+ function compareNumericChunks(aStr, aStart, aEnd, bStr, bStart, bEnd) {
122
+ let aSignificantStart = aStart;
123
+ while (aSignificantStart < aEnd && aStr.charCodeAt(aSignificantStart) === 48) aSignificantStart++;
124
+ let bSignificantStart = bStart;
125
+ while (bSignificantStart < bEnd && bStr.charCodeAt(bSignificantStart) === 48) bSignificantStart++;
126
+ const aSignificantLength = aEnd - aSignificantStart;
127
+ const bSignificantLength = bEnd - bSignificantStart;
128
+ if (aSignificantLength === 0 && bSignificantLength === 0) return 0;
129
+ if (aSignificantLength <= 15 && bSignificantLength <= 15) {
130
+ const an = parseSmallInt(aStr, aSignificantStart, aEnd);
131
+ const bn = parseSmallInt(bStr, bSignificantStart, bEnd);
99
132
  if (an > bn) return 1;
100
133
  if (bn > an) return -1;
134
+ return 0;
135
+ }
136
+ const an = parseInt(aStr.slice(aStart, aEnd), 10);
137
+ const bn = parseInt(bStr.slice(bStart, bEnd), 10);
138
+ if (an > bn) return 1;
139
+ if (bn > an) return -1;
140
+ return 0;
141
+ }
142
+ function parseSmallInt(str, start, end) {
143
+ let result = 0;
144
+ for (let i = start; i < end; i++) result = result * 10 + str.charCodeAt(i) - 48;
145
+ return result;
146
+ }
147
+ function countRemainingChunks(str, start) {
148
+ let count = 0;
149
+ let index = start;
150
+ while (index < str.length) {
151
+ count++;
152
+ index = findChunkEnd(str, index, isDigit(str.charCodeAt(index)));
101
153
  }
102
- let remaining = 0;
103
- for (; ai < aLen; ai++) if (a[ai]) remaining++;
104
- for (; bi < bLen; bi++) if (b[bi]) remaining--;
105
- return remaining;
154
+ return count;
106
155
  }
107
156
  /**
108
157
  * The built-in sorting function registry.
@@ -1 +1 @@
1
- {"version":3,"file":"sortFns.cjs","names":[],"sources":["../../src/fns/sortFns.ts"],"sourcesContent":["import 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 * 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 = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareAlphanumeric(\n toString(rowA.getValue(columnId)).toLowerCase(),\n toString(rowB.getValue(columnId)).toLowerCase(),\n )\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 = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareAlphanumeric(\n toString(rowA.getValue(columnId)),\n toString(rowB.getValue(columnId)),\n )\n}\n\n// The text filter 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 = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareBasic(\n toString(rowA.getValue(columnId)).toLowerCase(),\n toString(rowB.getValue(columnId)).toLowerCase(),\n )\n}\n\n// The text filter 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 = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareBasic(\n toString(rowA.getValue(columnId)),\n toString(rowB.getValue(columnId)),\n )\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 = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n const a: number | string = rowA.getValue(columnId)\n const b: number | string = rowB.getValue(columnId)\n\n // Can handle nullish values\n // Use > and < because == (and ===) doesn't work with\n // Date objects (would require calling getTime()).\n return a > b ? 1 : a < b ? -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 = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareBasic(rowA.getValue(columnId), rowB.getValue(columnId))\n}\n\n// Utils\n\nfunction compareBasic(a: any, b: any) {\n return a === b ? 0 : a > b ? 1 : -1\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 const a = aStr.split(reSplitAlphaNumeric)\n const b = bStr.split(reSplitAlphaNumeric)\n\n let ai = 0\n let bi = 0\n const aLen = a.length\n const bLen = b.length\n\n while (ai < aLen && bi < bLen) {\n // Skip the empty boundary chunks that .filter(Boolean) used to remove\n if (!a[ai]) {\n ai++\n continue\n }\n if (!b[bi]) {\n bi++\n continue\n }\n\n const aa = a[ai++]!\n const bb = b[bi++]!\n\n // Chunks are either all-digit (parseInt always succeeds) or digit-free\n // (parseInt is always NaN), so NaN-ness fully classifies each chunk\n const an = parseInt(aa, 10)\n const bn = parseInt(bb, 10)\n\n const aIsNaN = isNaN(an)\n const bIsNaN = isNaN(bn)\n\n // Both are string\n if (aIsNaN && bIsNaN) {\n if (aa > bb) {\n return 1\n }\n if (bb > aa) {\n return -1\n }\n continue\n }\n\n // One is a string, one is a number — the string chunk sorts first\n if (aIsNaN || bIsNaN) {\n return aIsNaN ? -1 : 1\n }\n\n // Both are numbers\n if (an > bn) {\n return 1\n }\n if (bn > an) {\n return -1\n }\n }\n\n // One side is exhausted — compare the counts of remaining non-empty chunks\n let remaining = 0\n for (; ai < aLen; ai++) {\n if (a[ai]) {\n remaining++\n }\n }\n for (; bi < bLen; bi++) {\n if (b[bi]) {\n remaining--\n }\n }\n return remaining\n}\n\n// Exports\n\n/**\n * The built-in sorting function registry.\n *\n * Pass this object to sorted row model creation or extend it with custom sorting functions.\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":";;;;;;;;AAUA,MAAa,sBAAsB;;;;;;AAOnC,MAAa,uBAIX,MACA,MACA,aACG;CACH,OAAO,oBACL,SAAS,KAAK,SAAS,QAAQ,CAAC,CAAC,CAAC,YAAY,GAC9C,SAAS,KAAK,SAAS,QAAQ,CAAC,CAAC,CAAC,YAAY,CAChD;AACF;;;;;;AAOA,MAAa,oCAIX,MACA,MACA,aACG;CACH,OAAO,oBACL,SAAS,KAAK,SAAS,QAAQ,CAAC,GAChC,SAAS,KAAK,SAAS,QAAQ,CAAC,CAClC;AACF;;;;;;AASA,MAAa,eAIX,MACA,MACA,aACG;CACH,OAAO,aACL,SAAS,KAAK,SAAS,QAAQ,CAAC,CAAC,CAAC,YAAY,GAC9C,SAAS,KAAK,SAAS,QAAQ,CAAC,CAAC,CAAC,YAAY,CAChD;AACF;;;;;;AASA,MAAa,4BAIX,MACA,MACA,aACG;CACH,OAAO,aACL,SAAS,KAAK,SAAS,QAAQ,CAAC,GAChC,SAAS,KAAK,SAAS,QAAQ,CAAC,CAClC;AACF;;;;;;AAOA,MAAa,mBAIX,MACA,MACA,aACG;CACH,MAAM,IAAqB,KAAK,SAAS,QAAQ;CACjD,MAAM,IAAqB,KAAK,SAAS,QAAQ;CAKjD,OAAO,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK;AAClC;;;;;;AAOA,MAAa,gBAIX,MACA,MACA,aACG;CACH,OAAO,aAAa,KAAK,SAAS,QAAQ,GAAG,KAAK,SAAS,QAAQ,CAAC;AACtE;AAIA,SAAS,aAAa,GAAQ,GAAQ;CACpC,OAAO,MAAM,IAAI,IAAI,IAAI,IAAI,IAAI;AACnC;AAEA,SAAS,SAAS,GAAQ;CACxB,IAAI,OAAO,MAAM,UAAU;EACzB,IAAI,MAAM,CAAC,KAAK,MAAM,YAAY,MAAM,WACtC,OAAO;EAET,OAAO,OAAO,CAAC;CACjB;CACA,IAAI,OAAO,MAAM,UACf,OAAO;CAET,OAAO;AACT;AAKA,SAAS,oBAAoB,MAAc,MAAc;CACvD,MAAM,IAAI,KAAK,MAAM,mBAAmB;CACxC,MAAM,IAAI,KAAK,MAAM,mBAAmB;CAExC,IAAI,KAAK;CACT,IAAI,KAAK;CACT,MAAM,OAAO,EAAE;CACf,MAAM,OAAO,EAAE;CAEf,OAAO,KAAK,QAAQ,KAAK,MAAM;EAE7B,IAAI,CAAC,EAAE,KAAK;GACV;GACA;EACF;EACA,IAAI,CAAC,EAAE,KAAK;GACV;GACA;EACF;EAEA,MAAM,KAAK,EAAE;EACb,MAAM,KAAK,EAAE;EAIb,MAAM,KAAK,SAAS,IAAI,EAAE;EAC1B,MAAM,KAAK,SAAS,IAAI,EAAE;EAE1B,MAAM,SAAS,MAAM,EAAE;EACvB,MAAM,SAAS,MAAM,EAAE;EAGvB,IAAI,UAAU,QAAQ;GACpB,IAAI,KAAK,IACP,OAAO;GAET,IAAI,KAAK,IACP,OAAO;GAET;EACF;EAGA,IAAI,UAAU,QACZ,OAAO,SAAS,KAAK;EAIvB,IAAI,KAAK,IACP,OAAO;EAET,IAAI,KAAK,IACP,OAAO;CAEX;CAGA,IAAI,YAAY;CAChB,OAAO,KAAK,MAAM,MAChB,IAAI,EAAE,KACJ;CAGJ,OAAO,KAAK,MAAM,MAChB,IAAI,EAAE,KACJ;CAGJ,OAAO;AACT;;;;;;AASA,MAAa,UAAU;CACrB,cAAc;CACd,2BAA2B;CAC3B,OAAO;CACP,UAAU;CACV,MAAM;CACN,mBAAmB;AACrB"}
1
+ {"version":3,"file":"sortFns.cjs","names":[],"sources":["../../src/fns/sortFns.ts"],"sourcesContent":["import 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 * 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 = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareAlphanumeric(\n toString(rowA.getValue(columnId)).toLowerCase(),\n toString(rowB.getValue(columnId)).toLowerCase(),\n )\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 = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareAlphanumeric(\n toString(rowA.getValue(columnId)),\n toString(rowB.getValue(columnId)),\n )\n}\n\n// The text filter 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 = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareBasic(\n toString(rowA.getValue(columnId)).toLowerCase(),\n toString(rowB.getValue(columnId)).toLowerCase(),\n )\n}\n\n// The text filter 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 = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareBasic(\n toString(rowA.getValue(columnId)),\n toString(rowB.getValue(columnId)),\n )\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 = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n const a = toDateSortValue(rowA.getValue(columnId))\n const b = toDateSortValue(rowB.getValue(columnId))\n\n // Can handle nullish values\n // Use > and < because == (and ===) doesn't work with\n // Date objects (would require calling getTime()).\n return a > b ? 1 : a < b ? -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 = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareBasic(rowA.getValue(columnId), rowB.getValue(columnId))\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 * Pass this object to sorted row model creation or extend it with custom sorting functions.\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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"}
@@ -44,8 +44,8 @@ const sortFn_textCaseSensitive = (rowA, rowB, columnId) => {
44
44
  * This comparator returns ascending-order results; descending order is applied by the sorting row model.
45
45
  */
46
46
  const sortFn_datetime = (rowA, rowB, columnId) => {
47
- const a = rowA.getValue(columnId);
48
- const b = rowB.getValue(columnId);
47
+ const a = toDateSortValue(rowA.getValue(columnId));
48
+ const b = toDateSortValue(rowB.getValue(columnId));
49
49
  return a > b ? 1 : a < b ? -1 : 0;
50
50
  };
51
51
  /**
@@ -59,6 +59,9 @@ const sortFn_basic = (rowA, rowB, columnId) => {
59
59
  function compareBasic(a, b) {
60
60
  return a === b ? 0 : a > b ? 1 : -1;
61
61
  }
62
+ function toDateSortValue(value) {
63
+ return value instanceof Date ? value.getTime() : value;
64
+ }
62
65
  function toString(a) {
63
66
  if (typeof a === "number") {
64
67
  if (isNaN(a) || a === Infinity || a === -Infinity) return "";
@@ -68,40 +71,86 @@ function toString(a) {
68
71
  return "";
69
72
  }
70
73
  function compareAlphanumeric(aStr, bStr) {
71
- const a = aStr.split(reSplitAlphaNumeric);
72
- const b = bStr.split(reSplitAlphaNumeric);
73
74
  let ai = 0;
74
75
  let bi = 0;
75
- const aLen = a.length;
76
- const bLen = b.length;
76
+ const aLen = aStr.length;
77
+ const bLen = bStr.length;
77
78
  while (ai < aLen && bi < bLen) {
78
- if (!a[ai]) {
79
- ai++;
80
- continue;
81
- }
82
- if (!b[bi]) {
83
- bi++;
79
+ const aIsNumeric = isDigit(aStr.charCodeAt(ai));
80
+ const bIsNumeric = isDigit(bStr.charCodeAt(bi));
81
+ const aEnd = findChunkEnd(aStr, ai, aIsNumeric);
82
+ const bEnd = findChunkEnd(bStr, bi, bIsNumeric);
83
+ if (!aIsNumeric && !bIsNumeric) {
84
+ const stringComparison = compareStringChunks(aStr, ai, aEnd, bStr, bi, bEnd);
85
+ if (stringComparison) return stringComparison;
86
+ ai = aEnd;
87
+ bi = bEnd;
84
88
  continue;
85
89
  }
86
- const aa = a[ai++];
87
- const bb = b[bi++];
88
- const an = parseInt(aa, 10);
89
- const bn = parseInt(bb, 10);
90
- const aIsNaN = isNaN(an);
91
- const bIsNaN = isNaN(bn);
92
- if (aIsNaN && bIsNaN) {
93
- if (aa > bb) return 1;
94
- if (bb > aa) return -1;
95
- continue;
96
- }
97
- if (aIsNaN || bIsNaN) return aIsNaN ? -1 : 1;
90
+ if (aIsNumeric !== bIsNumeric) return aIsNumeric ? 1 : -1;
91
+ const numericComparison = compareNumericChunks(aStr, ai, aEnd, bStr, bi, bEnd);
92
+ if (numericComparison) return numericComparison;
93
+ ai = aEnd;
94
+ bi = bEnd;
95
+ }
96
+ return countRemainingChunks(aStr, ai) - countRemainingChunks(bStr, bi);
97
+ }
98
+ function isDigit(charCode) {
99
+ return charCode >= 48 && charCode <= 57;
100
+ }
101
+ function findChunkEnd(str, start, isNumeric) {
102
+ let end = start + 1;
103
+ while (end < str.length && isDigit(str.charCodeAt(end)) === isNumeric) end++;
104
+ return end;
105
+ }
106
+ function compareStringChunks(aStr, aStart, aEnd, bStr, bStart, bEnd) {
107
+ const aLength = aEnd - aStart;
108
+ const bLength = bEnd - bStart;
109
+ const minLength = aLength < bLength ? aLength : bLength;
110
+ for (let i = 0; i < minLength; i++) {
111
+ const aCode = aStr.charCodeAt(aStart + i);
112
+ const bCode = bStr.charCodeAt(bStart + i);
113
+ if (aCode > bCode) return 1;
114
+ if (bCode > aCode) return -1;
115
+ }
116
+ if (aLength > bLength) return 1;
117
+ if (bLength > aLength) return -1;
118
+ return 0;
119
+ }
120
+ function compareNumericChunks(aStr, aStart, aEnd, bStr, bStart, bEnd) {
121
+ let aSignificantStart = aStart;
122
+ while (aSignificantStart < aEnd && aStr.charCodeAt(aSignificantStart) === 48) aSignificantStart++;
123
+ let bSignificantStart = bStart;
124
+ while (bSignificantStart < bEnd && bStr.charCodeAt(bSignificantStart) === 48) bSignificantStart++;
125
+ const aSignificantLength = aEnd - aSignificantStart;
126
+ const bSignificantLength = bEnd - bSignificantStart;
127
+ if (aSignificantLength === 0 && bSignificantLength === 0) return 0;
128
+ if (aSignificantLength <= 15 && bSignificantLength <= 15) {
129
+ const an = parseSmallInt(aStr, aSignificantStart, aEnd);
130
+ const bn = parseSmallInt(bStr, bSignificantStart, bEnd);
98
131
  if (an > bn) return 1;
99
132
  if (bn > an) return -1;
133
+ return 0;
134
+ }
135
+ const an = parseInt(aStr.slice(aStart, aEnd), 10);
136
+ const bn = parseInt(bStr.slice(bStart, bEnd), 10);
137
+ if (an > bn) return 1;
138
+ if (bn > an) return -1;
139
+ return 0;
140
+ }
141
+ function parseSmallInt(str, start, end) {
142
+ let result = 0;
143
+ for (let i = start; i < end; i++) result = result * 10 + str.charCodeAt(i) - 48;
144
+ return result;
145
+ }
146
+ function countRemainingChunks(str, start) {
147
+ let count = 0;
148
+ let index = start;
149
+ while (index < str.length) {
150
+ count++;
151
+ index = findChunkEnd(str, index, isDigit(str.charCodeAt(index)));
100
152
  }
101
- let remaining = 0;
102
- for (; ai < aLen; ai++) if (a[ai]) remaining++;
103
- for (; bi < bLen; bi++) if (b[bi]) remaining--;
104
- return remaining;
153
+ return count;
105
154
  }
106
155
  /**
107
156
  * The built-in sorting function registry.
@@ -1 +1 @@
1
- {"version":3,"file":"sortFns.js","names":[],"sources":["../../src/fns/sortFns.ts"],"sourcesContent":["import 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 * 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 = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareAlphanumeric(\n toString(rowA.getValue(columnId)).toLowerCase(),\n toString(rowB.getValue(columnId)).toLowerCase(),\n )\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 = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareAlphanumeric(\n toString(rowA.getValue(columnId)),\n toString(rowB.getValue(columnId)),\n )\n}\n\n// The text filter 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 = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareBasic(\n toString(rowA.getValue(columnId)).toLowerCase(),\n toString(rowB.getValue(columnId)).toLowerCase(),\n )\n}\n\n// The text filter 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 = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareBasic(\n toString(rowA.getValue(columnId)),\n toString(rowB.getValue(columnId)),\n )\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 = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n const a: number | string = rowA.getValue(columnId)\n const b: number | string = rowB.getValue(columnId)\n\n // Can handle nullish values\n // Use > and < because == (and ===) doesn't work with\n // Date objects (would require calling getTime()).\n return a > b ? 1 : a < b ? -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 = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareBasic(rowA.getValue(columnId), rowB.getValue(columnId))\n}\n\n// Utils\n\nfunction compareBasic(a: any, b: any) {\n return a === b ? 0 : a > b ? 1 : -1\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 const a = aStr.split(reSplitAlphaNumeric)\n const b = bStr.split(reSplitAlphaNumeric)\n\n let ai = 0\n let bi = 0\n const aLen = a.length\n const bLen = b.length\n\n while (ai < aLen && bi < bLen) {\n // Skip the empty boundary chunks that .filter(Boolean) used to remove\n if (!a[ai]) {\n ai++\n continue\n }\n if (!b[bi]) {\n bi++\n continue\n }\n\n const aa = a[ai++]!\n const bb = b[bi++]!\n\n // Chunks are either all-digit (parseInt always succeeds) or digit-free\n // (parseInt is always NaN), so NaN-ness fully classifies each chunk\n const an = parseInt(aa, 10)\n const bn = parseInt(bb, 10)\n\n const aIsNaN = isNaN(an)\n const bIsNaN = isNaN(bn)\n\n // Both are string\n if (aIsNaN && bIsNaN) {\n if (aa > bb) {\n return 1\n }\n if (bb > aa) {\n return -1\n }\n continue\n }\n\n // One is a string, one is a number — the string chunk sorts first\n if (aIsNaN || bIsNaN) {\n return aIsNaN ? -1 : 1\n }\n\n // Both are numbers\n if (an > bn) {\n return 1\n }\n if (bn > an) {\n return -1\n }\n }\n\n // One side is exhausted — compare the counts of remaining non-empty chunks\n let remaining = 0\n for (; ai < aLen; ai++) {\n if (a[ai]) {\n remaining++\n }\n }\n for (; bi < bLen; bi++) {\n if (b[bi]) {\n remaining--\n }\n }\n return remaining\n}\n\n// Exports\n\n/**\n * The built-in sorting function registry.\n *\n * Pass this object to sorted row model creation or extend it with custom sorting functions.\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":";;;;;;;AAUA,MAAa,sBAAsB;;;;;;AAOnC,MAAa,uBAIX,MACA,MACA,aACG;CACH,OAAO,oBACL,SAAS,KAAK,SAAS,QAAQ,CAAC,CAAC,CAAC,YAAY,GAC9C,SAAS,KAAK,SAAS,QAAQ,CAAC,CAAC,CAAC,YAAY,CAChD;AACF;;;;;;AAOA,MAAa,oCAIX,MACA,MACA,aACG;CACH,OAAO,oBACL,SAAS,KAAK,SAAS,QAAQ,CAAC,GAChC,SAAS,KAAK,SAAS,QAAQ,CAAC,CAClC;AACF;;;;;;AASA,MAAa,eAIX,MACA,MACA,aACG;CACH,OAAO,aACL,SAAS,KAAK,SAAS,QAAQ,CAAC,CAAC,CAAC,YAAY,GAC9C,SAAS,KAAK,SAAS,QAAQ,CAAC,CAAC,CAAC,YAAY,CAChD;AACF;;;;;;AASA,MAAa,4BAIX,MACA,MACA,aACG;CACH,OAAO,aACL,SAAS,KAAK,SAAS,QAAQ,CAAC,GAChC,SAAS,KAAK,SAAS,QAAQ,CAAC,CAClC;AACF;;;;;;AAOA,MAAa,mBAIX,MACA,MACA,aACG;CACH,MAAM,IAAqB,KAAK,SAAS,QAAQ;CACjD,MAAM,IAAqB,KAAK,SAAS,QAAQ;CAKjD,OAAO,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK;AAClC;;;;;;AAOA,MAAa,gBAIX,MACA,MACA,aACG;CACH,OAAO,aAAa,KAAK,SAAS,QAAQ,GAAG,KAAK,SAAS,QAAQ,CAAC;AACtE;AAIA,SAAS,aAAa,GAAQ,GAAQ;CACpC,OAAO,MAAM,IAAI,IAAI,IAAI,IAAI,IAAI;AACnC;AAEA,SAAS,SAAS,GAAQ;CACxB,IAAI,OAAO,MAAM,UAAU;EACzB,IAAI,MAAM,CAAC,KAAK,MAAM,YAAY,MAAM,WACtC,OAAO;EAET,OAAO,OAAO,CAAC;CACjB;CACA,IAAI,OAAO,MAAM,UACf,OAAO;CAET,OAAO;AACT;AAKA,SAAS,oBAAoB,MAAc,MAAc;CACvD,MAAM,IAAI,KAAK,MAAM,mBAAmB;CACxC,MAAM,IAAI,KAAK,MAAM,mBAAmB;CAExC,IAAI,KAAK;CACT,IAAI,KAAK;CACT,MAAM,OAAO,EAAE;CACf,MAAM,OAAO,EAAE;CAEf,OAAO,KAAK,QAAQ,KAAK,MAAM;EAE7B,IAAI,CAAC,EAAE,KAAK;GACV;GACA;EACF;EACA,IAAI,CAAC,EAAE,KAAK;GACV;GACA;EACF;EAEA,MAAM,KAAK,EAAE;EACb,MAAM,KAAK,EAAE;EAIb,MAAM,KAAK,SAAS,IAAI,EAAE;EAC1B,MAAM,KAAK,SAAS,IAAI,EAAE;EAE1B,MAAM,SAAS,MAAM,EAAE;EACvB,MAAM,SAAS,MAAM,EAAE;EAGvB,IAAI,UAAU,QAAQ;GACpB,IAAI,KAAK,IACP,OAAO;GAET,IAAI,KAAK,IACP,OAAO;GAET;EACF;EAGA,IAAI,UAAU,QACZ,OAAO,SAAS,KAAK;EAIvB,IAAI,KAAK,IACP,OAAO;EAET,IAAI,KAAK,IACP,OAAO;CAEX;CAGA,IAAI,YAAY;CAChB,OAAO,KAAK,MAAM,MAChB,IAAI,EAAE,KACJ;CAGJ,OAAO,KAAK,MAAM,MAChB,IAAI,EAAE,KACJ;CAGJ,OAAO;AACT;;;;;;AASA,MAAa,UAAU;CACrB,cAAc;CACd,2BAA2B;CAC3B,OAAO;CACP,UAAU;CACV,MAAM;CACN,mBAAmB;AACrB"}
1
+ {"version":3,"file":"sortFns.js","names":[],"sources":["../../src/fns/sortFns.ts"],"sourcesContent":["import 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 * 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 = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareAlphanumeric(\n toString(rowA.getValue(columnId)).toLowerCase(),\n toString(rowB.getValue(columnId)).toLowerCase(),\n )\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 = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareAlphanumeric(\n toString(rowA.getValue(columnId)),\n toString(rowB.getValue(columnId)),\n )\n}\n\n// The text filter 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 = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareBasic(\n toString(rowA.getValue(columnId)).toLowerCase(),\n toString(rowB.getValue(columnId)).toLowerCase(),\n )\n}\n\n// The text filter 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 = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareBasic(\n toString(rowA.getValue(columnId)),\n toString(rowB.getValue(columnId)),\n )\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 = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n const a = toDateSortValue(rowA.getValue(columnId))\n const b = toDateSortValue(rowB.getValue(columnId))\n\n // Can handle nullish values\n // Use > and < because == (and ===) doesn't work with\n // Date objects (would require calling getTime()).\n return a > b ? 1 : a < b ? -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 = <\n TFeatures extends TableFeatures,\n TData extends RowData,\n>(\n rowA: Row<TFeatures, TData>,\n rowB: Row<TFeatures, TData>,\n columnId: string,\n) => {\n return compareBasic(rowA.getValue(columnId), rowB.getValue(columnId))\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 * Pass this object to sorted row model creation or extend it with custom sorting functions.\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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/table-core",
3
- "version": "9.0.0-beta.28",
3
+ "version": "9.0.0-beta.30",
4
4
  "description": "Headless UI for building powerful tables & datagrids for TS/JS.",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",