Rocky_Mountain_Vending/.pnpm-store/v10/files/80/49ce38bdc534e809cbcb6877860fc4d14bc2a2ae82c29b3acef10cbc328b3f9d33e789568f33137b7bc04479343009192fab8527b2fafce681e4c76a1e3e20
DMleadgen 46d973904b
Initial commit: Rocky Mountain Vending website
Next.js website for Rocky Mountain Vending company featuring:
- Product catalog with Stripe integration
- Service areas and parts pages
- Admin dashboard with Clerk authentication
- SEO optimized pages with JSON-LD structured data

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 16:22:15 -07:00

1 line
No EOL
12 KiB
Text

{"version":3,"sources":["../../../../../src/shared/lib/router/utils/sortable-routes.ts"],"sourcesContent":["/**\n * A route that can be sorted by specificity.\n */\nexport type SortableRoute = {\n /**\n * The source page of the route. This represents the original page that's on\n * disk. For example, the `app/[lang]/[...rest]/page.tsx` would have a source\n * page of '/[lang]/[...rest]'.\n */\n readonly sourcePage: string\n\n /**\n * The page of the route. This represents the final rendered route. For\n * example, the `app/[lang]/[...rest]/page.tsx` that was rendered with a lang\n * value of `en` would have a page of '/en/[...rest]'.\n */\n readonly page: string\n}\n\n/**\n * Determines the specificity of a route segment for sorting purposes.\n *\n * In Next.js routing, more specific routes should match before less specific ones.\n * This function returns a numeric value where lower numbers indicate higher specificity.\n *\n * Specificity order (most to least specific):\n * 1. Static segments (e.g., \"about\", \"api\") - return 0\n * 2. Dynamic segments (e.g., \"[id]\", \"[slug]\") - return 1\n * 3. Catch-all segments (e.g., \"[...slug]\") - return 2\n * 4. Optional catch-all segments (e.g., \"[[...slug]]\") - return 3\n *\n * @param segment - A single path segment (e.g., \"api\", \"[id]\", \"[...slug]\")\n * @returns A numeric specificity value (0-3, where 0 is most specific)\n */\nexport function getSegmentSpecificity(segment: string): number {\n // Static segments are most specific - they match exactly one path\n if (!segment.includes('[')) {\n return 0\n }\n\n // Optional catch-all [[...param]] is least specific - matches zero or more segments\n if (segment.startsWith('[[...') && segment.endsWith(']]')) {\n return 3\n }\n\n // Catch-all [...param] is less specific - matches one or more segments\n if (segment.startsWith('[...') && segment.endsWith(']')) {\n return 2\n }\n\n // Regular dynamic [param] is more specific than catch-all - matches exactly one segment\n if (segment.startsWith('[') && segment.endsWith(']')) {\n return 1\n }\n\n // Default to static (fallback case)\n return 0\n}\n\n/**\n * Compares two route paths using a depth-first traversal approach.\n *\n * This function implements a deterministic comparison that sorts routes by specificity:\n * 1. More specific routes come first (fewer dynamic segments)\n * 2. Shorter routes are more specific than longer ones\n * 3. Routes with same specificity are sorted lexicographically\n *\n * The comparison is done segment by segment, left to right, similar to how\n * you would traverse a route tree in depth-first order.\n *\n * @param pathA - First route path to compare (e.g., \"/api/users/[id]\")\n * @param pathB - Second route path to compare (e.g., \"/api/[...slug]\")\n * @returns Negative if pathA is more specific, positive if pathB is more specific, 0 if equal\n */\nexport function compareRouteSegments(pathA: string, pathB: string): number {\n // Split paths into segments, removing empty strings from leading/trailing slashes\n const segmentsA = pathA.split('/').filter(Boolean)\n const segmentsB = pathB.split('/').filter(Boolean)\n\n // Compare segment by segment up to the length of the longer path\n const maxLength = Math.max(segmentsA.length, segmentsB.length)\n\n for (let i = 0; i < maxLength; i++) {\n const segA = segmentsA[i] || ''\n const segB = segmentsB[i] || ''\n\n // Handle length differences: shorter routes are MORE specific\n // Example: \"/api\" is more specific than \"/api/users\"\n if (!segA && segB) return -1 // pathA is shorter, so more specific\n if (segA && !segB) return 1 // pathB is shorter, so more specific\n if (!segA && !segB) return 0 // Both paths ended, they're equal\n\n // Compare segment specificity using our specificity scoring\n const specificityA = getSegmentSpecificity(segA)\n const specificityB = getSegmentSpecificity(segB)\n\n // Lower specificity number = more specific route\n // Example: \"api\" (0) vs \"[slug]\" (1) - \"api\" wins\n if (specificityA !== specificityB) {\n return specificityA - specificityB\n }\n\n // If segments have same specificity, compare lexicographically for determinism\n // Example: \"[id]\" vs \"[slug]\" - \"[id]\" comes first alphabetically\n if (segA !== segB) {\n return segA.localeCompare(segB)\n }\n\n // Segments are identical, continue to next segment\n }\n\n // All segments compared equally\n return 0\n}\n\n/**\n * Compares two complete routes for sorting purposes.\n *\n * Routes are compared with a two-tier priority system:\n * 1. Primary: Compare by source path specificity\n * 2. Secondary: If sources are equal, compare by page path specificity\n *\n * This ensures that routes are primarily organized by their source patterns,\n * with page-specific variations grouped together.\n *\n * @param a - First route to compare\n * @param b - Second route to compare\n * @returns Negative if route a should come first, positive if route b should come first, 0 if equal\n */\nfunction compareSortableRoutes(a: SortableRoute, b: SortableRoute): number {\n // First compare by source specificity - this is the primary sorting criterion\n // Source represents the original route pattern and takes precedence\n const sourceResult = compareRouteSegments(a.sourcePage, b.sourcePage)\n if (sourceResult !== 0) return sourceResult\n\n // If sources are identical, compare by page specificity as a tiebreaker\n // Page represents the final rendered route and provides secondary ordering\n return compareRouteSegments(a.page, b.page)\n}\n\n/**\n * Sorts an array of routes by specificity using a deterministic depth-first traversal approach.\n *\n * This function implements Next.js route matching priority where more specific routes\n * should be matched before less specific ones. The sorting is deterministic and stable,\n * meaning identical inputs will always produce identical outputs.\n *\n * Sorting criteria (in order of priority):\n * 1. Source path specificity (primary)\n * 2. Page path specificity (secondary)\n * 3. Lexicographic ordering (tertiary, for determinism)\n *\n * Examples of specificity order:\n * - \"/api/users\" (static) comes before \"/api/[slug]\" (dynamic)\n * - \"/api/[id]\" (dynamic) comes before \"/api/[...slug]\" (catch-all)\n * - \"/api/[...slug]\" (catch-all) comes before \"/api/[[...slug]]\" (optional catch-all)\n *\n * @param routes - Array of routes to sort\n * @returns New sorted array (does not mutate input)\n */\nexport function sortSortableRoutes(\n routes: readonly SortableRoute[]\n): readonly SortableRoute[] {\n // Because sort is always in-place, we need to create a shallow copy to avoid\n // mutating the input array.\n return [...routes].sort(compareSortableRoutes)\n}\n\n/**\n * Sorts an array of pages by specificity using a deterministic depth-first\n * traversal approach.\n *\n * @param pages - Array of pages to sort\n * @returns New sorted array (does not mutate input)\n */\nexport function sortPages(pages: readonly string[]): readonly string[] {\n // Because sort is always in-place, we need to create a shallow copy to avoid\n // mutating the input array.\n return [...pages].sort(compareRouteSegments)\n}\n\n/**\n * Sorts an array of objects by sourcePage and page using a deterministic\n * depth-first traversal approach.\n *\n * @param objects - Array of objects to sort\n * @param getter - Function to get the sourcePage and page from an object\n * @returns New sorted array (does not mutate input)\n */\nexport function sortSortableRouteObjects<T>(\n objects: readonly T[],\n getter: (object: T) => SortableRoute\n): readonly T[] {\n // Create a SortableRoute for each object.\n const routes: Array<SortableRoute & { object: T }> = []\n for (const object of objects) {\n const route = getter(object)\n routes.push({ ...route, object })\n }\n\n // In-place sort the SortableRoutes.\n routes.sort(compareSortableRoutes)\n\n // Map the sorted SortableRoutes back to the original objects.\n return routes.map(({ object }) => object)\n}\n\n/**\n * Sorts an array of objects by page using a deterministic depth-first traversal\n * approach.\n *\n * @param objects - Array of objects to sort\n * @param getter - Function to get the page from an object\n * @returns New sorted array (does not mutate input)\n */\nexport function sortPageObjects<T>(\n objects: readonly T[],\n getter: (object: T) => string\n): readonly T[] {\n const indexes: Record<string, number[]> = {}\n const pages: Set<string> = new Set()\n for (let i = 0; i < objects.length; i++) {\n const object = objects[i]\n const page = getter(object)\n indexes[page]?.push(i) || (indexes[page] = [i])\n pages.add(page)\n }\n\n // Sort the unique pages.\n const sortedPages = Array.from(pages).sort(compareRouteSegments)\n\n // Map the sorted pages back to the original objects.\n return sortedPages.reduce<T[]>((sortedObjects, page) => {\n // Add all objects for this page to the sorted array.\n for (const i of indexes[page]) {\n sortedObjects.push(objects[i])\n }\n\n // Return the sorted array.\n return sortedObjects\n }, [])\n}\n"],"names":["getSegmentSpecificity","segment","includes","startsWith","endsWith","compareRouteSegments","pathA","pathB","segmentsA","split","filter","Boolean","segmentsB","maxLength","Math","max","length","i","segA","segB","specificityA","specificityB","localeCompare","compareSortableRoutes","a","b","sourceResult","sourcePage","page","sortSortableRoutes","routes","sort","sortPages","pages","sortSortableRouteObjects","objects","getter","object","route","push","map","sortPageObjects","indexes","Set","add","sortedPages","Array","from","reduce","sortedObjects"],"mappings":"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","ignoreList":[0]}