Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion app/components/MarkdownText.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,21 @@ function stripAndEscapeHtml(text: string): string {
// First decode any HTML entities in the input
let stripped = decodeHtmlEntities(text)
// Check if original text has HTML tags or markdown images BEFORE stripping
// Only strip package name for these "badge-style" descriptions
const hasHtmlTags = /<\/?[a-z][^>]*>/i.test(stripped)
const hasMarkdownImages = /!\[[^\]]*\]\([^)]*\)/.test(stripped)
// Then strip markdown image badges
stripped = stripMarkdownImages(stripped)
// Then strip actual HTML tags (keep their text content)
// Only match tags that start with a letter or / (to avoid matching things like "a < b > c")
stripped = stripped.replace(/<\/?[a-z][^>]*>/gi, '')
if (props.packageName) {
// Only strip package name if original text had HTML tags or markdown images
// Normal descriptions like "Nuxt is a framework..." should keep the package name
if ((hasHtmlTags || hasMarkdownImages) && props.packageName) {
// Trim first to handle leading/trailing whitespace from stripped HTML
stripped = stripped.trim()
// Collapse multiple whitespace into single space
Expand Down
50 changes: 27 additions & 23 deletions test/nuxt/components/MarkdownText.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,91 +259,95 @@ describe('MarkdownText', () => {
})

describe('packageName prop', () => {
it('strips package name from the beginning of plain text', async () => {
// Package name stripping ONLY happens for descriptions with HTML tags or markdown images
// Normal plain text descriptions should keep the package name (like "Nuxt is a framework...")

it('does NOT strip package name from plain text descriptions', async () => {
// Plain text descriptions should be kept as-is
const component = await mountSuspended(MarkdownText, {
props: {
text: 'my-package - A great library',
packageName: 'my-package',
},
})
expect(component.text()).toBe('A great library')
expect(component.text()).toBe('my-package - A great library')
})

it('strips package name with colon separator', async () => {
it('does NOT strip package name from plain text with colon', async () => {
const component = await mountSuspended(MarkdownText, {
props: {
text: 'my-package: A great library',
packageName: 'my-package',
},
})
expect(component.text()).toBe('A great library')
expect(component.text()).toBe('my-package: A great library')
})

it('strips package name with em dash separator', async () => {
it('strips package name from HTML-containing descriptions', async () => {
const component = await mountSuspended(MarkdownText, {
props: {
text: 'my-package A great library',
text: '<b>my-package</b> - A great library',
packageName: 'my-package',
},
})
expect(component.text()).toBe('A great library')
})

it('strips package name without separator', async () => {
it('strips package name from HTML descriptions with colon separator', async () => {
const component = await mountSuspended(MarkdownText, {
props: {
text: 'my-package A great library',
text: '<div>my-package: A great library</div>',
packageName: 'my-package',
},
})
expect(component.text()).toBe('A great library')
})

it('is case-insensitive', async () => {
it('strips package name from HTML descriptions with em dash', async () => {
const component = await mountSuspended(MarkdownText, {
props: {
text: 'MY-PACKAGE - A great library',
text: '<span>my-package — A great library</span>',
packageName: 'my-package',
},
})
expect(component.text()).toBe('A great library')
})

it('does not strip package name from middle of text', async () => {
it('is case-insensitive for HTML descriptions', async () => {
const component = await mountSuspended(MarkdownText, {
props: {
text: 'A great my-package library',
text: '<b>MY-PACKAGE</b> - A great library',
packageName: 'my-package',
},
})
expect(component.text()).toBe('A great my-package library')
expect(component.text()).toBe('A great library')
})

it('handles scoped package names', async () => {
it('does not strip package name from middle of HTML text', async () => {
const component = await mountSuspended(MarkdownText, {
props: {
text: '@org/my-package - A great library',
packageName: '@org/my-package',
text: '<div>A great my-package library</div>',
packageName: 'my-package',
},
})
expect(component.text()).toBe('A great library')
expect(component.text()).toBe('A great my-package library')
})

it('handles package names with special regex characters', async () => {
it('handles scoped package names in HTML descriptions', async () => {
const component = await mountSuspended(MarkdownText, {
props: {
text: 'pkg.name+test - A great library',
packageName: 'pkg.name+test',
text: '<b>@org/my-package</b> - A great library',
packageName: '@org/my-package',
},
})
expect(component.text()).toBe('A great library')
})

it('strips package name from HTML-containing descriptions', async () => {
it('handles package names with special regex characters in HTML', async () => {
const component = await mountSuspended(MarkdownText, {
props: {
text: '<b>my-package</b> - A great library',
packageName: 'my-package',
text: '<b>pkg.name+test</b> - A great library',
packageName: 'pkg.name+test',
},
})
expect(component.text()).toBe('A great library')
Expand Down
Loading