Skip to content

Commit 07d7284

Browse files
committed
Merge branch 'fixSort' of github.com:kajoseph/bitcore
2 parents 584126a + 290abb1 commit 07d7284

2 files changed

Lines changed: 36 additions & 27 deletions

File tree

packages/bitcore-wallet-service/src/lib/common/utils.ts

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -381,46 +381,50 @@ export const Utils = {
381381
* @returns
382382
*/
383383
sortAsc<T = any>(arr: Array<T>, ...keys: (string | string[])[]): Array<T> {
384-
function transformVals(val1, val2) {
385-
if (val1 === undefined) {
386-
val1 = '\uFFFF'; // highest possible string value, otherwise 'undefined' < 'xyz'
387-
} else if (val1 === null || val1 === false || val1.toString() === 'NaN') {
388-
val1 = '0';
389-
} else if (val1 === true) {
390-
val1 = '1';
384+
function normalizeVal(v) {
385+
if (v === undefined) return '\uFFFF'; // highest possible value, sorts last
386+
if (v === null || v === false || v?.toString() === 'NaN') return 0;
387+
if (v === true) return 1;
388+
return v;
389+
}
390+
391+
function compareVals(a, b): number {
392+
a = normalizeVal(a);
393+
b = normalizeVal(b);
394+
395+
// Compare bigints directly to avoid loss of precision via Number()
396+
if (typeof a === 'bigint' && typeof b === 'bigint') {
397+
return a < b ? -1 : a > b ? 1 : 0;
391398
}
392399

393-
if (val2 === undefined) {
394-
val2 = '\uFFFF'; // highest possible string value, otherwise 'undefined' < 'xyz'
395-
} else if (val2 === null || val2 === false || val2.toString() === 'NaN') {
396-
val2 = '0';
397-
} else if (val2 === true) {
398-
val2 = '1';
400+
// Numeric comparison for numbers, bigints, and non-empty numeric strings
401+
const aIsNumeric = typeof a !== 'string' ? !isNaN(Number(a)) : a.trim() !== '' && !isNaN(Number(a));
402+
const bIsNumeric = typeof b !== 'string' ? !isNaN(Number(b)) : b.trim() !== '' && !isNaN(Number(b));
403+
if (aIsNumeric && bIsNumeric) {
404+
const na = Number(a);
405+
const nb = Number(b);
406+
return na < nb ? -1 : na > nb ? 1 : 0;
399407
}
400408

401-
return [Buffer.from(val1.toString()), Buffer.from(val2.toString())];
402-
};
409+
// String comparison fallback
410+
const sa = String(a);
411+
const sb = String(b);
412+
return sa < sb ? -1 : sa > sb ? 1 : 0;
413+
}
403414

404415
if (!keys.length) {
405-
return arr.sort((a, b) => { const [_a, _b] = transformVals(a, b); return _a.compare(_b); });
406-
} else if (keys.length === 1 && !Array.isArray(keys[0])) {
407-
const key = keys[0];
408-
return arr.sort((a, b) => { const [_a, _b] = transformVals(a[key], b[key]); return _a.compare(_b); });
416+
return arr.sort((a, b) => compareVals(a, b));
409417
}
418+
410419
return arr.sort((a, b) => {
411-
// compare concatenated strings for multiple key sorting
412-
let aVal = '';
413-
let bVal = '';
414420
for (const k of keys) {
415-
const [aTemp, bTemp] = transformVals(
421+
const cmp = compareVals(
416422
Array.isArray(k) ? k.reduce((val, key) => val[key], a) : a[k],
417423
Array.isArray(k) ? k.reduce((val, key) => val[key], b) : b[k]
418424
);
419-
420-
aVal += aTemp.toString();
421-
bVal += bTemp.toString();
425+
if (cmp !== 0) return cmp;
422426
}
423-
return Buffer.from(aVal).compare(Buffer.from(bVal));
427+
return 0;
424428
});
425429
},
426430

packages/bitcore-wallet-service/test/utils.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,11 @@ describe('Utils', function() {
368368
res.should.deep.equal([1, 2, 3]);
369369
});
370370

371+
it('should sort a simple array with multi-digit values', function() {
372+
const res = Utils.sortAsc([30, 1, 200, 2]);
373+
res.should.deep.equal([1, 2, 30, 200]);
374+
});
375+
371376
it('should sort a simple array with undefined values', function() {
372377
const res = Utils.sortAsc([3, undefined, 1, 2, '\uFFFE']);
373378
res.should.deep.equal([1, 2, 3, '\uFFFE', undefined]); // undefined should be in last position

0 commit comments

Comments
 (0)