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

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