@fileverse-dev/formulajs 4.4.16 → 4.4.17-fix-sort-fn-2

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/lib/cjs/index.cjs CHANGED
@@ -1271,47 +1271,74 @@ function ROWS(array) {
1271
1271
  * @returns
1272
1272
  */
1273
1273
  function SORT(array, sort_index = 1, sort_order = 1, by_col = false) {
1274
- if (!array || !Array.isArray(array)) {
1275
- return na
1276
- }
1274
+ console.log("SORT function called with arguments:", { array, sort_index, sort_order, by_col });
1275
+ if (!array || !Array.isArray(array)) return na;
1276
+ if (array.length === 0) return 0;
1277
1277
 
1278
- if (array.length === 0) {
1279
- return 0
1280
- }
1278
+ let idx = parseNumber(sort_index);
1279
+ if (!idx || idx < 1) return value;
1280
+ idx = idx - 1;
1281
1281
 
1282
- sort_index = parseNumber(sort_index);
1283
- if (!sort_index || sort_index < 1) {
1284
- return value
1285
- }
1282
+ let order = parseNumber(sort_order);
1283
+ if (order !== 1 && order !== -1) return value;
1286
1284
 
1287
- sort_order = parseNumber(sort_order);
1288
- if (sort_order !== 1 && sort_order !== -1) {
1289
- return value
1290
- }
1285
+ const byCol = parseBool(by_col);
1286
+ if (typeof byCol !== "boolean") return name;
1287
+
1288
+ // Rectangularize then orient
1289
+ const matrix = fillMatrix(array);
1290
+ const working = byCol ? transpose(matrix) : matrix;
1291
1291
 
1292
- by_col = parseBool(by_col);
1293
- if (typeof by_col !== 'boolean') {
1294
- return name
1292
+ if (!working.length || !working[0] || idx >= working[0].length) {
1293
+ return value; // out of bounds
1295
1294
  }
1296
1295
 
1297
- const sortArray = (arr) =>
1298
- arr.sort((a, b) => {
1299
- a = parseString(a[sort_index - 1]);
1300
- b = parseString(b[sort_index - 1]);
1296
+ // Helpers (aiming for spreadsheet-ish behavior)
1297
+ const isBlank = (v) => v === "" || v === null || v === undefined;
1301
1298
 
1302
- return sort_order === 1 ? (a < b ? sort_order * -1 : sort_order) : a > b ? sort_order : sort_order * -1
1303
- });
1299
+ const cmp = (a, b) => {
1300
+ // Blanks last (ascending); we'll multiply by order later for descending.
1301
+ const aBlank = isBlank(a);
1302
+ const bBlank = isBlank(b);
1303
+ if (aBlank && bBlank) return 0;
1304
+ if (aBlank) return 1;
1305
+ if (bBlank) return -1;
1304
1306
 
1305
- const matrix = fillMatrix(array);
1306
- const result = by_col ? transpose(matrix) : matrix;
1307
+ // If both parse as finite numbers, compare numerically
1308
+ const na = parseNumber(a);
1309
+ const nb = parseNumber(b);
1310
+ const aNum = Number.isFinite(na);
1311
+ const bNum = Number.isFinite(nb);
1307
1312
 
1308
- return sort_index >= 1 && sort_index <= result[0].length
1309
- ? by_col
1310
- ? transpose(sortArray(result))
1311
- : sortArray(result)
1312
- : value
1313
+ if (aNum && bNum) {
1314
+ if (na < nb) return -1;
1315
+ if (na > nb) return 1;
1316
+ return 0;
1317
+ }
1318
+
1319
+ // Fallback: case-insensitive string compare
1320
+ const sa = (parseString(a) ?? "").toString().toLowerCase();
1321
+ const sb = (parseString(b) ?? "").toString().toLowerCase();
1322
+ if (sa < sb) return -1;
1323
+ if (sa > sb) return 1;
1324
+ return 0;
1325
+ };
1326
+
1327
+ // Stable sort: decorate with original index
1328
+ const decorated = working.map((row, i) => ({ row, i }));
1329
+
1330
+ decorated.sort((A, B) => {
1331
+ const base = cmp(A.row[idx], B.row[idx]);
1332
+ if (base !== 0) return base * order;
1333
+ // stable tiebreaker: original order
1334
+ return A.i - B.i;
1335
+ });
1336
+
1337
+ const sorted = decorated.map((d) => d.row);
1338
+ return byCol ? transpose(sorted) : sorted;
1313
1339
  }
1314
1340
 
1341
+
1315
1342
  /**
1316
1343
  * Returns the transpose of an array.
1317
1344
  *
@@ -18586,17 +18613,22 @@ const SUPPORTED_TOKEN_NAMES = {
18586
18613
 
18587
18614
 
18588
18615
  function formatNumber(raw, decimals) {
18589
- if(!decimals){
18616
+ try {
18617
+ if(!decimals){
18618
+ return raw
18619
+ }
18620
+ const quorum = BigInt(raw);
18621
+ const divisor = 10 ** decimals;
18622
+ const normalized = Number(quorum) / divisor;
18623
+
18624
+ return new Intl.NumberFormat("en-US", {
18625
+ notation: "compact",
18626
+ maximumFractionDigits: 2,
18627
+ }).format(normalized);
18628
+ } catch (error) {
18629
+ console.log({error});
18590
18630
  return raw
18591
18631
  }
18592
- const quorum = BigInt(raw);
18593
- const divisor = 10 ** decimals;
18594
- const normalized = Number(quorum) / divisor;
18595
-
18596
- return new Intl.NumberFormat("en-US", {
18597
- notation: "compact",
18598
- maximumFractionDigits: 2,
18599
- }).format(normalized);
18600
18632
  }
18601
18633
 
18602
18634
  let cachedChains = null;
package/lib/esm/index.mjs CHANGED
@@ -1269,47 +1269,74 @@ function ROWS(array) {
1269
1269
  * @returns
1270
1270
  */
1271
1271
  function SORT(array, sort_index = 1, sort_order = 1, by_col = false) {
1272
- if (!array || !Array.isArray(array)) {
1273
- return na
1274
- }
1272
+ console.log("SORT function called with arguments:", { array, sort_index, sort_order, by_col });
1273
+ if (!array || !Array.isArray(array)) return na;
1274
+ if (array.length === 0) return 0;
1275
1275
 
1276
- if (array.length === 0) {
1277
- return 0
1278
- }
1276
+ let idx = parseNumber(sort_index);
1277
+ if (!idx || idx < 1) return value;
1278
+ idx = idx - 1;
1279
1279
 
1280
- sort_index = parseNumber(sort_index);
1281
- if (!sort_index || sort_index < 1) {
1282
- return value
1283
- }
1280
+ let order = parseNumber(sort_order);
1281
+ if (order !== 1 && order !== -1) return value;
1284
1282
 
1285
- sort_order = parseNumber(sort_order);
1286
- if (sort_order !== 1 && sort_order !== -1) {
1287
- return value
1288
- }
1283
+ const byCol = parseBool(by_col);
1284
+ if (typeof byCol !== "boolean") return name;
1285
+
1286
+ // Rectangularize then orient
1287
+ const matrix = fillMatrix(array);
1288
+ const working = byCol ? transpose(matrix) : matrix;
1289
1289
 
1290
- by_col = parseBool(by_col);
1291
- if (typeof by_col !== 'boolean') {
1292
- return name
1290
+ if (!working.length || !working[0] || idx >= working[0].length) {
1291
+ return value; // out of bounds
1293
1292
  }
1294
1293
 
1295
- const sortArray = (arr) =>
1296
- arr.sort((a, b) => {
1297
- a = parseString(a[sort_index - 1]);
1298
- b = parseString(b[sort_index - 1]);
1294
+ // Helpers (aiming for spreadsheet-ish behavior)
1295
+ const isBlank = (v) => v === "" || v === null || v === undefined;
1299
1296
 
1300
- return sort_order === 1 ? (a < b ? sort_order * -1 : sort_order) : a > b ? sort_order : sort_order * -1
1301
- });
1297
+ const cmp = (a, b) => {
1298
+ // Blanks last (ascending); we'll multiply by order later for descending.
1299
+ const aBlank = isBlank(a);
1300
+ const bBlank = isBlank(b);
1301
+ if (aBlank && bBlank) return 0;
1302
+ if (aBlank) return 1;
1303
+ if (bBlank) return -1;
1302
1304
 
1303
- const matrix = fillMatrix(array);
1304
- const result = by_col ? transpose(matrix) : matrix;
1305
+ // If both parse as finite numbers, compare numerically
1306
+ const na = parseNumber(a);
1307
+ const nb = parseNumber(b);
1308
+ const aNum = Number.isFinite(na);
1309
+ const bNum = Number.isFinite(nb);
1305
1310
 
1306
- return sort_index >= 1 && sort_index <= result[0].length
1307
- ? by_col
1308
- ? transpose(sortArray(result))
1309
- : sortArray(result)
1310
- : value
1311
+ if (aNum && bNum) {
1312
+ if (na < nb) return -1;
1313
+ if (na > nb) return 1;
1314
+ return 0;
1315
+ }
1316
+
1317
+ // Fallback: case-insensitive string compare
1318
+ const sa = (parseString(a) ?? "").toString().toLowerCase();
1319
+ const sb = (parseString(b) ?? "").toString().toLowerCase();
1320
+ if (sa < sb) return -1;
1321
+ if (sa > sb) return 1;
1322
+ return 0;
1323
+ };
1324
+
1325
+ // Stable sort: decorate with original index
1326
+ const decorated = working.map((row, i) => ({ row, i }));
1327
+
1328
+ decorated.sort((A, B) => {
1329
+ const base = cmp(A.row[idx], B.row[idx]);
1330
+ if (base !== 0) return base * order;
1331
+ // stable tiebreaker: original order
1332
+ return A.i - B.i;
1333
+ });
1334
+
1335
+ const sorted = decorated.map((d) => d.row);
1336
+ return byCol ? transpose(sorted) : sorted;
1311
1337
  }
1312
1338
 
1339
+
1313
1340
  /**
1314
1341
  * Returns the transpose of an array.
1315
1342
  *
@@ -18584,17 +18611,22 @@ const SUPPORTED_TOKEN_NAMES = {
18584
18611
 
18585
18612
 
18586
18613
  function formatNumber(raw, decimals) {
18587
- if(!decimals){
18614
+ try {
18615
+ if(!decimals){
18616
+ return raw
18617
+ }
18618
+ const quorum = BigInt(raw);
18619
+ const divisor = 10 ** decimals;
18620
+ const normalized = Number(quorum) / divisor;
18621
+
18622
+ return new Intl.NumberFormat("en-US", {
18623
+ notation: "compact",
18624
+ maximumFractionDigits: 2,
18625
+ }).format(normalized);
18626
+ } catch (error) {
18627
+ console.log({error});
18588
18628
  return raw
18589
18629
  }
18590
- const quorum = BigInt(raw);
18591
- const divisor = 10 ** decimals;
18592
- const normalized = Number(quorum) / divisor;
18593
-
18594
- return new Intl.NumberFormat("en-US", {
18595
- notation: "compact",
18596
- maximumFractionDigits: 2,
18597
- }).format(normalized);
18598
18630
  }
18599
18631
 
18600
18632
  let cachedChains = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fileverse-dev/formulajs",
3
- "version": "4.4.16",
3
+ "version": "4.4.17-fix-sort-fn-2",
4
4
  "description": "JavaScript implementation of most Microsoft Excel formula functions",
5
5
  "author": "Formulajs",
6
6
  "publishConfig": {