diff --git a/app/pages/search.vue b/app/pages/search.vue index dcb285382..a31a85174 100644 --- a/app/pages/search.vue +++ b/app/pages/search.vue @@ -33,6 +33,29 @@ const updateUrlPage = debounce((page: number) => { const { model: searchQuery, provider: searchProvider } = useGlobalSearch() const query = computed(() => searchQuery.value) +// Parses the raw search query to extract package info, such as scope, name, version. +// Uses this info to provide a strippedQuery (the query, but without version info) that is used for searching. +const parsedQuery = computed(() => { + const q = query.value.trim() + // Regex matches a (un)scoped package and optionally extracts versioning info using the following syntax: @scope/specifier@version + // It makes use of 4 capture groups to extract this info. + const match = q.match( + /^(?:@(?[^/]+)\/)?(?[^/@ ]+)(?:@(?[^ ]*))?(?.*)/, + ) + if (!match) return { scope: null, name: q, version: null, strippedQuery: q } + + const { scope, specifier, version, trailing } = match.groups ?? {} + // Reconstruct the query without the version info, essentially stripping the version data: + // anything directly after the @ for the version specifier is stripped. + const name = scope ? `@${scope}/${specifier}` : (specifier ?? '') + const strippedQuery = `${name} ${trailing ?? ''}`.trim() + + return { scope: scope ?? null, name: name, version: version || null, strippedQuery } +}) + +const packageScope = computed(() => parsedQuery.value.scope) +const strippedQuery = computed(() => parsedQuery.value.strippedQuery) + // Track if page just loaded (for hiding "Searching..." during view transition) const hasInteracted = shallowRef(false) onMounted(() => { @@ -192,7 +215,7 @@ const { suggestions: validatedSuggestions, packageAvailability, } = useSearch( - query, + strippedQuery, searchProvider, () => ({ size: requestedSize.value, @@ -287,14 +310,6 @@ const isValidPackageName = computed(() => isValidNewPackageName(query.value.trim // Get connector state const { isConnected, npmUser, listOrgUsers } = useConnector() -// Check if this is a scoped package and extract scope -const packageScope = computed(() => { - const q = query.value.trim() - if (!q.startsWith('@')) return null - const match = q.match(/^@([^/]+)\//) - return match ? match[1] : null -}) - // Track org membership for scoped packages const orgMembership = ref>({}) @@ -667,7 +682,7 @@ defineOgImageComponent('Default', {

- {{ $t('search.no_results', { query }) }} + {{ $t('search.no_results', { query: strippedQuery }) }}