Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(post/tag): render tag before content #4171

Closed
wants to merge 6 commits into from
Closed
Changes from 1 commit
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
63 changes: 22 additions & 41 deletions lib/hexo/post.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,19 @@ const { copyDir, exists, listDir, mkdirs, readFile, rmdir, unlink, writeFile } =
const yfm = require('hexo-front-matter');

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

const _escapeContent = (cache, str) => {
const placeholder = '\uFFFC';
return `<!--${placeholder}${cache.push(str) - 1}-->`;
};
const rEscapeContent = /<escape(?:[^>]*)>([\s\S]*?)<\/escape>/g;
const rPlaceholder = /(?:<|&lt;)!--hexoPostRenderEscape:(\d+)--(?:>|&gt;)/g;
SukkaW marked this conversation as resolved.
Show resolved Hide resolved

class PostRenderCache {
constructor() {
this.cache = [];
}

escapeContent(str) {
const rEscapeContent = /<escape(?:[^>]*)>([\s\S]*?)<\/escape>/g;
return str.replace(rEscapeContent, (_, content) => _escapeContent(this.cache, content));
return str.replace(rEscapeContent, (_, content) => `<!--hexoPostRenderEscape:${this.cache.push(content) - 1}-->`);
}

loadContent(str) {
const rPlaceholder = /(?:<|&lt;)!--\uFFFC(\d+)--(?:>|&gt;)/g;
const restored = str.replace(rPlaceholder, (_, index) => {
assert(this.cache[index]);
const value = this.cache[index];
Expand All @@ -38,19 +33,6 @@ class PostRenderCache {
if (restored === str) return restored;
return this.loadContent(restored); // self-recursive for nexted escaping
}

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)
.replace(rSwigBlock, escape)
.replace(rSwigComment, '')
.replace(rSwigVar, escape);
}
}

const prepareFrontMatter = data => {
Expand Down Expand Up @@ -96,7 +78,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 @@ -135,7 +117,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 @@ -183,7 +165,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 @@ -254,46 +236,45 @@ 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 content wrapped in <escape></escape>
data.content = cacheObj.escapeContent(data.content);

if (isSwig) {
// Render with Nunjucks if this is a swig file
// Render with Nunjucks if the post is a swig file
return tag.render(data.content, data);
}
stevenjoezhang marked this conversation as resolved.
Show resolved Hide resolved

// Escape all Swig tags
if (!disableNunjucks) {
data.content = cacheObj.escapeAllSwigTags(data.content);
}

const options = data.markdown || {};
if (!config.highlight.enable) options.highlight = null;

ctx.log.debug('Rendering post: %s', magenta(source));
// Render with markdown or other renderer
return ctx.render.render({
text: data.content,

const promise = text => ctx.render.render({
text,
path: source,
engine: data.engine,
toString: true,
onRenderEnd(content) {
// Replace cache data with real contents
data.content = cacheObj.loadContent(content);

// Return content after replace the placeholders
if (disableNunjucks) return data.content;

// Render with Nunjucks
return tag.render(data.content, data);
return data.content;
}
}, options);

if (!disableNunjucks) {
return tag.render(data.content, data).then(promise);
}

// Nunjucks is disabled
return promise(data.content);

}).then(content => {
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