From cd010915ffc252e6ac64ac9f45a8dbaf7c14a6ef Mon Sep 17 00:00:00 2001 From: Codefoxdev Date: Tue, 24 Feb 2026 19:21:28 +0100 Subject: [PATCH 1/3] feat: parse search query to extact essential package info --- app/pages/search.vue | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/app/pages/search.vue b/app/pages/search.vue index dcb285382..5dd929a05 100644 --- a/app/pages/search.vue +++ b/app/pages/search.vue @@ -33,6 +33,24 @@ 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 + // 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 } +}) + // Track if page just loaded (for hiding "Searching..." during view transition) const hasInteracted = shallowRef(false) onMounted(() => { From c32e8457fa05a8264f71985fe111db2e43e656ad Mon Sep 17 00:00:00 2001 From: Codefoxdev Date: Tue, 24 Feb 2026 19:27:23 +0100 Subject: [PATCH 2/3] refactor: update the relevant components to use the new stripped query --- app/pages/search.vue | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/app/pages/search.vue b/app/pages/search.vue index 5dd929a05..dba340eba 100644 --- a/app/pages/search.vue +++ b/app/pages/search.vue @@ -51,6 +51,9 @@ const parsedQuery = computed(() => { 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(() => { @@ -210,7 +213,7 @@ const { suggestions: validatedSuggestions, packageAvailability, } = useSearch( - query, + strippedQuery, searchProvider, () => ({ size: requestedSize.value, @@ -305,14 +308,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>({}) @@ -685,7 +680,7 @@ defineOgImageComponent('Default', {

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

From 123a992644d150b00ab5c46a6f7a396ecb410ec1 Mon Sep 17 00:00:00 2001 From: Codefoxdev Date: Tue, 24 Feb 2026 20:06:30 +0100 Subject: [PATCH 3/3] refactor: update regex query to use named capture groups --- app/pages/search.vue | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/pages/search.vue b/app/pages/search.vue index dba340eba..a31a85174 100644 --- a/app/pages/search.vue +++ b/app/pages/search.vue @@ -39,10 +39,12 @@ 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(/^(?:@([^/]+)\/)?([^/@ ]+)(?:@([^ ]*))?(.*)/) + const match = q.match( + /^(?:@(?[^/]+)\/)?(?[^/@ ]+)(?:@(?[^ ]*))?(?.*)/, + ) if (!match) return { scope: null, name: q, version: null, strippedQuery: q } - const [, scope, specifier, version, trailing] = match + 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 ?? '')