diff --git a/lib/hexo/post.js b/lib/hexo/post.js index 73e2328d55..5a384f8d67 100644 --- a/lib/hexo/post.js +++ b/lib/hexo/post.js @@ -10,6 +10,9 @@ const { slugize, escapeRegExp } = require('hexo-util'); const { copyDir, exists, listDir, mkdirs, readFile, rmdir, unlink, writeFile } = require('hexo-fs'); const yfm = require('hexo-front-matter'); +const replaceSwigTag = str => str.replace(/{/g, '\uFFFCleft\uFFFC').replace(/}/g, '\uFFFCright\uFFFC'); +const restoreReplacesSwigTag = str => str.replace(/\uFFFCleft\uFFFC/g, '{').replace(/\uFFFCright\uFFFC/g, '}'); + const preservedKeys = ['title', 'slug', 'path', 'layout', 'date', 'content']; const rPlaceholder = /(?:<|<)!--\uFFFC(\d+)--(?:>|>)/g; @@ -18,7 +21,7 @@ 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 rSwigTagInsideInlineCode = /`.*?{.*?}.*?`/g; const _escapeContent = (cache, str) => { const placeholder = '\uFFFC'; @@ -48,9 +51,7 @@ class PostRenderCache { escapeAllSwigTags(str) { const escape = _str => _escapeContent(this.cache, _str); return str.replace(rSwigRawFullBlock, escape) // Escape {% raw %} first - .replace(rSwigTagInsideInlineCode, str => { - return str.replace(/{/g, '{').replace(/}/g, '}'); - }) + .replace(rSwigTagInsideInlineCode, replaceSwigTag) // Avoid double escaped by marked renderer .replace(rSwigFullBlock, escape) .replace(rSwigBlock, escape) .replace(rSwigComment, '') @@ -256,7 +257,6 @@ class Post { return promise.then(content => { data.content = content; - // Run "before_post_render" filters return ctx.execFilter('before_post_render', data, { context: ctx }); }).then(() => { @@ -277,7 +277,7 @@ class Post { toString: true, onRenderEnd(content) { // Replace cache data with real contents - data.content = cacheObj.loadContent(content); + data.content = cacheObj.loadContent(restoreReplacesSwigTag(content)); // Return content after replace the placeholders if (disableNunjucks) return data.content; @@ -287,6 +287,7 @@ class Post { } }, options); }).then(content => { + // restore { and } inside inline code data.content = content; // Run "after_post_render" filters diff --git a/test/scripts/hexo/post.js b/test/scripts/hexo/post.js index 0311c1e00b..8ff492f694 100644 --- a/test/scripts/hexo/post.js +++ b/test/scripts/hexo/post.js @@ -8,6 +8,7 @@ const { highlight, escapeHTML } = require('hexo-util'); const { spy, useFakeTimers } = require('sinon'); const frontMatter = require('hexo-front-matter'); const fixture = require('../../fixtures/post_render'); +const escapeSwigTag = str => str.replace(/{/g, '{').replace(/}/g, '}'); describe('Post', () => { const Hexo = require('../../../lib/hexo'); @@ -455,8 +456,8 @@ describe('Post', () => { const paths = [join(hexo.source_dir, '_posts', 'Hello-World-1.md')]; return Promise.all([ - post.create({title: 'Hello World', layout: 'draft'}), - post.create({title: 'Hello World'}) + post.create({ title: 'Hello World', layout: 'draft' }), + post.create({ title: 'Hello World' }) ]).then(data => { paths.push(data[1].path); @@ -473,8 +474,8 @@ describe('Post', () => { const path = join(hexo.source_dir, '_posts', 'Hello-World.md'); return Promise.all([ - post.create({title: 'Hello World', layout: 'draft'}), - post.create({title: 'Hello World'}) + post.create({ title: 'Hello World', layout: 'draft' }), + post.create({ title: 'Hello World' }) ]).then(data => post.publish({ slug: 'Hello-World' }, true)).then(data => { @@ -1015,7 +1016,7 @@ describe('Post', () => { engine: 'markdown' }); - data.content.trim().should.eql('
In Go’s templates, blocks look like this: {{block "template name" .}} (content) {{end}}
.
In Go’s templates, blocks look like this: ${escapeSwigTag(escapeHTML('{{block "template name" .}} (content) {{end}}'))}
.
{{ 1 + 1 }}
2
${escapeSwigTag('{{ 1 + 1 }}')}
2
${escapeSwigTag('{{ 1 + 1 }}')}
3 ${escapeSwigTag('{{ 2 + 2 }}')}
Text
Another Text
', + '', + 'Raw 2' + ].join('\n')); + }); + // https://github.com/hexojs/hexo/issues/4087 it('render() - issue #4087', async () => { // Adopted from https://github.com/hexojs/hexo/issues/4087#issuecomment-596999486