11<script setup lang="ts">
22import { setResponseHeader } from ' h3'
3+ import { parsePackageParam } from ' #shared/utils/parse-package-param'
34
45definePageMeta ({
56 name: ' docs' ,
@@ -13,24 +14,19 @@ const router = useRouter()
1314const { t } = useI18n ()
1415
1516const parsedRoute = computed (() => {
16- const segments = route .params .path ?.filter (Boolean )
17- const vIndex = segments .indexOf (' v' )
18-
19- if (vIndex === - 1 || vIndex >= segments .length - 1 ) {
20- return {
21- packageName: segments .join (' /' ),
22- version: null as string | null ,
23- }
24- }
17+ const rawPath = route .params .path ?.filter (Boolean ).join (' /' ) ?? ' '
18+ const { packageName, version, rest } = parsePackageParam (rawPath )
2519
2620 return {
27- packageName: segments .slice (0 , vIndex ).join (' /' ),
28- version: segments .slice (vIndex + 1 ).join (' /' ),
21+ packageName ,
22+ version: version ?? null ,
23+ entrypoint: rest .length > 0 ? rest .join (' /' ) : null ,
2924 }
3025})
3126
3227const packageName = computed (() => parsedRoute .value .packageName )
3328const requestedVersion = computed (() => parsedRoute .value .version )
29+ const entrypoint = computed (() => parsedRoute .value .entrypoint )
3430
3531// Validate package name on server-side for early error detection
3632if (import .meta .server && packageName .value ) {
@@ -48,12 +44,8 @@ if (import.meta.server && !requestedVersion.value && packageName.value) {
4844 const version = await fetchLatestVersion (packageName .value )
4945 if (version ) {
5046 setResponseHeader (useRequestEvent ()! , ' Cache-Control' , ' no-cache' )
51- const pathSegments = [... packageName .value .split (' /' ), ' v' , version ]
5247 app .runWithContext (() =>
53- navigateTo (
54- { name: ' docs' , params: { path: pathSegments as [string , ... string []] } },
55- { redirectCode: 302 },
56- ),
48+ navigateTo (docsRoute (packageName .value , version ), { redirectCode: 302 }),
5749 )
5850 }
5951}
6254 [requestedVersion , latestVersion , packageName ],
6355 ([version , latest , name ]) => {
6456 if (! version && latest && name ) {
65- const pathSegments = [... name .split (' /' ), ' v' , latest ]
66- router .replace ({ name: ' docs' , params: { path: pathSegments as [string , ... string []] } })
57+ router .replace (docsRoute (name , latest ))
6758 }
6859 },
6960 { immediate: true },
@@ -90,7 +81,8 @@ useCommandPalettePackageCommands(commandPalettePackageContext)
9081
9182const docsUrl = computed (() => {
9283 if (! packageName .value || ! resolvedVersion .value ) return null
93- return ` /api/registry/docs/${packageName .value }/v/${resolvedVersion .value } `
84+ const base = ` /api/registry/docs/${packageName .value }/v/${resolvedVersion .value } `
85+ return entrypoint .value ? ` ${base }/${entrypoint .value } ` : base
9486})
9587
9688const shouldFetch = computed (() => !! docsUrl .value )
@@ -119,9 +111,10 @@ const latestVersionDetailed = computed(() => {
119111 return pkg .value .versions [latestTag ] ?? null
120112})
121113
122- const versionUrlPattern = computed (
123- () => ` /package-docs/${pkg .value ?.name || packageName .value }/v/{version} ` ,
124- )
114+ const versionUrlPattern = computed (() => {
115+ const base = ` /package-docs/${pkg .value ?.name || packageName .value }/v/{version} `
116+ return entrypoint .value && entrypoint .value !== ' .' ? ` ${base }/${entrypoint .value } ` : base
117+ })
125118
126119useCommandPaletteVersionCommands (commandPalettePackageContext , versionUrlPattern )
127120
@@ -171,6 +164,39 @@ const stickyStyle = computed(() => {
171164 ' --combined-header-height' : ` ${56 + (packageHeaderHeight .value || 44 )}px ` ,
172165 }
173166})
167+
168+ // Multi-entrypoint support
169+ const entrypoints = computed (() => docsData .value ?.entrypoints ?? null )
170+ const hasRootEntrypoint = computed (() => entrypoints .value ?.includes (' .' ) ?? false )
171+ const currentEntrypoint = computed (
172+ () => docsData .value ?.entrypoint ?? entrypoint .value ?? (hasRootEntrypoint .value ? ' .' : ' ' ),
173+ )
174+
175+ // Redirect to first entrypoint for multi-entrypoint packages
176+ watch (docsData , data => {
177+ if (
178+ data ?.entrypoints ?.length &&
179+ ! data .entrypoints .includes (' .' ) &&
180+ ! entrypoint .value &&
181+ resolvedVersion .value
182+ ) {
183+ const firstEntrypoint = data .entrypoints [0 ]!
184+ router .replace (docsRoute (packageName .value , resolvedVersion .value , firstEntrypoint ))
185+ }
186+ })
187+
188+ useCommandPaletteEntrypointCommands (
189+ computed (() => {
190+ const packageContext = commandPalettePackageContext .value
191+ const allEntrypoints = entrypoints .value
192+ if (! packageContext || ! allEntrypoints ?.length || allEntrypoints .length < 2 ) return null
193+ return {
194+ packageContext ,
195+ entrypoints: allEntrypoints ,
196+ currentEntrypoint: currentEntrypoint .value || null ,
197+ }
198+ }),
199+ )
174200 </script >
175201
176202<template >
@@ -184,6 +210,19 @@ const stickyStyle = computed(() => {
184210 page =" docs"
185211 />
186212
213+ <nav
214+ v-if =" entrypoints?.length && currentEntrypoint && resolvedVersion"
215+ :aria-label =" $t('package.docs.entrypoints')"
216+ class =" container py-2 border-b border-border"
217+ >
218+ <EntrypointSelector
219+ :package-name =" packageName"
220+ :version =" resolvedVersion"
221+ :current-entrypoint =" currentEntrypoint"
222+ :entrypoints =" entrypoints"
223+ />
224+ </nav >
225+
187226 <div class =" flex" dir =" ltr" >
188227 <!-- Sidebar TOC -->
189228 <aside
0 commit comments