@@ -586,7 +586,7 @@ function parseHtmlTagAttributes(tag: string): Record<string, string> {
586586}
587587
588588function normalizeMarkdown ( content : string , origin ?: string , profile ?: DetectedProfile ) : string {
589- const normalized = profile ?. normalize ?.( content ) ?? content
589+ const normalized = normalizeCodeFencePadding ( profile ?. normalize ?.( content ) ?? content )
590590 return (
591591 normalized
592592 // Remove links with no text (e.g. `[](/)`)
@@ -632,3 +632,32 @@ function normalizeMarkdown(content: string, origin?: string, profile?: DetectedP
632632 . trim ( )
633633 )
634634}
635+
636+ function normalizeCodeFencePadding ( content : string ) : string {
637+ const lines = content . split ( '\n' )
638+ const normalized : string [ ] = [ ]
639+ let codeFence : { char : '`' | '~' ; length : number ; lines : string [ ] } | undefined
640+
641+ for ( const line of lines ) {
642+ if ( codeFence ) {
643+ const closeMatch = line . match ( / ^ ( ` { 3 , } | ~ { 3 , } ) \s * $ / )
644+ if ( closeMatch ?. [ 1 ] ?. startsWith ( codeFence . char ) && closeMatch [ 1 ] . length >= codeFence . length ) {
645+ while ( codeFence . lines [ 0 ] ?. trim ( ) === '' ) codeFence . lines . shift ( )
646+ while ( codeFence . lines . at ( - 1 ) ?. trim ( ) === '' ) codeFence . lines . pop ( )
647+ normalized . push ( ...codeFence . lines , line )
648+ codeFence = undefined
649+ continue
650+ }
651+ codeFence . lines . push ( line )
652+ continue
653+ }
654+
655+ const openMatch = line . match ( / ^ ( ` { 3 , } | ~ { 3 , } ) / )
656+ if ( openMatch ?. [ 1 ] )
657+ codeFence = { char : openMatch [ 1 ] [ 0 ] as '`' | '~' , length : openMatch [ 1 ] . length , lines : [ ] }
658+ normalized . push ( line )
659+ }
660+
661+ if ( codeFence ) normalized . push ( ...codeFence . lines )
662+ return normalized . join ( '\n' )
663+ }
0 commit comments