Skip to content

Commit

Permalink
fix(post): support swig tag inside post (#4352)
Browse files Browse the repository at this point in the history
Close #3259, #3346 & #3346 (comment)
  • Loading branch information
SukkaW authored Jun 13, 2020
1 parent 7d208ea commit 2b70b82
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 14 deletions.
30 changes: 18 additions & 12 deletions lib/hexo/post.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ const yfm = require('hexo-front-matter');

const preservedKeys = ['title', 'slug', 'path', 'layout', 'date', 'content'];

const rPlaceholder = /(?:<|&lt;)!--\uFFFC(\d+)--(?:>|&gt;)/g;
const rSwigVar = /\{\{[\s\S]*?\}\}/g;
const rSwigComment = /\{#[\s\S]*?#\}/g;
const rSwigBlock = /\{%[\s\S]*?%\}/g;
const rSwigFullBlock = /\{% *(.+?)(?: *| +.*?)%\}[\s\S]+?\{% *end\1 *%\}/g;
const rSwigRawFullBlock = /{% *raw *%\}[\s\S]+?\{% *endraw *%\}/g;
const rSwigTagInsideInlineCode = /`.*{.*}.*`/g;

const _escapeContent = (cache, str) => {
const placeholder = '\uFFFC';
return `<!--${placeholder}${cache.push(str) - 1}-->`;
Expand All @@ -27,7 +35,6 @@ class PostRenderCache {
str = str.replace(/<!--hexoPostRenderEscape:/g, '').replace(/:hexoPostRenderEscape-->/g, '');
}

const rPlaceholder = /(?:<|&lt;)!--\uFFFC(\d+)--(?:>|&gt;)/g;
const restored = str.replace(rPlaceholder, (_, index) => {
assert(this.cache[index]);
const value = this.cache[index];
Expand All @@ -39,13 +46,12 @@ class PostRenderCache {
}

escapeAllSwigTags(str) {
const rSwigVar = /\{\{[\s\S]*?\}\}/g;
const rSwigComment = /\{#[\s\S]*?#\}/g;
const rSwigBlock = /\{%[\s\S]*?%\}/g;
const rSwigFullBlock = /\{% *(.+?)(?: *| +.*?)%\}[\s\S]+?\{% *end\1 *%\}/g;

const escape = _str => _escapeContent(this.cache, _str);
return str.replace(rSwigFullBlock, escape)
return str.replace(rSwigRawFullBlock, escape) // Escape {% raw %} first
.replace(rSwigTagInsideInlineCode, str => {
return str.replace(/{/g, '&#123;').replace(/}/g, '&#125;');
})
.replace(rSwigFullBlock, escape)
.replace(rSwigBlock, escape)
.replace(rSwigComment, '')
.replace(rSwigVar, escape);
Expand Down Expand Up @@ -97,7 +103,7 @@ class Post {
const ctx = this.context;
const { config } = ctx;

data.slug = slugize((data.slug || data.title).toString(), {transform: config.filename_case});
data.slug = slugize((data.slug || data.title).toString(), { transform: config.filename_case });
data.layout = (data.layout || config.default_layout).toLowerCase();
data.date = data.date ? moment(data.date) : moment();

Expand Down Expand Up @@ -136,7 +142,7 @@ class Post {
let yfmSplit;

return this._getScaffold(data.layout).then(scaffold => {
const frontMatter = prepareFrontMatter({...data});
const frontMatter = prepareFrontMatter({ ...data });
yfmSplit = yfm.split(scaffold);

return tag.render(yfmSplit.data, frontMatter);
Expand Down Expand Up @@ -184,7 +190,7 @@ class Post {
const ctx = this.context;
const { config } = ctx;
const draftDir = join(ctx.source_dir, '_drafts');
const slug = slugize(data.slug.toString(), {transform: config.filename_case});
const slug = slugize(data.slug.toString(), { transform: config.filename_case });
data.slug = slug;
const regex = new RegExp(`^${escapeRegExp(slug)}(?:[^\\/\\\\]+)`);
let src = '';
Expand Down Expand Up @@ -252,7 +258,7 @@ class Post {
data.content = content;

// Run "before_post_render" filters
return ctx.execFilter('before_post_render', data, {context: ctx});
return ctx.execFilter('before_post_render', data, { context: ctx });
}).then(() => {
// Escape all Nunjucks/Swig tags
if (!disableNunjucks) {
Expand Down Expand Up @@ -284,7 +290,7 @@ class Post {
data.content = content;

// Run "after_post_render" filters
return ctx.execFilter('after_post_render', data, {context: ctx});
return ctx.execFilter('after_post_render', data, { context: ctx });
}).asCallback(callback);
}
}
Expand Down
29 changes: 27 additions & 2 deletions test/scripts/hexo/post.js
Original file line number Diff line number Diff line change
Expand Up @@ -669,13 +669,13 @@ describe('Post', () => {
});

it('render() - recover escaped nunjucks blocks which is html escaped', () => {
const content = '`{% raw %}{{ test }}{% endraw %}`';
const content = '`{% raw %}{{ test }}{% endraw %}`, {%raw%}{{ test }}{%endraw%}';

return post.render(null, {
content,
engine: 'markdown'
}).then(data => {
data.content.trim().should.eql('<p><code>{{ test }}</code></p>');
data.content.trim().should.eql('<p><code>{{ test }}</code>, {{ test }}</p>');
});
});

Expand Down Expand Up @@ -1004,4 +1004,29 @@ describe('Post', () => {
data.content.trim().should.include('<h1 id="Title-2"><a href="#Title-2" class="headerlink" title="Title 2"></a>Title 2</h1>');
data.content.trim().should.include('<h1 id="Title-3"><a href="#Title-3" class="headerlink" title="Title 3"></a>Title 3</h1>');
});

// test for Issue #3259
// https://github.com/hexojs/hexo/issues/3259
it('render() - "{{" & "}}" inside inline code', async () => {
const content = 'In Go\'s templates, blocks look like this: `{{block "template name" .}} (content) {{end}}`.';

const data = await post.render(null, {
content,
engine: 'markdown'
});

data.content.trim().should.eql('<p>In Go’s templates, blocks look like this: <code>&amp;#123;&amp;#123;block &quot;template name&quot; .&amp;#125;&amp;#125; (content) &amp;#123;&amp;#123;end&amp;#125;&amp;#125;</code>.</p>');
});

// test for https://github.com/hexojs/hexo/issues/3346#issuecomment-595497849
it('render() - swig var inside inline code', async () => {
const content = '`{{ 1 + 1 }}` {{ 1 + 1 }}';

const data = await post.render(null, {
content,
engine: 'markdown'
});

data.content.trim().should.eql('<p><code>&amp;#123;&amp;#123; 1 + 1 &amp;#125;&amp;#125;</code> 2</p>');
});
});

0 comments on commit 2b70b82

Please sign in to comment.