From 1fd045904e94d68878b3a5f748bf20f7c61a1cf7 Mon Sep 17 00:00:00 2001
From: ilya-g <ilya.gorbunov@jetbrains.com>
Date: Fri, 17 Feb 2023 16:42:28 +0100
Subject: Consistent alphabetical order of element groups in index and
 navigation (#2861)

* Sort groups of divergent elements by their key first ignoring case, then preserving it

* Add tests for sorting groups and navigation
---
 .../base/src/main/kotlin/renderers/html/NavigationDataProvider.kt | 8 ++++++--
 .../main/kotlin/translators/documentables/DefaultPageCreator.kt   | 6 +++++-
 plugins/base/src/main/kotlin/utils/alphabeticalOrder.kt           | 7 +++++++
 3 files changed, 18 insertions(+), 3 deletions(-)
 create mode 100644 plugins/base/src/main/kotlin/utils/alphabeticalOrder.kt

(limited to 'plugins/base/src/main')

diff --git a/plugins/base/src/main/kotlin/renderers/html/NavigationDataProvider.kt b/plugins/base/src/main/kotlin/renderers/html/NavigationDataProvider.kt
index ecce70e8..4dae21c8 100644
--- a/plugins/base/src/main/kotlin/renderers/html/NavigationDataProvider.kt
+++ b/plugins/base/src/main/kotlin/renderers/html/NavigationDataProvider.kt
@@ -6,6 +6,7 @@ import org.jetbrains.dokka.base.transformers.documentables.isDeprecated
 import org.jetbrains.dokka.base.transformers.documentables.isException
 import org.jetbrains.dokka.base.translators.documentables.DocumentableLanguage
 import org.jetbrains.dokka.base.translators.documentables.documentableLanguage
+import org.jetbrains.dokka.base.utils.canonicalAlphabeticalOrder
 import org.jetbrains.dokka.model.*
 import org.jetbrains.dokka.pages.*
 
@@ -90,6 +91,9 @@ abstract class NavigationDataProvider {
         }
     }
 
+    private val navigationNodeOrder: Comparator<NavigationNode> =
+        compareBy(canonicalAlphabeticalOrder) { it.name }
+
     private fun ContentPage.navigableChildren() =
         if (this is ClasslikePage) {
             this.navigableChildren()
@@ -97,7 +101,7 @@ abstract class NavigationDataProvider {
             children
                 .filterIsInstance<ContentPage>()
                 .map { visit(it) }
-                .sortedBy { it.name.toLowerCase() }
+                .sortedWith(navigationNodeOrder)
         }
 
     private fun ClasslikePage.navigableChildren(): List<NavigationNode> {
@@ -111,7 +115,7 @@ abstract class NavigationDataProvider {
             // no sorting for enum entries, should be the same order as in source code
             navigableChildren
         } else {
-            navigableChildren.sortedBy { it.name.toLowerCase() }
+            navigableChildren.sortedWith(navigationNodeOrder)
         }
     }
 }
diff --git a/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt b/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt
index 25f3c450..6006af5b 100644
--- a/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt
+++ b/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt
@@ -9,6 +9,7 @@ import org.jetbrains.dokka.base.transformers.documentables.ClashingDriIdentifier
 import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter
 import org.jetbrains.dokka.base.transformers.pages.tags.CustomTagContentProvider
 import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder.DocumentableContentBuilder
+import org.jetbrains.dokka.base.utils.canonicalAlphabeticalOrder
 import org.jetbrains.dokka.links.Callable
 import org.jetbrains.dokka.links.DRI
 import org.jetbrains.dokka.model.*
@@ -508,6 +509,9 @@ open class DefaultPageCreator(
         }
     }
 
+    private val groupKeyComparator: Comparator<Map.Entry<String?, *>> =
+        compareBy(nullsFirst(canonicalAlphabeticalOrder)) { it.key }
+
     protected open fun DocumentableContentBuilder.divergentBlock(
         name: String,
         collection: Collection<Documentable>,
@@ -525,7 +529,7 @@ open class DefaultPageCreator(
                     .groupBy { it.name } // This groupBy should probably use LocationProvider
                     // This hacks displaying actual typealias signatures along classlike ones
                     .mapValues { if (it.value.any { it is DClasslike }) it.value.filter { it !is DTypeAlias } else it.value }
-                    .entries.sortedBy { it.key }
+                    .entries.sortedWith(groupKeyComparator)
                     .forEach { (elementName, elements) -> // This groupBy should probably use LocationProvider
                         val sortedElements = sortDivergentElementsDeterministically(elements)
                         row(
diff --git a/plugins/base/src/main/kotlin/utils/alphabeticalOrder.kt b/plugins/base/src/main/kotlin/utils/alphabeticalOrder.kt
new file mode 100644
index 00000000..68b9cde8
--- /dev/null
+++ b/plugins/base/src/main/kotlin/utils/alphabeticalOrder.kt
@@ -0,0 +1,7 @@
+package org.jetbrains.dokka.base.utils
+
+
+/**
+ * Canonical alphabetical order to sort named elements
+ */
+internal val canonicalAlphabeticalOrder: Comparator<in String> = String.CASE_INSENSITIVE_ORDER.thenBy { it }
\ No newline at end of file
-- 
cgit