@@ -248,6 +248,33 @@ function linkifyIssueReferences(html: string, owner: string, repo: string): stri
248248 return parts . join ( "" ) ;
249249}
250250
251+ /** Convert full commit SHAs (40 hex chars) to commit links */
252+ function linkifyCommits ( html : string , owner : string , repo : string ) : string {
253+ const parts = html . split ( / ( < [ ^ > ] + > ) / ) ;
254+ let inCode = 0 ;
255+ let inLink = 0 ;
256+
257+ for ( let i = 0 ; i < parts . length ; i ++ ) {
258+ const part = parts [ i ] ;
259+ if ( part . startsWith ( "<" ) ) {
260+ const lower = part . toLowerCase ( ) ;
261+ if ( lower . startsWith ( "<code" ) || lower . startsWith ( "<pre" ) ) inCode ++ ;
262+ else if ( lower . startsWith ( "</code" ) || lower . startsWith ( "</pre" ) ) inCode -- ;
263+ else if ( lower . startsWith ( "<a " ) || lower . startsWith ( "<a>" ) ) inLink ++ ;
264+ else if ( lower . startsWith ( "</a" ) ) inLink -- ;
265+ continue ;
266+ }
267+ if ( inCode > 0 || inLink > 0 ) continue ;
268+ // Match 40-character commit SHA
269+ parts [ i ] = part . replace (
270+ / \b ( [ a - f 0 - 9 ] { 40 } ) \b / g,
271+ ( sha ) =>
272+ `<a href="/${ owner } /${ repo } /commit/${ sha } " class="ghmd-commit-ref">${ sha . slice ( 0 , 7 ) } </a>` ,
273+ ) ;
274+ }
275+ return parts . join ( "" ) ;
276+ }
277+
251278/** Convert @username mentions (outside of code/links) to profile links */
252279function linkifyMentions ( html : string ) : string {
253280 // Split on tags to avoid replacing inside <a>, <code>, <pre> content
@@ -508,6 +535,11 @@ export async function renderMarkdownToHtml(
508535 html = linkifyIssueReferences ( html , refCtx . owner , refCtx . repo ) ;
509536 }
510537
538+ // Linkify commit hashes when repo context is available
539+ if ( repoContext ) {
540+ html = linkifyCommits ( html , repoContext . owner , repoContext . repo ) ;
541+ }
542+
511543 return html ;
512544}
513545
0 commit comments