Skip to content

Commit 2de6a60

Browse files
committed
refactor: accept versioned route builder in cmd palette
The placeholder shape made callers that already had named-route helpers resolve routes to strings and then patch encoded placeholders back into place. That was brittle, especially for routes where Vue Router encodes params differently from the URL shape users see. We have a documented guideline that internal navigation should use route object syntax with named routes instead of strings. This commit allows callers to respect that guideline.
1 parent 69351cf commit 2de6a60

6 files changed

Lines changed: 52 additions & 26 deletions

File tree

app/composables/useCommandPaletteVersionCommands.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
// @unocss-include
2-
import type { MaybeRefOrGetter } from 'vue'
2+
import type { MaybeRef, MaybeRefOrGetter } from 'vue'
3+
import type { RouteLocationRaw } from 'vue-router'
34
import type {
45
CommandPaletteCommand,
56
CommandPaletteContextCommandInput,
67
CommandPalettePackageContext,
78
} from '~/types/command-palette'
89
import { compare, satisfies, validRange } from 'semver'
910

11+
type CommandPaletteVersionRoute = (version: string) => RouteLocationRaw
12+
1013
function getSortedVersions(context: CommandPalettePackageContext) {
1114
return [...context.versions].sort((a, b) => {
1215
if (a === context.resolvedVersion) return -1
@@ -19,7 +22,7 @@ function createVersionCommands(
1922
context: CommandPalettePackageContext,
2023
t: ReturnType<typeof useI18n>['t'],
2124
versions = getSortedVersions(context),
22-
urlPattern?: string | null,
25+
routeForVersion?: CommandPaletteVersionRoute | null,
2326
): CommandPaletteCommand[] {
2427
return versions.map(version => ({
2528
id: `version:${version}`,
@@ -28,13 +31,13 @@ function createVersionCommands(
2831
keywords: [context.packageName, version, t('command_palette.groups.versions')],
2932
iconClass: 'i-lucide:tag',
3033
active: version === context.resolvedVersion,
31-
to: urlPattern?.replace('{version}', version) ?? packageRoute(context.packageName, version),
34+
to: routeForVersion?.(version) ?? packageRoute(context.packageName, version),
3235
}))
3336
}
3437

3538
export function useCommandPaletteVersionCommands(
3639
context: MaybeRefOrGetter<CommandPalettePackageContext | null>,
37-
urlPattern?: MaybeRefOrGetter<string | null | undefined>,
40+
routeForVersion?: MaybeRef<CommandPaletteVersionRoute | null | undefined>,
3841
) {
3942
const { t } = useI18n()
4043

@@ -43,7 +46,7 @@ export function useCommandPaletteVersionCommands(
4346
const resolvedContext = toValue(context)
4447
if (!resolvedContext?.resolvedVersion) return []
4548

46-
return createVersionCommands(resolvedContext, t, undefined, toValue(urlPattern))
49+
return createVersionCommands(resolvedContext, t, undefined, unref(routeForVersion))
4750
}),
4851
)
4952

@@ -58,6 +61,6 @@ export function useCommandPaletteVersionCommands(
5861
satisfies(version, semverRange, { includePrerelease: true }),
5962
)
6063

61-
return createVersionCommands(resolvedContext, t, matchingVersions, toValue(urlPattern))
64+
return createVersionCommands(resolvedContext, t, matchingVersions, unref(routeForVersion))
6265
})
6366
}

