@@ -13,7 +13,6 @@ import type { NodeJSLikeCallback, RenderData } from '../types';
1313const preservedKeys = [ 'title' , 'slug' , 'path' , 'layout' , 'date' , 'content' ] ;
1414
1515const rHexoPostRenderEscape = / < h e x o P o s t R e n d e r C o d e B l o c k > ( [ \s \S ] + ?) < \/ h e x o P o s t R e n d e r C o d e B l o c k > / g;
16- const rCommentEscape = / ( < ! - - [ \s \S ] * ?- - > ) / g;
1716const rSwigTag = / ( \{ \{ .+ ?\} \} ) | ( \{ # .+ ?# \} ) | ( \{ % .+ ?% \} ) / s;
1817
1918const rSwigPlaceHolder = / (?: < | & l t ; ) ! - - s w i g \uFFFC ( \d + ) - - (?: > | & g t ; ) / g;
@@ -26,6 +25,7 @@ const STATE_SWIG_COMMENT = 2;
2625const STATE_SWIG_TAG = 3 ;
2726const STATE_SWIG_FULL_TAG = 4 ;
2827const STATE_PLAINTEXT_COMMENT = 5 ;
28+ const STATE_INLINE_CODE = 6 ;
2929
3030const isNonWhiteSpaceChar = ( char : string ) => char !== '\r'
3131 && char !== '\n'
@@ -68,22 +68,15 @@ class PostRenderEscape {
6868 return str . replace ( rCommentHolder , PostRenderEscape . restoreContent ( this . stored ) ) ;
6969 }
7070
71- escapeComments ( str : string ) {
72- return str . replace ( rCommentEscape , ( _ , content ) => PostRenderEscape . escapeContent ( this . stored , 'comment' , content ) ) ;
73- }
74-
7571 escapeCodeBlocks ( str : string ) {
7672 return str . replace ( rHexoPostRenderEscape , ( _ , content ) => PostRenderEscape . escapeContent ( this . stored , 'code' , content ) ) ;
7773 }
7874
79- /**
80- * @param {string } str
81- * @returns string
82- */
8375 escapeAllSwigTags ( str : string ) {
8476 let state = STATE_PLAINTEXT ;
8577 let buffer_start = - 1 ;
8678 let plaintext_comment_start = - 1 ;
79+ let inline_code_backtick_count = 0 ;
8780 let plain_text_start = 0 ;
8881 let output = '' ;
8982
@@ -101,7 +94,7 @@ class PostRenderEscape {
10194 let idx = 0 ;
10295
10396 // for backtracking
104- const swig_start_idx = [ 0 , 0 , 0 , 0 , 0 ] ;
97+ const swig_start_idx = [ 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ;
10598
10699 const flushPlainText = ( end : number ) => {
107100 if ( plain_text_start !== - 1 && end > plain_text_start ) {
@@ -124,11 +117,25 @@ class PostRenderEscape {
124117 while ( idx < length ) {
125118 while ( idx < length ) {
126119 const char = str [ idx ] ;
120+ const prev_char = idx > 0 ? str [ idx - 1 ] : '' ;
127121 const next_char = str [ idx + 1 ] ;
128122
129- if ( state === STATE_PLAINTEXT ) { // From plain text to swig
123+ if ( state === STATE_PLAINTEXT ) { // From plain text to swig or inline code
130124 ensurePlainTextStart ( idx ) ;
131- if ( char === '{' ) {
125+ // Check for inline code block (backticks)
126+ if ( char === '`' && prev_char !== '\\' ) {
127+ // Count consecutive backticks
128+ let backtick_count = 1 ;
129+ while ( str [ idx + backtick_count ] === '`' ) {
130+ backtick_count ++ ;
131+ }
132+
133+ flushPlainText ( idx ) ;
134+ state = STATE_INLINE_CODE ;
135+ inline_code_backtick_count = backtick_count ;
136+ swig_start_idx [ state ] = idx ;
137+ idx += backtick_count - 1 ; // Skip the counted backticks
138+ } else if ( char === '{' ) {
132139 // check if it is a complete tag {{ }}
133140 if ( next_char === '{' ) {
134141 flushPlainText ( idx ) ;
@@ -154,13 +161,49 @@ class PostRenderEscape {
154161 swig_tag_name_end = false ;
155162 swig_start_idx [ state ] = idx ;
156163 }
157- }
158- if ( char === '<' && next_char === '!' && str [ idx + 2 ] === '-' && str [ idx + 3 ] === '-' ) {
164+ } else if ( char === '<' && next_char === '!' && str [ idx + 2 ] === '-' && str [ idx + 3 ] === '-' ) {
159165 flushPlainText ( idx ) ;
160166 state = STATE_PLAINTEXT_COMMENT ;
161167 plaintext_comment_start = idx ;
162168 idx += 3 ;
163169 }
170+ } else if ( state === STATE_INLINE_CODE ) {
171+ const inline_code_start = swig_start_idx [ state ] ;
172+ // Check for newline - inline code cannot span multiple lines
173+ if ( ( char === '\n' && next_char === '\n' )
174+ || ( char === '\r' && next_char === '\n' && str [ idx + 2 ] === '\r' && str [ idx + 3 ] === '\n' )
175+ || ( char === '\r' && next_char === '\n' && str [ idx + 2 ] === '\n' )
176+ || ( char === '\n' && next_char === '\r' && str [ idx + 2 ] === '\n' )
177+ ) {
178+ // Backtrack: treat the opening backticks as plain text and retry from after them
179+ pushAndReset ( str . slice ( inline_code_start , inline_code_start + inline_code_backtick_count ) ) ;
180+ // Reset idx to position right after the opening backticks
181+ idx = inline_code_start + inline_code_backtick_count - 1 ;
182+ state = STATE_PLAINTEXT ;
183+ } else if ( char === '{' && next_char === '%' && str . slice ( idx ) . match ( / ^ \{ % * r a w * % \} / ) ) {
184+ // we may have raw tag in inline code
185+ const raw_tag_end_match = str . slice ( idx ) . match ( / \{ % * e n d r a w * % \} / ) ;
186+ if ( raw_tag_end_match ) {
187+ pushAndReset ( str . slice ( inline_code_start , idx ) ) ;
188+ // escape the raw tag content
189+ pushAndReset ( PostRenderEscape . escapeContent ( this . stored , 'swig' , str . slice ( idx , idx + raw_tag_end_match . index ! + raw_tag_end_match [ 0 ] . length ) ) ) ;
190+ idx = idx + raw_tag_end_match . index ! + raw_tag_end_match [ 0 ] . length - 1 ;
191+ swig_start_idx [ state ] = idx + 1 ;
192+ }
193+ } else if ( char === '`' ) {
194+ // Count consecutive backticks
195+ let backtick_count = 1 ;
196+ while ( str [ idx + backtick_count ] === '`' ) {
197+ backtick_count ++ ;
198+ }
199+
200+ // If the count matches, we found the closing backticks
201+ if ( backtick_count === inline_code_backtick_count ) {
202+ pushAndReset ( str . slice ( inline_code_start , idx + backtick_count ) ) ;
203+ idx += backtick_count - 1 ; // Skip the counted backticks
204+ state = STATE_PLAINTEXT ;
205+ }
206+ }
164207 } else if ( state === STATE_SWIG_TAG ) {
165208 if ( char === '"' || char === '\'' ) {
166209 if ( swig_string_quote === '' ) {
@@ -269,6 +312,14 @@ class PostRenderEscape {
269312 pushAndReset ( PostRenderEscape . escapeContent ( this . stored , 'comment' , comment ) ) ;
270313 break ;
271314 }
315+ if ( state === STATE_INLINE_CODE ) {
316+ const inline_code_start = swig_start_idx [ state ] ;
317+ pushAndReset ( str . slice ( inline_code_start , inline_code_start + inline_code_backtick_count ) ) ;
318+ // Reset idx to position right after the opening backticks
319+ idx = inline_code_start + inline_code_backtick_count ;
320+ state = STATE_PLAINTEXT ;
321+ continue ;
322+ }
272323 // If the swig tag is not closed, then it is a plain text, we need to backtrack
273324 if ( state === STATE_SWIG_FULL_TAG ) {
274325 pushAndReset ( `{%${ str . slice ( swig_full_tag_start_start , swig_full_tag_start_end ) } %` ) ;
0 commit comments