@@ -4,6 +4,7 @@ import { join } from 'path'
44import PageLayout from '@/components/PageLayout'
55import { generatePageMetadata } from '@/components/PageLayout'
66import { Metadata } from 'next'
7+ import { parseAdvisoryToHTML } from '@/lib/securityAdvisory'
78
89interface SecurityAdvisoryPageProps {
910 params : Promise < {
@@ -38,87 +39,6 @@ function getAdvisoryContent(advisory: string): { title: string; description: str
3839 }
3940}
4041
41- // Function to convert Markdown content to JSX
42- function parseAdvisoryContent ( content : string ) : React . JSX . Element {
43- // Robust parser: group consecutive metadata lines into a single <dl class="dl-horizontal">
44- const lines = content . split ( '\n' )
45-
46- const htmlParts : string [ ] = [ ]
47- let inDl = false
48-
49- const closeDlIfOpen = ( ) => {
50- if ( inDl ) {
51- htmlParts . push ( '</dl>' )
52- inDl = false
53- }
54- }
55-
56- for ( let line of lines ) {
57- let l = line . trim ( )
58-
59- // Skip empty lines, but ensure we close an open DL
60- if ( l . length === 0 ) {
61- closeDlIfOpen ( )
62- continue
63- }
64-
65- // Keep raw HTML intact
66- if ( l . startsWith ( '<' ) ) {
67- closeDlIfOpen ( )
68- htmlParts . push ( l )
69- continue
70- }
71-
72- // Headings
73- if ( l . startsWith ( '#### ' ) ) {
74- closeDlIfOpen ( )
75- htmlParts . push ( `<h4>${ l . substring ( 5 ) } </h4>` )
76- continue
77- }
78- if ( l . startsWith ( '### ' ) ) {
79- closeDlIfOpen ( )
80- htmlParts . push ( `<h3>${ l . substring ( 4 ) } </h3>` )
81- continue
82- }
83- if ( l . startsWith ( '## ' ) ) {
84- closeDlIfOpen ( )
85- htmlParts . push ( `<h2>${ l . substring ( 3 ) } </h2>` )
86- continue
87- }
88-
89- // Metadata lines like **Issued on::** 2004-07-27 or **Risk:** medium
90- // Strategy: capture bold label and the value; strip trailing colons from label
91- const metaMatch = l . match ( / ^ \* \* ( .+ ?) \* \* \s * ( .+ ) $ / )
92- if ( metaMatch ) {
93- let labelRaw = metaMatch [ 1 ] . trim ( )
94- const value = metaMatch [ 2 ] . trim ( )
95-
96- // Accept labels with one or more trailing colons inside the bold
97- labelRaw = labelRaw . replace ( / : + \s * $ / , '' ) . trim ( )
98-
99- if ( ! inDl ) {
100- htmlParts . push ( '<dl class="dl-horizontal">' )
101- inDl = true
102- }
103-
104- htmlParts . push ( `<dt>${ labelRaw } :</dt><dd>${ value } </dd>` )
105- continue
106- }
107-
108- // Default: wrap as paragraph
109- closeDlIfOpen ( )
110- htmlParts . push ( `<p>${ l } </p>` )
111- }
112-
113- // Close any open DL at the end
114- if ( inDl ) {
115- htmlParts . push ( '</dl>' )
116- }
117-
118- const processedContent = htmlParts . join ( '\n' ) . replace ( / \n + / g, '\n' ) . trim ( )
119- return < div dangerouslySetInnerHTML = { { __html : processedContent } } />
120- }
121-
12242export async function generateStaticParams ( ) {
12343 // Read all security advisory files from the content/security directory
12444 const { readdirSync } = await import ( 'fs' )
@@ -166,8 +86,8 @@ export default async function SecurityAdvisoryPage({ params }: SecurityAdvisoryP
16686 notFound ( )
16787 }
16888
169- const contentElement = parseAdvisoryContent ( advisoryData . content )
170-
89+ const html = parseAdvisoryToHTML ( advisoryData . content )
90+
17191 return (
17292 < PageLayout title = { advisoryData . title } >
17393 < div className = "row" >
@@ -179,7 +99,7 @@ export default async function SecurityAdvisoryPage({ params }: SecurityAdvisoryP
17999 </ ol >
180100 </ nav >
181101
182- { contentElement }
102+ < div dangerouslySetInnerHTML = { { __html : html } } />
183103 </ div >
184104 </ div >
185105 </ PageLayout >
0 commit comments