meblog
Version:
A simple blog engine for personal blogging
164 lines (163 loc) • 6.14 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const fs_1 = tslib_1.__importDefault(require("fs"));
const path_1 = tslib_1.__importDefault(require("path"));
const glob_1 = tslib_1.__importDefault(require("glob"));
const gulplog_1 = tslib_1.__importDefault(require("gulplog"));
const ansi_colors_1 = tslib_1.__importDefault(require("ansi-colors"));
const DataSource_1 = tslib_1.__importDefault(require("./DataSource"));
const Post_1 = require("../post/Post");
const MarkdownPostParser_1 = tslib_1.__importDefault(require("../post/MarkdownPostParser"));
const FileUtils_1 = tslib_1.__importDefault(require("../util/FileUtils"));
class FilesSource extends DataSource_1.default {
postsDirectoryPath;
dataDirectoryPath;
separator;
postParser;
postLayouts;
posts = [];
tags = [];
constructor(config, postsDirectoryPath, separator = '---') {
super(config);
postsDirectoryPath = postsDirectoryPath.trim();
if (postsDirectoryPath.endsWith('/')) {
postsDirectoryPath.slice(0, -1);
}
this.postsDirectoryPath = postsDirectoryPath;
if (!fs_1.default.existsSync(this.postsDirectoryPath)) {
return;
}
this.dataDirectoryPath = path_1.default.resolve(this.postsDirectoryPath, '../cache');
this.separator = separator;
this.postParser = new MarkdownPostParser_1.default();
this.postLayouts = this.getLayouts();
}
get postsJsonPath() {
return path_1.default.join(this.dataDirectoryPath, 'posts.json');
}
get tagsJsonPath() {
return path_1.default.join(this.dataDirectoryPath, 'tags.json');
}
getLayouts() {
return glob_1.default
.sync(path_1.default.join(this.config.rootDir, './templates/posts/*.pug'))
.map((file) => FileUtils_1.default.basenameWithoutExt(file));
}
filterInvalidPostLayout(post) {
if (!this.postLayouts.includes(post.layout)) {
gulplog_1.default.info(`Post ${ansi_colors_1.default.green(post.title)}\
has ${ansi_colors_1.default.red(`invalid layout "${post.layout}" will be ignored`)}`);
return false;
}
return true;
}
getSourcePostPaths() {
return glob_1.default.sync(`${this.postsDirectoryPath}/**/*.md`);
}
hasAnyChanges() {
if (!fs_1.default.existsSync(this.postsJsonPath)) {
gulplog_1.default.debug('Cache data is not found');
return true;
}
const postsJsonLastModifiedAt = fs_1.default.statSync(this.postsJsonPath).mtimeMs;
const files = this.getSourcePostPaths();
for (const filePath of files) {
const lastModifiedAt = fs_1.default.statSync(filePath).mtimeMs;
if (lastModifiedAt > postsJsonLastModifiedAt) {
gulplog_1.default.info('New post change at file:', filePath);
return true;
}
}
return false;
}
parse() {
const files = this.getSourcePostPaths();
const posts = this.parsePostsFromPaths(files);
const tags = posts.flatMap((p) => p.tags).filter((t) => t);
posts.sort((p1, p2) => p2.publishedAt.getTime() - p1.publishedAt.getTime());
return {
posts: posts,
tags: Array.from(new Set(tags)),
};
}
parsePosts(force = false) {
let shouldParse = false;
if (force || this.hasAnyChanges()) {
shouldParse = true;
}
if (!shouldParse) {
return;
}
const result = this.parse();
this.cacheData(result);
}
cacheData({ posts, tags }) {
const jsonPrettySpace = this.config.devMode ? 2 : 0;
if (!fs_1.default.existsSync(this.dataDirectoryPath)) {
fs_1.default.mkdirSync(this.dataDirectoryPath);
}
fs_1.default.writeFileSync(this.postsJsonPath, JSON.stringify(posts, null, jsonPrettySpace));
fs_1.default.writeFileSync(this.tagsJsonPath, JSON.stringify(tags, null, jsonPrettySpace));
}
filterUnpublishedPosts(filePath) {
return !FileUtils_1.default.basename(filePath).startsWith('__');
}
parsePostsFromPaths(filePaths) {
return filePaths
.filter((file) => this.filterUnpublishedPosts(file))
.filter((file) => fs_1.default.existsSync(file))
.map((file) => this.postParser.parse(file, this.separator))
.filter((p) => p.title && p.publishedAt && p.slug)
.filter((p) => this.filterInvalidPostLayout(p))
.map((p) => {
p.url = this.postRootUrl(p);
p.relativeUrl = this.postUrl(p);
return p;
});
}
loadData(force = false) {
if (!fs_1.default.existsSync(this.postsDirectoryPath)) {
return;
}
this.parsePosts(force);
delete require.cache[this.postsJsonPath];
delete require.cache[this.tagsJsonPath];
const jsonPosts = require(this.postsJsonPath);
this.posts = jsonPosts.map((p) => new Post_1.Post(p));
this.setupPostMap(this.posts);
this.tags = require(this.tagsJsonPath);
}
setupPostMap(posts) {
posts.reduce((_, post) => {
_[post.slug] = post;
return _;
}, posts);
}
filterPost(post, locale) {
const { language } = post;
locale = locale || this.config.defaultLocale;
return language
? language === locale
: locale === this.config.defaultLocale;
}
getPosts(locale) {
const posts = this.posts.filter(p => this.filterPost(p, locale));
this.setupPostMap(posts);
return posts;
}
getAllPosts() {
return this.posts;
}
getPostsByTag(tag, locale) {
const posts = this.posts
.filter((p) => p.tags.includes(tag))
.filter(p => this.filterPost(p, locale));
this.setupPostMap(posts);
return posts;
}
getTags() {
return this.tags;
}
}
exports.default = FilesSource;