Skip to content

Conversation

@lupas
Copy link

@lupas lupas commented Oct 11, 2025

Closes: #688

This pull request introduces a deterministic and locale-independent path sorting mechanism for route/path ordering.

The main goal is to fix bug #688 that resulted in a randomly sorted d.ts. file after almost every dev server start, that needed to either be committed or discarded.

The MR goes a bit beyond, ensure consistent sorting of routes, files, and views, regardless of locale or Unicode normalization differences. This is achieved by implementing a new comparePaths function and updating relevant parts of the codebase to use it. Comprehensive tests have also been added to verify the new sorting logic, including edge cases involving Unicode and dynamic segments.

Path sorting improvements:

  • Added a new comparePaths function in src/core/pathSorting.ts that sorts paths deterministically using fixed English collation, numeric-aware ordering, and Unicode normalization (NFC). This ensures index.vue is always first, files precede folders, and dynamic segments are handled consistently.
  • Updated the TreeNode.compare method in src/core/tree.ts to use the new comparePaths function for consistent node ordering.
  • Changed the route file info map generation in src/codegen/generateRouteFileInfoMap.ts to sort routes using comparePaths, ensuring stable output in generated code. [1] [2] [3]

Testing and validation:

  • Added a comprehensive test suite in src/core/pathSorting.spec.ts to verify the new sorting logic, covering REST-like routes, files vs. folders, index.vue prioritization, dynamic segments, numeric ordering, hierarchical grouping, and Unicode normalization.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 11, 2025

Walkthrough

Adds deterministic, NFC-normalizing path sorting utilities (comparePaths, sortPaths), integrates comparePaths into tree ordering and route-file-info generation, and introduces comprehensive tests for path sorting. No breaking public API changes beyond the new exports.

Changes

Cohort / File(s) Summary
Path sorting implementation
src/core/pathSorting.ts
New module: NFC normalization and fixed-English Intl.Collator; exports comparePaths(a,b) and sortPaths(paths) with segment-wise comparison, index.vue precedence, and file-vs-folder ordering.
Sorting tests
src/core/pathSorting.spec.ts
New test suite validating hierarchical ordering, parent-before-child, index.vue precedence, dynamic segments, numeric-aware ordering, grouping rules, and Unicode NFC normalization; includes snapshot formatter helper.
Tree integration
src/core/tree.ts
Replaced localeCompare usage in TreeNode.compare with imported comparePaths.
Codegen integration
src/codegen/generateRouteFileInfoMap.ts
Uses comparePaths to sort per-file routes before emitting the route-file-info map; mapping logic adjusted to compute sorted arrays prior to stringification.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • posva

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning The modification to TreeNode.compare in src/core/tree.ts is not referenced in issue #688 and does not impact the generated typed-router.d.ts order, making it unrelated to the PR’s stated goals. Remove or relocate the change to TreeNode.compare into a separate PR to keep this change focused solely on fixing the typed-router.d.ts sorting issue.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The title clearly identifies the main change as fixing the non-deterministic sort order in the generated typed-router.d.ts, directly reflecting the PR’s intent to introduce deterministic sorting.
Linked Issues Check ✅ Passed The PR introduces a stable, locale-independent sortPaths/comparePaths implementation, integrates it into generateRouteFileInfoMap to ensure consistent ordering of route entries, and adds tests covering all relevant sorting scenarios, fully addressing issue #688’s requirement for deterministic _RouteFileInfoMap output.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@lupas
Copy link
Author

lupas commented Oct 11, 2025

Additional Thoughts

1. Do sorting for routes also directly in tree.ts?

I could not find a smooth solution to sort routes already in tree.ts without messing up the deepChildren logic;
I am sure there might be a way.

I assume there are also performance considerations at play, so I count on you deciding where to put it for proper sorting.

2. Benchmark

I see you did prefer localeCompare over collator in tree.ts.
Decided on purpose to use collator for the sorting in pathSorting.ts after running two benchmarks locally.

Feel free to change back to localCompare if preferred. If so I would suggest to add the following:

    const c = x.localeCompare(y, 'en', {
      usage: 'sort',
      sensitivity: 'variant',
      numeric: true,
      caseFirst: 'lower',
    })

Without Collator

Dataset size: 300,000

sort (USE_COLLATOR=false) 10035.4 ms
sort (USE_COLLATOR=false) 9837.0 ms

With Collator

Dataset size: 300,000

sort (USE_COLLATOR=true) 2022.8 ms
sort (USE_COLLATOR=true) 2008.1 ms

@lupas
Copy link
Author

lupas commented Oct 11, 2025

@coderabbitai generate docstrings

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 11, 2025

✅ Actions performed

Initiated docstring generation; will generate only if new commits exist.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 11, 2025

Note

Docstrings generation - SUCCESS
Generated docstrings for this pull request at #734

