diff --git a/lib/extend/tag.ts b/lib/extend/tag.ts index 278a96deb5..e838d4be57 100644 --- a/lib/extend/tag.ts +++ b/lib/extend/tag.ts @@ -206,11 +206,23 @@ type RegisterOptions = { class Tag { public env: Environment; public source: string; + public block_swig_tag_map: { [name: string]: boolean }; constructor() { this.env = new Environment(null, { autoescape: false }); + this.block_swig_tag_map = { + if: true, + for: true, + each: true, + all: true, + macro: true, + block: true, + raw: true, + filter: true, + call: true + }; } register(name: string, fn: TagFunction): void @@ -246,6 +258,7 @@ class Tag { } this.env.addExtension(name, tag); + this.block_swig_tag_map[name] = !!options.ends; } unregister(name: string): void { @@ -254,6 +267,7 @@ class Tag { const { env } = this; if (env.hasExtension(name)) env.removeExtension(name); + delete this.block_swig_tag_map[name]; } render(str: string): Promise; diff --git a/lib/hexo/post.ts b/lib/hexo/post.ts index 07139c7ffe..6628d1d1b5 100644 --- a/lib/hexo/post.ts +++ b/lib/hexo/post.ts @@ -84,7 +84,7 @@ class PostRenderEscape { * @param {string} str * @returns string */ - escapeAllSwigTags(str: string) { + escapeAllSwigTags(str: string, block_swig_tag_map: { [name: string]: boolean }) { if (!/(\{\{.+?\}\})|(\{#.+?#\})|(\{%.+?%\})/s.test(str)) { return str; } @@ -158,7 +158,7 @@ class PostRenderEscape { buffer = ''; } else if (char === '%' && next_char === '}' && swig_string_quote === '') { // From swig back to plain text idx++; - if (swig_tag_name !== '' && str.includes(`end${swig_tag_name}`)) { + if (swig_tag_name !== '' && (block_swig_tag_map[swig_tag_name] ?? false)) { state = STATE_SWIG_FULL_TAG; swig_start_idx[state] = idx; } else { @@ -518,7 +518,7 @@ class Post { data.content = cacheObj.escapeCodeBlocks(data.content); // Escape all Nunjucks/Swig tags if (disableNunjucks === false) { - data.content = cacheObj.escapeAllSwigTags(data.content); + data.content = cacheObj.escapeAllSwigTags(data.content, tag.block_swig_tag_map); } const options: { highlight?: boolean; } = data.markdown || {}; diff --git a/test/scripts/hexo/post.ts b/test/scripts/hexo/post.ts index ecd5bdaa6a..d05cdb9001 100644 --- a/test/scripts/hexo/post.ts +++ b/test/scripts/hexo/post.ts @@ -1525,6 +1525,36 @@ describe('Post', () => { data.content.should.contains('22222'); }); + it('render() - tag prefix collision during escape swig tag (issue #5635)', async () => { + hexo.extend.tag.register('testtagblock', (args, content) => { + return 'rendered_test_tag_block'; + }, { ends: true }); + hexo.extend.tag.register('testtag', args => { + return 'rendered_test_tag'; + }); + + const content = [ + 'x{% testtag name %}', + '## Title', + '{% testtagblock %}', + 'content in block tag', + '{% endtesttagblock %}' + ].join('\n'); + + const data = await post.render('', { + content, + engine: 'markdown' + }); + + hexo.extend.tag.unregister('testtagblock'); + hexo.extend.tag.unregister('testtag'); + + data.content.should.contains('rendered_test_tag_block'); + data.content.should.contains('rendered_test_tag'); + data.content.should.contains(' { const content = 'nunjucks should throw {# } error';