Skip to content

Commit

Permalink
Merge branch 'master' into fix/codeblock
Browse files Browse the repository at this point in the history
  • Loading branch information
D-Sketon authored Feb 12, 2025
2 parents 98f87cf + 4a1e203 commit b731208
Show file tree
Hide file tree
Showing 13 changed files with 521 additions and 99 deletions.
14 changes: 14 additions & 0 deletions lib/hexo/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import type Box from '../box';
import type { BaseGeneratorReturn, FilterOptions, LocalsType, NodeJSLikeCallback, SiteLocals } from '../types';
import type { AddSchemaTypeOptions } from 'warehouse/dist/types';
import type Schema from 'warehouse/dist/schema';
import BinaryRelationIndex from '../models/binary_relation_index';

const libDir = dirname(__dirname);
const dbVersion = 1;
Expand Down Expand Up @@ -300,6 +301,10 @@ class Hexo extends EventEmitter {
static lib_dir: string;
static core_dir: string;
static version: string;
public _binaryRelationIndex: {
post_tag: BinaryRelationIndex<'post_id', 'tag_id'>;
post_category: BinaryRelationIndex<'post_id', 'category_id'>;
};

constructor(base = process.cwd(), args: Args = {}) {
super();
Expand Down Expand Up @@ -378,6 +383,10 @@ class Hexo extends EventEmitter {
this.theme = new Theme(this);
this.locals = new Locals();
this._bindLocals();
this._binaryRelationIndex = {
post_tag: new BinaryRelationIndex<'post_id', 'tag_id'>('post_id', 'tag_id', 'PostTag', this),
post_category: new BinaryRelationIndex<'post_id', 'category_id'>('post_id', 'category_id', 'PostCategory', this)
};
}

_bindLocals(): void {
Expand Down Expand Up @@ -536,6 +545,8 @@ class Hexo extends EventEmitter {
*/
load(callback?: NodeJSLikeCallback<any>): Promise<any> {
return loadDatabase(this).then(() => {
this._binaryRelationIndex.post_tag.load();
this._binaryRelationIndex.post_category.load();
this.log.info('Start processing');

return Promise.all([
Expand Down Expand Up @@ -694,6 +705,9 @@ class Hexo extends EventEmitter {
this.emit('generateBefore');

// Run before_generate filters
// https://github.com/hexojs/hexo/issues/5287
// locals should be invalidated before before_generate filters because tags may use locals
this.locals.invalidate();
return this.execFilter('before_generate', null, { context: this })
.then(() => this._routerRefresh(this._runGenerators(), useCache)).then(() => {
this.emit('generateAfter');
Expand Down
228 changes: 145 additions & 83 deletions lib/hexo/post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,112 +80,174 @@ class PostRenderEscape {
let swig_tag_name_end = false;
let swig_tag_name = '';
let swig_full_tag_start_buffer = '';
// current we just consider one level of string quote
let swig_string_quote = '';

const { length } = str;

for (let idx = 0; idx < length; idx++) {
const char = str[idx];
const next_char = str[idx + 1];
let idx = 0;

if (state === STATE_PLAINTEXT) { // From plain text to swig
if (char === '{') {
// check if it is a complete tag {{ }}
if (next_char === '{') {
state = STATE_SWIG_VAR;
idx++;
} else if (next_char === '#') {
state = STATE_SWIG_COMMENT;
idx++;
} else if (next_char === '%') {
state = STATE_SWIG_TAG;
idx++;
swig_tag_name = '';
swig_full_tag_start_buffer = '';
swig_tag_name_begin = false; // Mark if it is the first non white space char in the swig tag
swig_tag_name_end = false;
// for backtracking
const swig_start_idx = {
[STATE_SWIG_VAR]: 0,
[STATE_SWIG_COMMENT]: 0,
[STATE_SWIG_TAG]: 0,
[STATE_SWIG_FULL_TAG]: 0
};

while (idx < length) {
while (idx < length) {
const char = str[idx];
const next_char = str[idx + 1];

if (state === STATE_PLAINTEXT) { // From plain text to swig
if (char === '{') {
// check if it is a complete tag {{ }}
if (next_char === '{') {
state = STATE_SWIG_VAR;
idx++;
swig_start_idx[state] = idx;
} else if (next_char === '#') {
state = STATE_SWIG_COMMENT;
idx++;
swig_start_idx[state] = idx;
} else if (next_char === '%') {
state = STATE_SWIG_TAG;
idx++;
swig_tag_name = '';
swig_full_tag_start_buffer = '';
swig_tag_name_begin = false; // Mark if it is the first non white space char in the swig tag
swig_tag_name_end = false;
swig_start_idx[state] = idx;
} else {
output += char;
}
} else {
output += char;
}
} else {
output += char;
}
} else if (state === STATE_SWIG_TAG) {
if (char === '%' && next_char === '}') { // From swig back to plain text
idx++;
if (swig_tag_name !== '' && str.includes(`end${swig_tag_name}`)) {
state = STATE_SWIG_FULL_TAG;
} else {
} else if (state === STATE_SWIG_TAG) {
if (char === '"' || char === '\'') {
if (swig_string_quote === '') {
swig_string_quote = char;
} else if (swig_string_quote === char) {
swig_string_quote = '';
}
}
// {% } or {% %
if (((char !== '%' && next_char === '}') || (char === '%' && next_char !== '}')) && swig_string_quote === '') {
// From swig back to plain text
swig_tag_name = '';
state = STATE_PLAINTEXT;
output += PostRenderEscape.escapeContent(this.stored, 'swig', `{%${buffer}%}`);
}

buffer = '';
} else {
buffer = buffer + char;
swig_full_tag_start_buffer = swig_full_tag_start_buffer + char;

if (isNonWhiteSpaceChar(char)) {
if (!swig_tag_name_begin && !swig_tag_name_end) {
swig_tag_name_begin = true;
output += `{%${buffer}${char}`;
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}`)) {
state = STATE_SWIG_FULL_TAG;
swig_start_idx[state] = idx;
} else {
swig_tag_name = '';
state = STATE_PLAINTEXT;
output += PostRenderEscape.escapeContent(this.stored, 'swig', `{%${buffer}%}`);
}

if (swig_tag_name_begin) {
swig_tag_name += char;
}
buffer = '';
} else {
if (swig_tag_name_begin === true) {
swig_tag_name_begin = false;
swig_tag_name_end = true;
buffer = buffer + char;
swig_full_tag_start_buffer = swig_full_tag_start_buffer + char;

if (isNonWhiteSpaceChar(char)) {
if (!swig_tag_name_begin && !swig_tag_name_end) {
swig_tag_name_begin = true;
}

if (swig_tag_name_begin) {
swig_tag_name += char;
}
} else {
if (swig_tag_name_begin === true) {
swig_tag_name_begin = false;
swig_tag_name_end = true;
}
}
}
}
} else if (state === STATE_SWIG_VAR) {
if (char === '}' && next_char === '}') {
idx++;
state = STATE_PLAINTEXT;
output += PostRenderEscape.escapeContent(this.stored, 'swig', `{{${buffer}}}`);
buffer = '';
} else {
buffer = buffer + char;
}
} else if (state === STATE_SWIG_COMMENT) { // From swig back to plain text
if (char === '#' && next_char === '}') {
idx++;
state = STATE_PLAINTEXT;
buffer = '';
}
} else if (state === STATE_SWIG_FULL_TAG) {
if (char === '{' && next_char === '%') {
let swig_full_tag_end_buffer = '';

let _idx = idx + 2;
for (; _idx < length; _idx++) {
const _char = str[_idx];
const _next_char = str[_idx + 1];

if (_char === '%' && _next_char === '}') {
_idx++;
break;
} else if (state === STATE_SWIG_VAR) {
if (char === '"' || char === '\'') {
if (swig_string_quote === '') {
swig_string_quote = char;
} else if (swig_string_quote === char) {
swig_string_quote = '';
}

swig_full_tag_end_buffer = swig_full_tag_end_buffer + _char;
}

if (swig_full_tag_end_buffer.includes(`end${swig_tag_name}`)) {
// {{ }
if (char === '}' && next_char !== '}' && swig_string_quote === '') {
// From swig back to plain text
state = STATE_PLAINTEXT;
output += `{{${buffer}${char}`;
buffer = '';
} else if (char === '}' && next_char === '}' && swig_string_quote === '') {
idx++;
state = STATE_PLAINTEXT;
output += PostRenderEscape.escapeContent(this.stored, 'swig', `{{${buffer}}}`);
buffer = '';
} else {
buffer = buffer + char;
}
} else if (state === STATE_SWIG_COMMENT) { // From swig back to plain text
if (char === '#' && next_char === '}') {
idx++;
state = STATE_PLAINTEXT;
output += PostRenderEscape.escapeContent(this.stored, 'swig', `{%${swig_full_tag_start_buffer}%}${buffer}{%${swig_full_tag_end_buffer}%}`);
idx = _idx;
swig_full_tag_start_buffer = '';
swig_full_tag_end_buffer = '';
buffer = '';
}
} else if (state === STATE_SWIG_FULL_TAG) {
if (char === '{' && next_char === '%') {
let swig_full_tag_end_buffer = '';
let swig_full_tag_found = false;

let _idx = idx + 2;
for (; _idx < length; _idx++) {
const _char = str[_idx];
const _next_char = str[_idx + 1];

if (_char === '%' && _next_char === '}') {
_idx++;
swig_full_tag_found = true;
break;
}

swig_full_tag_end_buffer = swig_full_tag_end_buffer + _char;
}

if (swig_full_tag_found && swig_full_tag_end_buffer.includes(`end${swig_tag_name}`)) {
state = STATE_PLAINTEXT;
output += PostRenderEscape.escapeContent(this.stored, 'swig', `{%${swig_full_tag_start_buffer}%}${buffer}{%${swig_full_tag_end_buffer}%}`);
idx = _idx;
swig_full_tag_start_buffer = '';
swig_full_tag_end_buffer = '';
buffer = '';
} else {
buffer += char;
}
} else {
buffer += char;
}
} else {
buffer += char;
}
idx++;
}
if (state === STATE_PLAINTEXT) {
break;
}
// If the swig tag is not closed, then it is a plain text, we need to backtrack
idx = swig_start_idx[state];
buffer = '';
swig_string_quote = '';
if (state === STATE_SWIG_FULL_TAG) {
output += `{%${swig_full_tag_start_buffer}%`;
} else {
output += '{';
}
swig_full_tag_start_buffer = '';
state = STATE_PLAINTEXT;
}

return output;
Expand Down
Loading

0 comments on commit b731208

Please sign in to comment.