coderabbitai bot added a commit that referenced this pull request Oct 11, 2025
Docstrings generation was requested by @lupas.

* #733 (comment)

The following files were modified:

* `src/codegen/generateRouteFileInfoMap.ts`
* `src/core/sortDts.ts`
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 104a7b3 and 3d6b337.

📒 Files selected for processing (2)
  • src/core/sortDts.ts (1 hunks)
  • src/core/tree.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/core/tree.ts (1)
src/core/sortDts.ts (1)
  • comparePaths (30-59)
🔇 Additional comments (6)
src/core/tree.ts (1)

170-172: LGTM!

Correctly delegates to the deterministic comparePaths function.

src/core/sortDts.ts (5)

1-15: LGTM!

Clear documentation of purpose, rules, and normalization strategy.


17-23: LGTM!

Collator configuration is appropriate for deterministic, locale-independent sorting with proper numeric handling.


25-27: LGTM!

Proper normalization and segmentation logic.


61-62: LGTM!

Clean helper that avoids mutation.


49-51: File detection logic OK
Routes directory contains only .vue files, so the current file-vs-folder check is safe. Revisit if other route file types are added.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3d6b337 and 73619d3.

📒 Files selected for processing (3)
  • src/core/pathSorting.spec.ts (1 hunks)
  • src/core/pathSorting.ts (1 hunks)
  • src/core/tree.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/core/tree.ts
🧰 Additional context used
🧬 Code graph analysis (1)
src/core/pathSorting.spec.ts (1)
src/core/pathSorting.ts (2)
  • comparePaths (30-59)
  • sortPaths (62-62)
🔇 Additional comments (3)
src/core/pathSorting.ts (2)

17-23: LGTM!

The fixed English collator with numeric and case-first options ensures deterministic, locale-independent sorting.


61-62: LGTM!

Correctly creates a shallow copy before sorting to avoid mutating the input array.

src/core/pathSorting.spec.ts (1)

1-160: LGTM!

Comprehensive test coverage validates all sorting rules: hierarchical ordering, index.vue precedence, file-before-folder logic, numeric sorting, dynamic segments, and Unicode normalization edge cases.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/codegen/generateRouteFileInfoMap.ts (1)

42-54: Consider explicitly sorting Map entries for robustness.

While the Map insertion order may be deterministic if getChildrenSorted() provides stable ordering (as noted in the AI summary), explicitly sorting entries by file key would guarantee determinism independent of tree traversal order.

Apply this diff to sort Map entries by file key:

   const code = Array.from(routesInfo.entries())
+    .sort(([fileA], [fileB]) => comparePaths(fileA, fileB))
     .map(([file, { routes, views }]) => {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 73619d3 and f90200a.

📒 Files selected for processing (1)
  • src/codegen/generateRouteFileInfoMap.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/codegen/generateRouteFileInfoMap.ts (2)
src/core/pathSorting.ts (1)
  • comparePaths (30-59)
src/utils/index.ts (2)
  • formatMultilineUnion (51-55)
  • stringToStringType (67-69)
🔇 Additional comments (1)
src/codegen/generateRouteFileInfoMap.ts (1)

4-4: Import looks good.

The comparePaths import is necessary for deterministic sorting.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/codegen/generateRouteFileInfoMap.ts (1)

43-51: Views are not sorted with comparePaths.

Views remain unsorted, undermining deterministic output. This is the same concern from the previous review.

Apply this diff to sort views:

   .map(([file, { routes, views }]) => {
     const routesSorted = [...routes].sort(comparePaths)
+    const viewsSorted = [...new Set(views)].sort(comparePaths)
     return `
   '${file}': {
     routes:
       ${formatMultilineUnion(routesSorted.map(stringToStringType), 6)}
     views:
-      ${formatMultilineUnion(views.map(stringToStringType), 6)}
+      ${formatMultilineUnion(viewsSorted.map(stringToStringType), 6)}
   }`
   })
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f90200a and 45889dd.

📒 Files selected for processing (1)
  • src/codegen/generateRouteFileInfoMap.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/codegen/generateRouteFileInfoMap.ts (2)
src/core/pathSorting.ts (1)
  • comparePaths (30-59)
src/utils/index.ts (2)
  • formatMultilineUnion (51-55)
  • stringToStringType (67-69)
🔇 Additional comments (2)
src/codegen/generateRouteFileInfoMap.ts (2)

4-4: LGTM!

Import is correct for the deterministic sorting implementation.


43-48: LGTM!

Routes are correctly sorted with comparePaths for deterministic output.

@posva
Copy link
Owner

posva commented Oct 12, 2025

Thanks but this was actually already fixed at #698

@posva posva closed this Oct 12, 2025
@lupas
Copy link
Author

lupas commented Oct 12, 2025

Even better! <:o) Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants