From 1d09c40b12d68ea274859d5b6a53c8b31b5a0b2c Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 25 Mar 2026 13:20:20 +0000 Subject: [PATCH 1/4] fix: do not strip package name from description --- app/pages/package/[[org]]/[name].vue | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/pages/package/[[org]]/[name].vue b/app/pages/package/[[org]]/[name].vue index babd2bec69..427afbef43 100644 --- a/app/pages/package/[[org]]/[name].vue +++ b/app/pages/package/[[org]]/[name].vue @@ -256,8 +256,7 @@ const versionSecurityMetadata = computed(() => { // Process package description const pkgDescription = useMarkdown(() => ({ - text: pkg.value?.description ?? '', - packageName: pkg.value?.name, + text: pkg.value?.description ?? '' })) // Fetch dependency analysis (lazy, client-side) From 14bcc14d4123d3fa9b8d4d3a68632229af8796bd Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 25 Mar 2026 13:22:46 +0000 Subject: [PATCH 2/4] format --- app/pages/package/[[org]]/[name].vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/pages/package/[[org]]/[name].vue b/app/pages/package/[[org]]/[name].vue index 427afbef43..4bc4d85bca 100644 --- a/app/pages/package/[[org]]/[name].vue +++ b/app/pages/package/[[org]]/[name].vue @@ -256,7 +256,7 @@ const versionSecurityMetadata = computed(() => { // Process package description const pkgDescription = useMarkdown(() => ({ - text: pkg.value?.description ?? '' + text: pkg.value?.description ?? '', })) // Fetch dependency analysis (lazy, client-side) From 201aa9bd818d9e1f52f870c764d7200639d0add2 Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 25 Mar 2026 17:28:59 +0000 Subject: [PATCH 3/4] wip --- app/components/Package/Card.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/app/components/Package/Card.vue b/app/components/Package/Card.vue index bdb6441e08..9887418b8e 100644 --- a/app/components/Package/Card.vue +++ b/app/components/Package/Card.vue @@ -37,7 +37,6 @@ const isExactMatch = computed(() => { const pkgDescription = useMarkdown(() => ({ text: props.result.package.description ?? '', plain: true, - packageName: props.result.package.name, })) const numberFormatter = useNumberFormatter() From 0d19788cbc6d6ed19a1946c6a368388d628b6aaf Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 25 Mar 2026 17:30:11 +0000 Subject: [PATCH 4/4] fix --- app/composables/useMarkdown.ts | 20 +---- test/nuxt/composables/use-markdown.spec.ts | 89 ---------------------- 2 files changed, 3 insertions(+), 106 deletions(-) diff --git a/app/composables/useMarkdown.ts b/app/composables/useMarkdown.ts index cd70bf6529..97355ecf59 100644 --- a/app/composables/useMarkdown.ts +++ b/app/composables/useMarkdown.ts @@ -4,8 +4,6 @@ interface UseMarkdownOptions { text: string /** When true, renders link text without the anchor tag (useful when inside another link) */ plain?: boolean - /** Package name to strip from the beginning of the description (if present) */ - packageName?: string } export function useMarkdown(options: MaybeRefOrGetter) { @@ -25,7 +23,7 @@ function stripMarkdownImages(text: string): string { } // Strip HTML tags and escape remaining HTML to prevent XSS -function stripAndEscapeHtml(text: string, packageName?: string): string { +function stripAndEscapeHtml(text: string): string { // First decode any HTML entities in the input let stripped = decodeHtmlEntities(text) @@ -45,18 +43,6 @@ function stripAndEscapeHtml(text: string, packageName?: string): string { (match, codeSpan: string | undefined) => codeSpan ?? '', ) - if (packageName) { - // Trim first to handle leading/trailing whitespace from stripped HTML - stripped = stripped.trim() - // Collapse multiple whitespace into single space - stripped = stripped.replace(/\s+/g, ' ') - // Escape special regex characters in package name - const escapedName = packageName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') - // Match package name at the start, optionally followed by: space, dash, colon, hyphen, or just space - const namePattern = new RegExp(`^${escapedName}\\s*[-:—]?\\s*`, 'i') - stripped = stripped.replace(namePattern, '').trim() - } - // Then escape any remaining HTML entities return stripped .replace(/&/g, '&') @@ -67,11 +53,11 @@ function stripAndEscapeHtml(text: string, packageName?: string): string { } // Parse simple inline markdown to HTML -function parseMarkdown({ text, packageName, plain }: UseMarkdownOptions): string { +function parseMarkdown({ text, plain }: UseMarkdownOptions): string { if (!text) return '' // First strip HTML tags and escape remaining HTML - let html = stripAndEscapeHtml(text, packageName) + let html = stripAndEscapeHtml(text) // Bold: **text** or __text__ html = html.replace(/\*\*(.+?)\*\*/g, '$1') diff --git a/test/nuxt/composables/use-markdown.spec.ts b/test/nuxt/composables/use-markdown.spec.ts index bf7abd02b0..7aa258e0df 100644 --- a/test/nuxt/composables/use-markdown.spec.ts +++ b/test/nuxt/composables/use-markdown.spec.ts @@ -196,95 +196,6 @@ describe('useMarkdown', () => { }) }) - describe('packageName prop', () => { - it('strips package name from the beginning of plain text', () => { - const processed = useMarkdown({ - text: 'my-package - A great library', - packageName: 'my-package', - }) - expect(processed.value).toBe('A great library') - }) - - it('strips package name with colon separator', () => { - const processed = useMarkdown({ - text: 'my-package: A great library', - packageName: 'my-package', - }) - expect(processed.value).toBe('A great library') - }) - - it('strips package name with em dash separator', () => { - const processed = useMarkdown({ - text: 'my-package — A great library', - packageName: 'my-package', - }) - expect(processed.value).toBe('A great library') - }) - - it('strips package name without separator', () => { - const processed = useMarkdown({ - text: 'my-package A great library', - packageName: 'my-package', - }) - expect(processed.value).toBe('A great library') - }) - - it('is case-insensitive', () => { - const processed = useMarkdown({ - text: 'MY-PACKAGE - A great library', - packageName: 'my-package', - }) - expect(processed.value).toBe('A great library') - }) - - it('does not strip package name from middle of text', () => { - const processed = useMarkdown({ - text: 'A great my-package library', - packageName: 'my-package', - }) - expect(processed.value).toBe('A great my-package library') - }) - - it('handles scoped package names', () => { - const processed = useMarkdown({ - text: '@org/my-package - A great library', - packageName: '@org/my-package', - }) - expect(processed.value).toBe('A great library') - }) - - it('handles package names with special regex characters', () => { - const processed = useMarkdown({ - text: 'pkg.name+test - A great library', - packageName: 'pkg.name+test', - }) - expect(processed.value).toBe('A great library') - }) - - it('strips package name from HTML-containing descriptions', () => { - const processed = useMarkdown({ - text: 'my-package - A great library', - packageName: 'my-package', - }) - expect(processed.value).toBe('A great library') - }) - - it('strips package name from descriptions with markdown images', () => { - const processed = useMarkdown({ - text: '![badge](https://badge.svg) my-package - A great library', - packageName: 'my-package', - }) - expect(processed.value).toBe('A great library') - }) - - it('does nothing when packageName is not provided', () => { - const processed = useMarkdown({ - text: 'my-package - A great library', - }) - expect(processed.value).toBe('my-package - A great library') - }) - }) - describe('HTML tag stripping', () => { it('strips simple HTML tags but keeps content', () => { const processed = useMarkdown({ text: 'bold text here' })