From d515d295ce736e7096d555a30e2b6bb40e19c100 Mon Sep 17 00:00:00 2001 From: Adit Syed Afnan <111628226+S-A-Adit@users.noreply.github.com> Date: Thu, 8 Jan 2026 21:58:00 -0500 Subject: [PATCH] feat(editor): enhance string comparison handling in eval.ts (#14233) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactors the compareString function to safely handle null and undefined inputs and improves overall string comparison logic. This prevents incorrect sort behavior and ensures consistent ordering when comparing mixed or missing values, particularly in table view sorting scenarios. ## Summary by CodeRabbit * **Bug Fixes** * Improved string comparison used for sorting: empty values are consistently placed last, numeric parts sort numerically before non-numeric parts, and mixed-type and case variations are handled more predictably for stable, consistent ordering across data views. ✏️ Tip: You can customize this high-level summary in your review settings. --- .../affine/data-view/src/core/sort/eval.ts | 33 ++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/blocksuite/affine/data-view/src/core/sort/eval.ts b/blocksuite/affine/data-view/src/core/sort/eval.ts index 71507b6798..d3e277b74f 100644 --- a/blocksuite/affine/data-view/src/core/sort/eval.ts +++ b/blocksuite/affine/data-view/src/core/sort/eval.ts @@ -48,32 +48,41 @@ const compareList = ( return 0; }; const compareString = (a: unknown, b: unknown): CompareType => { - if (typeof a != 'string' || a === '') { - return Compare.GT; + const strA = String(a ?? ''); + const strB = String(b ?? ''); + + if (strA === '' && strB !== '') { + return Compare.GT; // Empty strings come last } - if (typeof b != 'string' || b === '') { - return Compare.LT; + if (strA !== '' && strB === '') { + return Compare.LT; // Empty strings come last } - const listA = a.split('.'); - const listB = b.split('.'); + if (strA === '' && strB === '') { + return 0; // Both empty, equal + } + + const listA = strA.split('.'); + const listB = strB.split('.'); return compareList(listA, listB, (a, b) => { - const lowA = a.toLowerCase(); - const lowB = b.toLowerCase(); + const lowA = String(a).toLowerCase(); // Ensure 'a' and 'b' from split are strings too + const lowB = String(b).toLowerCase(); + const numberA = Number.parseInt(lowA); const numberB = Number.parseInt(lowB); const aIsNaN = Number.isNaN(numberA); const bIsNaN = Number.isNaN(numberB); + if (aIsNaN && !bIsNaN) { - return 1; + return 1; // Non-numeric part comes after numeric part } if (!aIsNaN && bIsNaN) { - return -1; + return -1; // Numeric part comes before non-numeric part } if (!aIsNaN && !bIsNaN && numberA !== numberB) { - return numberA - numberB; + return numberA - numberB; // Numeric comparison for numeric parts } - return lowA.localeCompare(lowB); + return lowA.localeCompare(lowB); // Lexicographical comparison for string parts }); }; const compareNumber = (a: unknown, b: unknown) => {