app/pages/diff/[[org]]/[packageName]/v/[versionRange].vue

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -116,19 +116,19 @@ const latestVersionDetailed = computed(() => {
116116
return pkg.value.versions[latestTag] ?? null
117117
})
118118
119-
const normalizeRoutePath = (routeLocation: RouteLocationRaw) => {
120-
const resolvedHref = router.resolve(routeLocation).href
121-
return resolvedHref.replace(/%7B/g, '{').replace(/%7D/g, '}')
119+
function diffVersionUrlPattern(from: string, to: string) {
120+
const { org, packageName: name } = route.params
121+
return `/diff/${org ? `${org}/` : ''}${name}/v/${from}...${to}`
122122
}
123123
124-
const fromVersionUrlPattern = computed(() => {
125-
return normalizeRoutePath(diffRoute(packageName.value, '{version}', toVersion.value))
126-
})
127-
const toVersionUrlPattern = computed(() => {
128-
return normalizeRoutePath(diffRoute(packageName.value, fromVersion.value, '{version}'))
129-
})
124+
const fromVersionUrlPattern = computed(() => diffVersionUrlPattern('{version}', toVersion.value))
125+
const toVersionUrlPattern = computed(() => diffVersionUrlPattern(fromVersion.value, '{version}'))
126+
127+
function fromVersionRoute(version: string): RouteLocationRaw {
128+
return diffRoute(packageName.value, version, toVersion.value)
129+
}
130130
131-
useCommandPaletteVersionCommands(commandPalettePackageContext, fromVersionUrlPattern)
131+
useCommandPaletteVersionCommands(commandPalettePackageContext, fromVersionRoute)
132132
133133
useSeoMeta({
134134
title: () => {

app/pages/package-code/[[org]]/[packageName]/v/[version]/[...filePath].vue

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<script setup lang="ts">
2+
import type { RouteLocationRaw } from 'vue-router'
23
import type { CommandPaletteContextCommandInput } from '~/types/command-palette'
34
45
// Maximum file size we'll try to load (500KB) - must match server
@@ -86,7 +87,16 @@ const versionUrlPattern = computed(() =>
8687
}),
8788
)
8889
89-
useCommandPaletteVersionCommands(commandPalettePackageContext, versionUrlPattern)
90+
function codeVersionRoute(nextVersion: string): RouteLocationRaw {
91+
return getCodeUrl({
92+
org: route.params.org,
93+
packageName: route.params.packageName,
94+
version: nextVersion,
95+
filePath: filePath.value,
96+
})
97+
}
98+
99+
useCommandPaletteVersionCommands(commandPalettePackageContext, codeVersionRoute)
90100
91101
// Fetch file tree
92102
const { data: fileTree, status: treeStatus } = useFetch<PackageFileTreeResponse>(

app/pages/package-docs/[...path].vue

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<script setup lang="ts">
2+
import type { RouteLocationRaw } from 'vue-router'
23
import { setResponseHeader } from 'h3'
34
45
definePageMeta({
@@ -123,7 +124,19 @@ const versionUrlPattern = computed(
123124
() => `/package-docs/${pkg.value?.name || packageName.value}/v/{version}`,
124125
)
125126
126-
useCommandPaletteVersionCommands(commandPalettePackageContext, versionUrlPattern)
127+
function docsVersionRoute(version: string): RouteLocationRaw {
128+
const name = pkg.value?.name || packageName.value
129+
const [firstSegment = name, ...remainingSegments] = name.split('/')
130+
131+
return {
132+
name: 'docs',
133+
params: {
134+
path: [firstSegment, ...remainingSegments, 'v', version],
135+
},
136+
}
137+
}
138+
139+
useCommandPaletteVersionCommands(commandPalettePackageContext, docsVersionRoute)
127140
128141
const pageTitle = computed(() => {
129142
if (!packageName.value) return t('package.docs.page_title')

app/pages/package/[[org]]/[name].vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,9 @@ const versionUrlPattern = computed(
487487
() => `/package/${pkg.value?.name || packageName.value}/v/{version}`,
488488
)
489489
490-
useCommandPaletteVersionCommands(commandPalettePackageContext, versionUrlPattern)
490+
useCommandPaletteVersionCommands(commandPalettePackageContext, version =>
491+
packageRoute(packageName.value, version),
492+
)
491493
492494
const dependencyCount = computed(() => getDependencyCount(displayVersion.value))
493495

test/nuxt/composables/use-command-palette-commands.spec.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { afterEach, describe, expect, it, vi } from 'vitest'
22
import { computed, defineComponent, h, ref, watchEffect, type Ref } from 'vue'
3+
import type { RouteLocationRaw } from 'vue-router'
34
import { mockNuxtImport, mountSuspended } from '@nuxt/test-utils/runtime'
45
import { downloadPackageTarball } from '~/utils/package-download'
56
import type {
@@ -49,7 +50,7 @@ async function captureCommandPalette(options?: {
4950
npmUser?: string | null
5051
atprotoHandle?: string | null
5152
packageContext?: CommandPalettePackageContext | null
52-
versionUrlPattern?: string
53+
versionRoute?: (version: string) => RouteLocationRaw
5354
contextCommands?: CommandPaletteContextCommandInput[]
5455
}) {
5556
const groupedCommands = ref<CommandPaletteCommandGroup[]>([]) as Ref<CommandPaletteCommandGroup[]>
@@ -76,10 +77,7 @@ async function captureCommandPalette(options?: {
7677
if (options?.packageContext) {
7778
setPackageContext(options.packageContext)
7879
useCommandPalettePackageCommands(() => options.packageContext ?? null)
79-
useCommandPaletteVersionCommands(
80-
() => options.packageContext ?? null,
81-
() => options.versionUrlPattern,
82-
)
80+
useCommandPaletteVersionCommands(() => options.packageContext ?? null, options.versionRoute)
8381
} else {
8482
clearPackageContext()
8583
}
@@ -345,7 +343,7 @@ describe('useCommandPaletteCommands', () => {
345343
wrapper.unmount()
346344
})
347345

348-
it('keeps version navigation on the current surface when a version URL pattern is provided', async () => {
346+
it('keeps version navigation on the current surface when a version route builder is provided', async () => {
349347
const { wrapper, flatCommands, routePath } = await captureCommandPalette({
350348
route: '/package-code/vue/v/3.4.2/src/index.ts',
351349
packageContext: {
@@ -354,7 +352,7 @@ describe('useCommandPaletteCommands', () => {
354352
latestVersion: '4.0.0',
355353
versions: ['4.0.0', '3.5.0', '3.4.2'],
356354
},
357-
versionUrlPattern: '/package-code/vue/v/{version}/src/index.ts',
355+
versionRoute: version => `/package-code/vue/v/${version}/src/index.ts`,
358356
})
359357

360358
const versionCommand = flatCommands.value.find(command => command.id === 'version:3.5.0')

0 commit comments

Comments
 (0)