Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions lib/extend/tag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -246,6 +258,7 @@ class Tag {
}

this.env.addExtension(name, tag);
this.block_swig_tag_map[name] = !!options.ends;
}

unregister(name: string): void {
Expand All @@ -254,6 +267,7 @@ class Tag {
const { env } = this;

if (env.hasExtension(name)) env.removeExtension(name);
delete this.block_swig_tag_map[name];
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not this.block_swig_tag_map[name] = false?

}

render(str: string): Promise<any>;
Expand Down
6 changes: 3 additions & 3 deletions lib/hexo/post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 || {};
Expand Down
30 changes: 30 additions & 0 deletions test/scripts/hexo/post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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('<h2');
data.content.should.not.contains('## Title');
});

it('render() - incomplete tags throw error', async () => {
const content = 'nunjucks should throw {# } error';

Expand Down