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 @@ -59,7 +59,7 @@
return node;
}

run(context, args, body, callback) {

Check warning on line 62 in lib/extend/tag.ts

View workflow job for this annotation

GitHub Actions / linter

'callback' is defined but never used

Check warning on line 62 in lib/extend/tag.ts

View workflow job for this annotation

GitHub Actions / linter

'body' is defined but never used
return this._run(context, args, '');
}

Expand All @@ -80,14 +80,14 @@
return new nodes.CallExtension(this, 'run', node, [body]);
}

_parseBody(parser, nodes, lexer) {

Check warning on line 83 in lib/extend/tag.ts

View workflow job for this annotation

GitHub Actions / linter

'lexer' is defined but never used

Check warning on line 83 in lib/extend/tag.ts

View workflow job for this annotation

GitHub Actions / linter

'nodes' is defined but never used
const body = parser.parseUntilBlocks(`end${this.tags[0]}`);

parser.advanceAfterBlockEnd();
return body;
}

run(context, args, body, callback) {

Check warning on line 90 in lib/extend/tag.ts

View workflow job for this annotation

GitHub Actions / linter

'callback' is defined but never used
return this._run(context, args, trimBody(body));
}
}
Expand Down Expand Up @@ -206,11 +206,23 @@
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 @@
}

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

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

if (env.hasExtension(name)) env.removeExtension(name);
delete this.block_swig_tag_map[name];
Copy link
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
Loading